mirror of
https://github.com/usual2970/certimate.git
synced 2025-07-10 21:19:55 +00:00
Compare commits
6 Commits
d509445519
...
52d24ff2f2
Author | SHA1 | Date | |
---|---|---|---|
![]() |
52d24ff2f2 | ||
![]() |
7a66bdf139 | ||
![]() |
16bc12c15b | ||
![]() |
0556d68a4e | ||
![]() |
586c7fa927 | ||
![]() |
9ef16ebcf9 |
3
go.sum
3
go.sum
@ -392,6 +392,7 @@ github.com/gojek/heimdall/v7 v7.0.3/go.mod h1:Z43HtMid7ysSjmsedPTXAki6jcdcNVnjn5
|
||||
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 v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
@ -697,6 +698,8 @@ github.com/pocketbase/dbx v1.11.0 h1:LpZezioMfT3K4tLrqA55wWFw1EtH1pM4tzSVa7kgszU
|
||||
github.com/pocketbase/dbx v1.11.0/go.mod h1:xXRCIAKTHMgUCyCKZm55pUOdvFziJjQfXaWKhu2vhMs=
|
||||
github.com/pocketbase/pocketbase v0.22.21 h1:DGPCxn6co8VuTV0mton4NFO/ON49XiFMszRr+Mysy48=
|
||||
github.com/pocketbase/pocketbase v0.22.21/go.mod h1:Cw5E4uoGhKItBIE2lJL3NfmiUr9Syk2xaNJ2G7Dssow=
|
||||
github.com/pocketbase/pocketbase v0.23.12 h1:HB4THFbzaliF0C3wvpx+kNOZxIwCEMDqN3/17gn5N7E=
|
||||
github.com/pocketbase/pocketbase v0.23.12/go.mod h1:OcFJNMO0Vzt3f9+lweMbup6iL7V13ckxu1pdEY6FeM0=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
|
@ -7,10 +7,10 @@ import (
|
||||
"github.com/pocketbase/pocketbase/tools/cron"
|
||||
)
|
||||
|
||||
var schedulerOnce sync.Once
|
||||
|
||||
var scheduler *cron.Cron
|
||||
|
||||
var schedulerOnce sync.Once
|
||||
|
||||
func GetScheduler() *cron.Cron {
|
||||
schedulerOnce.Do(func() {
|
||||
scheduler = cron.New()
|
43
internal/applicant/acmehttpreq.go
Normal file
43
internal/applicant/acmehttpreq.go
Normal file
@ -0,0 +1,43 @@
|
||||
package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/httpreq"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type acmeHttpReqApplicant struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewACMEHttpReqApplicant(option *ApplyOption) Applicant {
|
||||
return &acmeHttpReqApplicant{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *acmeHttpReqApplicant) Apply() (*Certificate, error) {
|
||||
access := &domain.HttpreqAccess{}
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
config := httpreq.NewDefaultConfig()
|
||||
endpoint, _ := url.Parse(access.Endpoint)
|
||||
config.Endpoint = endpoint
|
||||
config.Mode = access.Mode
|
||||
config.Username = access.Username
|
||||
config.Password = access.Password
|
||||
if a.option.Timeout != 0 {
|
||||
config.PropagationTimeout = time.Duration(a.option.Timeout) * time.Second
|
||||
}
|
||||
|
||||
provider, err := httpreq.NewDNSProviderConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(a.option, provider)
|
||||
}
|
@ -2,35 +2,38 @@ package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/alidns"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type aliyun struct {
|
||||
type aliyunApplicant struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewAliyun(option *ApplyOption) Applicant {
|
||||
return &aliyun{
|
||||
func NewAliyunApplicant(option *ApplyOption) Applicant {
|
||||
return &aliyunApplicant{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *aliyun) Apply() (*Certificate, error) {
|
||||
func (a *aliyunApplicant) Apply() (*Certificate, error) {
|
||||
access := &domain.AliyunAccess{}
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
os.Setenv("ALICLOUD_ACCESS_KEY", access.AccessKeyId)
|
||||
os.Setenv("ALICLOUD_SECRET_KEY", access.AccessKeySecret)
|
||||
os.Setenv("ALICLOUD_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", a.option.Timeout))
|
||||
dnsProvider, err := alidns.NewDNSProvider()
|
||||
config := alidns.NewDefaultConfig()
|
||||
config.APIKey = access.AccessKeyId
|
||||
config.SecretKey = access.AccessKeySecret
|
||||
if a.option.Timeout != 0 {
|
||||
config.PropagationTimeout = time.Duration(a.option.Timeout) * time.Second
|
||||
}
|
||||
|
||||
provider, err := alidns.NewDNSProviderConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(a.option, dnsProvider)
|
||||
return apply(a.option, provider)
|
||||
}
|
||||
|
@ -208,29 +208,33 @@ func GetWithApplyNode(node *domain.WorkflowNode) (Applicant, error) {
|
||||
}
|
||||
|
||||
func GetWithTypeOption(t string, option *ApplyOption) (Applicant, error) {
|
||||
/*
|
||||
注意:如果追加新的常量值,请保持以 ASCII 排序。
|
||||
NOTICE: If you add new constant, please keep ASCII order.
|
||||
*/
|
||||
switch t {
|
||||
case configTypeAliyun:
|
||||
return NewAliyun(option), nil
|
||||
case configTypeTencentCloud:
|
||||
return NewTencent(option), nil
|
||||
case configTypeHuaweiCloud:
|
||||
return NewHuaweiCloud(option), nil
|
||||
case configTypeAWS:
|
||||
return NewAws(option), nil
|
||||
case configTypeCloudflare:
|
||||
return NewCloudflare(option), nil
|
||||
case configTypeNameSilo:
|
||||
return NewNamesilo(option), nil
|
||||
case configTypeGoDaddy:
|
||||
return NewGodaddy(option), nil
|
||||
case configTypePowerDNS:
|
||||
return NewPdns(option), nil
|
||||
case configTypeACMEHttpReq:
|
||||
return NewHttpreq(option), nil
|
||||
return NewACMEHttpReqApplicant(option), nil
|
||||
case configTypeAliyun:
|
||||
return NewAliyunApplicant(option), nil
|
||||
case configTypeAWS:
|
||||
return NewAWSApplicant(option), nil
|
||||
case configTypeCloudflare:
|
||||
return NewCloudflareApplicant(option), nil
|
||||
case configTypeGoDaddy:
|
||||
return NewGoDaddyApplicant(option), nil
|
||||
case configTypeHuaweiCloud:
|
||||
return NewHuaweiCloudApplicant(option), nil
|
||||
case configTypeNameSilo:
|
||||
return NewNamesiloApplicant(option), nil
|
||||
case configTypePowerDNS:
|
||||
return NewPowerDNSApplicant(option), nil
|
||||
case configTypeTencentCloud:
|
||||
return NewTencentCloudApplicant(option), nil
|
||||
case configTypeVolcEngine:
|
||||
return NewVolcengine(option), nil
|
||||
return NewVolcEngineApplicant(option), nil
|
||||
default:
|
||||
return nil, errors.New("unknown config type")
|
||||
return nil, fmt.Errorf("unsupported applicant type: %s", t)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,38 +2,40 @@ package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/route53"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type aws struct {
|
||||
type awsApplicant struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewAws(option *ApplyOption) Applicant {
|
||||
return &aws{
|
||||
func NewAWSApplicant(option *ApplyOption) Applicant {
|
||||
return &awsApplicant{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *aws) Apply() (*Certificate, error) {
|
||||
func (a *awsApplicant) Apply() (*Certificate, error) {
|
||||
access := &domain.AwsAccess{}
|
||||
json.Unmarshal([]byte(t.option.Access), access)
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
os.Setenv("AWS_REGION", access.Region)
|
||||
os.Setenv("AWS_ACCESS_KEY_ID", access.AccessKeyId)
|
||||
os.Setenv("AWS_SECRET_ACCESS_KEY", access.SecretAccessKey)
|
||||
os.Setenv("AWS_HOSTED_ZONE_ID", access.HostedZoneId)
|
||||
os.Setenv("AWS_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", t.option.Timeout))
|
||||
config := route53.NewDefaultConfig()
|
||||
config.AccessKeyID = access.AccessKeyId
|
||||
config.SecretAccessKey = access.SecretAccessKey
|
||||
config.Region = access.Region
|
||||
config.HostedZoneID = access.HostedZoneId
|
||||
if a.option.Timeout != 0 {
|
||||
config.PropagationTimeout = time.Duration(a.option.Timeout) * time.Second
|
||||
}
|
||||
|
||||
dnsProvider, err := route53.NewDNSProvider()
|
||||
provider, err := route53.NewDNSProviderConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(t.option, dnsProvider)
|
||||
return apply(a.option, provider)
|
||||
}
|
||||
|
@ -2,35 +2,37 @@ package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
cf "github.com/go-acme/lego/v4/providers/dns/cloudflare"
|
||||
"github.com/go-acme/lego/v4/providers/dns/cloudflare"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type cloudflare struct {
|
||||
type cloudflareApplicant struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewCloudflare(option *ApplyOption) Applicant {
|
||||
return &cloudflare{
|
||||
func NewCloudflareApplicant(option *ApplyOption) Applicant {
|
||||
return &cloudflareApplicant{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cloudflare) Apply() (*Certificate, error) {
|
||||
func (a *cloudflareApplicant) Apply() (*Certificate, error) {
|
||||
access := &domain.CloudflareAccess{}
|
||||
json.Unmarshal([]byte(c.option.Access), access)
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
os.Setenv("CLOUDFLARE_DNS_API_TOKEN", access.DnsApiToken)
|
||||
os.Setenv("CLOUDFLARE_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", c.option.Timeout))
|
||||
config := cloudflare.NewDefaultConfig()
|
||||
config.AuthToken = access.DnsApiToken
|
||||
if a.option.Timeout != 0 {
|
||||
config.PropagationTimeout = time.Duration(a.option.Timeout) * time.Second
|
||||
}
|
||||
|
||||
provider, err := cf.NewDNSProvider()
|
||||
provider, err := cloudflare.NewDNSProviderConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(c.option, provider)
|
||||
return apply(a.option, provider)
|
||||
}
|
||||
|
@ -2,36 +2,38 @@ package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
godaddyProvider "github.com/go-acme/lego/v4/providers/dns/godaddy"
|
||||
"github.com/go-acme/lego/v4/providers/dns/godaddy"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type godaddy struct {
|
||||
type godaddyApplicant struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewGodaddy(option *ApplyOption) Applicant {
|
||||
return &godaddy{
|
||||
func NewGoDaddyApplicant(option *ApplyOption) Applicant {
|
||||
return &godaddyApplicant{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *godaddy) Apply() (*Certificate, error) {
|
||||
func (a *godaddyApplicant) Apply() (*Certificate, error) {
|
||||
access := &domain.GodaddyAccess{}
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
os.Setenv("GODADDY_API_KEY", access.ApiKey)
|
||||
os.Setenv("GODADDY_API_SECRET", access.ApiSecret)
|
||||
os.Setenv("GODADDY_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", a.option.Timeout))
|
||||
config := godaddy.NewDefaultConfig()
|
||||
config.APIKey = access.ApiKey
|
||||
config.APISecret = access.ApiSecret
|
||||
if a.option.Timeout != 0 {
|
||||
config.PropagationTimeout = time.Duration(a.option.Timeout) * time.Second
|
||||
}
|
||||
|
||||
dnsProvider, err := godaddyProvider.NewDNSProvider()
|
||||
provider, err := godaddy.NewDNSProviderConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(a.option, dnsProvider)
|
||||
return apply(a.option, provider)
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/httpreq"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type httpReq struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewHttpreq(option *ApplyOption) Applicant {
|
||||
return &httpReq{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *httpReq) Apply() (*Certificate, error) {
|
||||
access := &domain.HttpreqAccess{}
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
os.Setenv("HTTPREQ_ENDPOINT", access.Endpoint)
|
||||
os.Setenv("HTTPREQ_MODE", access.Mode)
|
||||
os.Setenv("HTTPREQ_USERNAME", access.Username)
|
||||
os.Setenv("HTTPREQ_PASSWORD", access.Password)
|
||||
os.Setenv("HTTPREQ_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", a.option.Timeout))
|
||||
dnsProvider, err := httpreq.NewDNSProvider()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(a.option, dnsProvider)
|
||||
}
|
@ -2,42 +2,45 @@ package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
huaweicloudProvider "github.com/go-acme/lego/v4/providers/dns/huaweicloud"
|
||||
huaweicloud "github.com/go-acme/lego/v4/providers/dns/huaweicloud"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type huaweicloud struct {
|
||||
type huaweicloudApplicant struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewHuaweiCloud(option *ApplyOption) Applicant {
|
||||
return &huaweicloud{
|
||||
func NewHuaweiCloudApplicant(option *ApplyOption) Applicant {
|
||||
return &huaweicloudApplicant{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *huaweicloud) Apply() (*Certificate, error) {
|
||||
func (a *huaweicloudApplicant) Apply() (*Certificate, error) {
|
||||
access := &domain.HuaweiCloudAccess{}
|
||||
json.Unmarshal([]byte(t.option.Access), access)
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
region := access.Region
|
||||
if region == "" {
|
||||
// 华为云的 SDK 要求必须传一个区域,实际上 DNS-01 流程里用不到,但不传会报错
|
||||
region = "cn-north-1"
|
||||
}
|
||||
|
||||
os.Setenv("HUAWEICLOUD_REGION", region) // 华为云的 SDK 要求必须传一个区域,实际上 DNS-01 流程里用不到,但不传会报错
|
||||
os.Setenv("HUAWEICLOUD_ACCESS_KEY_ID", access.AccessKeyId)
|
||||
os.Setenv("HUAWEICLOUD_SECRET_ACCESS_KEY", access.SecretAccessKey)
|
||||
os.Setenv("HUAWEICLOUD_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", t.option.Timeout))
|
||||
config := huaweicloud.NewDefaultConfig()
|
||||
config.AccessKeyID = access.AccessKeyId
|
||||
config.SecretAccessKey = access.SecretAccessKey
|
||||
config.Region = region
|
||||
if a.option.Timeout != 0 {
|
||||
config.PropagationTimeout = time.Duration(a.option.Timeout) * time.Second
|
||||
}
|
||||
|
||||
dnsProvider, err := huaweicloudProvider.NewDNSProvider()
|
||||
provider, err := huaweicloud.NewDNSProviderConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(t.option, dnsProvider)
|
||||
return apply(a.option, provider)
|
||||
}
|
||||
|
@ -2,35 +2,37 @@ package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
namesiloProvider "github.com/go-acme/lego/v4/providers/dns/namesilo"
|
||||
namesilo "github.com/go-acme/lego/v4/providers/dns/namesilo"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type namesilo struct {
|
||||
type namesiloApplicant struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewNamesilo(option *ApplyOption) Applicant {
|
||||
return &namesilo{
|
||||
func NewNamesiloApplicant(option *ApplyOption) Applicant {
|
||||
return &namesiloApplicant{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *namesilo) Apply() (*Certificate, error) {
|
||||
func (a *namesiloApplicant) Apply() (*Certificate, error) {
|
||||
access := &domain.NameSiloAccess{}
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
os.Setenv("NAMESILO_API_KEY", access.ApiKey)
|
||||
os.Setenv("NAMESILO_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", a.option.Timeout))
|
||||
config := namesilo.NewDefaultConfig()
|
||||
config.APIKey = access.ApiKey
|
||||
if a.option.Timeout != 0 {
|
||||
config.PropagationTimeout = time.Duration(a.option.Timeout) * time.Second
|
||||
}
|
||||
|
||||
dnsProvider, err := namesiloProvider.NewDNSProvider()
|
||||
provider, err := namesilo.NewDNSProviderConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(a.option, dnsProvider)
|
||||
return apply(a.option, provider)
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/pdns"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type powerdns struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewPdns(option *ApplyOption) Applicant {
|
||||
return &powerdns{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *powerdns) Apply() (*Certificate, error) {
|
||||
access := &domain.PdnsAccess{}
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
os.Setenv("PDNS_API_URL", access.ApiUrl)
|
||||
os.Setenv("PDNS_API_KEY", access.ApiKey)
|
||||
os.Setenv("PDNS_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", a.option.Timeout))
|
||||
dnsProvider, err := pdns.NewDNSProvider()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(a.option, dnsProvider)
|
||||
}
|
41
internal/applicant/powerdns.go
Normal file
41
internal/applicant/powerdns.go
Normal file
@ -0,0 +1,41 @@
|
||||
package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/pdns"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type powerdnsApplicant struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewPowerDNSApplicant(option *ApplyOption) Applicant {
|
||||
return &powerdnsApplicant{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *powerdnsApplicant) Apply() (*Certificate, error) {
|
||||
access := &domain.PdnsAccess{}
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
config := pdns.NewDefaultConfig()
|
||||
host, _ := url.Parse(access.ApiUrl)
|
||||
config.Host = host
|
||||
config.APIKey = access.ApiKey
|
||||
if a.option.Timeout != 0 {
|
||||
config.PropagationTimeout = time.Duration(a.option.Timeout) * time.Second
|
||||
}
|
||||
|
||||
provider, err := pdns.NewDNSProviderConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(a.option, provider)
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type tencent struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewTencent(option *ApplyOption) Applicant {
|
||||
return &tencent{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *tencent) Apply() (*Certificate, error) {
|
||||
access := &domain.TencentAccess{}
|
||||
json.Unmarshal([]byte(t.option.Access), access)
|
||||
|
||||
os.Setenv("TENCENTCLOUD_SECRET_ID", access.SecretId)
|
||||
os.Setenv("TENCENTCLOUD_SECRET_KEY", access.SecretKey)
|
||||
os.Setenv("TENCENTCLOUD_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", t.option.Timeout))
|
||||
|
||||
dnsProvider, err := tencentcloud.NewDNSProvider()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(t.option, dnsProvider)
|
||||
}
|
39
internal/applicant/tencentcloud.go
Normal file
39
internal/applicant/tencentcloud.go
Normal file
@ -0,0 +1,39 @@
|
||||
package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/providers/dns/tencentcloud"
|
||||
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type tencentcloudApplicant struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewTencentCloudApplicant(option *ApplyOption) Applicant {
|
||||
return &tencentcloudApplicant{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *tencentcloudApplicant) Apply() (*Certificate, error) {
|
||||
access := &domain.TencentAccess{}
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
config := tencentcloud.NewDefaultConfig()
|
||||
config.SecretID = access.SecretId
|
||||
config.SecretKey = access.SecretKey
|
||||
if a.option.Timeout != 0 {
|
||||
config.PropagationTimeout = time.Duration(a.option.Timeout) * time.Second
|
||||
}
|
||||
|
||||
provider, err := tencentcloud.NewDNSProviderConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(a.option, provider)
|
||||
}
|
@ -2,34 +2,37 @@ package applicant
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
volcengineDns "github.com/go-acme/lego/v4/providers/dns/volcengine"
|
||||
"github.com/go-acme/lego/v4/providers/dns/volcengine"
|
||||
"github.com/usual2970/certimate/internal/domain"
|
||||
)
|
||||
|
||||
type volcengine struct {
|
||||
type volcengineApplicant struct {
|
||||
option *ApplyOption
|
||||
}
|
||||
|
||||
func NewVolcengine(option *ApplyOption) Applicant {
|
||||
return &volcengine{
|
||||
func NewVolcEngineApplicant(option *ApplyOption) Applicant {
|
||||
return &volcengineApplicant{
|
||||
option: option,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *volcengine) Apply() (*Certificate, error) {
|
||||
func (a *volcengineApplicant) Apply() (*Certificate, error) {
|
||||
access := &domain.VolcEngineAccess{}
|
||||
json.Unmarshal([]byte(a.option.Access), access)
|
||||
|
||||
os.Setenv("VOLC_ACCESSKEY", access.AccessKeyId)
|
||||
os.Setenv("VOLC_SECRETKEY", access.SecretAccessKey)
|
||||
os.Setenv("VOLC_PROPAGATION_TIMEOUT", fmt.Sprintf("%d", a.option.Timeout))
|
||||
dnsProvider, err := volcengineDns.NewDNSProvider()
|
||||
config := volcengine.NewDefaultConfig()
|
||||
config.AccessKey = access.AccessKeyId
|
||||
config.SecretKey = access.SecretAccessKey
|
||||
if a.option.Timeout != 0 {
|
||||
config.PropagationTimeout = time.Duration(a.option.Timeout) * time.Second
|
||||
}
|
||||
|
||||
provider, err := volcengine.NewDNSProviderConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return apply(a.option, dnsProvider)
|
||||
return apply(a.option, provider)
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defaultExpireSubject = "您有 {COUNT} 张证书即将过期"
|
||||
defaultExpireMessage = "有 {COUNT} 张证书即将过期,域名分别为 {DOMAINS},请保持关注!"
|
||||
defaultExpireSubject = "您有 ${COUNT} 张证书即将过期"
|
||||
defaultExpireMessage = "有 ${COUNT} 张证书即将过期,域名分别为 ${DOMAINS},请保持关注!"
|
||||
)
|
||||
|
||||
type CertificateRepository interface {
|
||||
@ -88,11 +88,11 @@ func buildMsg(records []domain.Certificate) *domain.NotifyMessage {
|
||||
countStr := strconv.Itoa(count)
|
||||
domainStr := strings.Join(domains, ";")
|
||||
|
||||
subject = strings.ReplaceAll(subject, "{COUNT}", countStr)
|
||||
subject = strings.ReplaceAll(subject, "{DOMAINS}", domainStr)
|
||||
subject = strings.ReplaceAll(subject, "${COUNT}", countStr)
|
||||
subject = strings.ReplaceAll(subject, "${DOMAINS}", domainStr)
|
||||
|
||||
message = strings.ReplaceAll(message, "{COUNT}", countStr)
|
||||
message = strings.ReplaceAll(message, "{DOMAINS}", domainStr)
|
||||
message = strings.ReplaceAll(message, "${COUNT}", countStr)
|
||||
message = strings.ReplaceAll(message, "${DOMAINS}", domainStr)
|
||||
|
||||
// 返回消息
|
||||
return &domain.NotifyMessage{
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { ClientResponseError } from "pocketbase";
|
||||
|
||||
import { getPocketBase } from "@/repository/pocketbase";
|
||||
|
||||
export const notifyTest = async (channel: string) => {
|
||||
@ -14,7 +16,7 @@ export const notifyTest = async (channel: string) => {
|
||||
});
|
||||
|
||||
if (resp.code != 0) {
|
||||
throw new Error(resp.msg);
|
||||
throw new ClientResponseError({ status: resp.code, response: resp, data: {} });
|
||||
}
|
||||
|
||||
return resp;
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { Statistics } from "@/domain/statistics";
|
||||
import { ClientResponseError } from "pocketbase";
|
||||
|
||||
import { type Statistics } from "@/domain/statistics";
|
||||
import { getPocketBase } from "@/repository/pocketbase";
|
||||
|
||||
export const get = async () => {
|
||||
@ -8,8 +10,8 @@ export const get = async () => {
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
if (resp.code !== 0) {
|
||||
throw new Error(resp.msg);
|
||||
if (resp.code != 0) {
|
||||
throw new ClientResponseError({ status: resp.code, response: resp, data: {} });
|
||||
}
|
||||
|
||||
return resp.data as Statistics;
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { ClientResponseError } from "pocketbase";
|
||||
|
||||
import { getPocketBase } from "@/repository/pocketbase";
|
||||
|
||||
export const run = async (id: string) => {
|
||||
@ -14,7 +16,7 @@ export const run = async (id: string) => {
|
||||
});
|
||||
|
||||
if (resp.code != 0) {
|
||||
throw new Error(resp.msg);
|
||||
throw new ClientResponseError({ status: resp.code, response: resp, data: {} });
|
||||
}
|
||||
|
||||
return resp;
|
||||
|
275
ui/src/components/ui/MultipleInput.tsx
Normal file
275
ui/src/components/ui/MultipleInput.tsx
Normal file
@ -0,0 +1,275 @@
|
||||
import { forwardRef, useImperativeHandle, useMemo, useRef, type ChangeEvent } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { Button, Input, Space, type InputRef, type InputProps } from "antd";
|
||||
import { produce } from "immer";
|
||||
import { ArrowDown as ArrowDownIcon, ArrowUp as ArrowUpIcon, Minus as MinusIcon, Plus as PlusIcon } from "lucide-react";
|
||||
|
||||
export type MultipleInputProps = Omit<InputProps, "count" | "defaultValue" | "showCount" | "value" | "onChange" | "onPressEnter" | "onClear"> & {
|
||||
allowClear?: boolean;
|
||||
defaultValue?: string[];
|
||||
maxCount?: number;
|
||||
minCount?: number;
|
||||
showSortButton?: boolean;
|
||||
value?: string[];
|
||||
onChange?: (index: number, e: ChangeEvent<HTMLInputElement>) => void;
|
||||
onCreate?: (index: number) => void;
|
||||
onRemove?: (index: number) => void;
|
||||
onSort?: (oldIndex: number, newIndex: number) => void;
|
||||
onValueChange?: (value: string[]) => void;
|
||||
};
|
||||
|
||||
const MultipleInput = ({
|
||||
allowClear = false,
|
||||
disabled,
|
||||
maxCount,
|
||||
minCount,
|
||||
showSortButton = true,
|
||||
onChange,
|
||||
onCreate,
|
||||
onSort,
|
||||
onRemove,
|
||||
...props
|
||||
}: MultipleInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const itemRefs = useRef<MultipleInputItemInstance[]>([]);
|
||||
|
||||
const [value, setValue] = useControllableValue<string[]>(props, {
|
||||
valuePropName: "value",
|
||||
defaultValue: [],
|
||||
defaultValuePropName: "defaultValue",
|
||||
trigger: "onValueChange",
|
||||
});
|
||||
|
||||
const handleCreate = () => {
|
||||
const newValue = produce(value, (draft) => {
|
||||
draft.push("");
|
||||
});
|
||||
setValue(newValue);
|
||||
setTimeout(() => itemRefs.current[newValue.length - 1]?.focus(), 0);
|
||||
|
||||
onCreate?.(newValue.length - 1);
|
||||
};
|
||||
|
||||
const handleInputChange = (index: number, e: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = produce(value, (draft) => {
|
||||
draft[index] = e.target.value;
|
||||
});
|
||||
setValue(newValue);
|
||||
|
||||
onChange?.(index, e);
|
||||
};
|
||||
|
||||
const handleInputBlur = (index: number) => {
|
||||
if (!allowClear && !value[index]) {
|
||||
const newValue = produce(value, (draft) => {
|
||||
draft.splice(index, 1);
|
||||
});
|
||||
setValue(newValue);
|
||||
}
|
||||
};
|
||||
|
||||
const handleClickUp = (index: number) => {
|
||||
if (index === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newValue = produce(value, (draft) => {
|
||||
const temp = draft[index - 1];
|
||||
draft[index - 1] = draft[index];
|
||||
draft[index] = temp;
|
||||
});
|
||||
setValue(newValue);
|
||||
|
||||
onSort?.(index, index - 1);
|
||||
};
|
||||
|
||||
const handleClickDown = (index: number) => {
|
||||
if (index === value.length - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newValue = produce(value, (draft) => {
|
||||
const temp = draft[index + 1];
|
||||
draft[index + 1] = draft[index];
|
||||
draft[index] = temp;
|
||||
});
|
||||
setValue(newValue);
|
||||
|
||||
onSort?.(index, index + 1);
|
||||
};
|
||||
|
||||
const handleClickAdd = (index: number) => {
|
||||
const newValue = produce(value, (draft) => {
|
||||
draft.splice(index + 1, 0, "");
|
||||
});
|
||||
setValue(newValue);
|
||||
setTimeout(() => itemRefs.current[index + 1]?.focus(), 0);
|
||||
|
||||
onCreate?.(index + 1);
|
||||
};
|
||||
|
||||
const handleClickRemove = (index: number) => {
|
||||
const newValue = produce(value, (draft) => {
|
||||
draft.splice(index, 1);
|
||||
});
|
||||
setValue(newValue);
|
||||
|
||||
onRemove?.(index);
|
||||
};
|
||||
|
||||
return value == null || value.length === 0 ? (
|
||||
<Button block color="primary" disabled={disabled || maxCount === 0} size={props.size} variant="dashed" onClick={handleCreate}>
|
||||
{t("common.button.add")}
|
||||
</Button>
|
||||
) : (
|
||||
<Space className="w-full" direction="vertical" size="small">
|
||||
{value.map((element, index) => {
|
||||
const allowUp = index > 0;
|
||||
const allowDown = index < value.length - 1;
|
||||
const allowRemove = minCount == null || value.length > minCount;
|
||||
const allowAdd = maxCount == null || value.length < maxCount;
|
||||
|
||||
return (
|
||||
<MultipleInputItem
|
||||
{...props}
|
||||
ref={(ref) => (itemRefs.current[index] = ref!)}
|
||||
allowAdd={allowAdd}
|
||||
allowClear={allowClear}
|
||||
allowDown={allowDown}
|
||||
allowRemove={allowRemove}
|
||||
allowUp={allowUp}
|
||||
disabled={disabled}
|
||||
defaultValue={undefined}
|
||||
showSortButton={showSortButton}
|
||||
value={element}
|
||||
onBlur={() => handleInputBlur(index)}
|
||||
onChange={(val) => handleInputChange(index, val)}
|
||||
onClickAdd={() => handleClickAdd(index)}
|
||||
onClickDown={() => handleClickDown(index)}
|
||||
onClickUp={() => handleClickUp(index)}
|
||||
onClickRemove={() => handleClickRemove(index)}
|
||||
onValueChange={undefined}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
|
||||
type MultipleInputItemProps = Omit<
|
||||
MultipleInputProps,
|
||||
"defaultValue" | "maxCount" | "minCount" | "preset" | "value" | "onChange" | "onCreate" | "onRemove" | "onSort" | "onValueChange"
|
||||
> & {
|
||||
allowAdd: boolean;
|
||||
allowRemove: boolean;
|
||||
allowUp: boolean;
|
||||
allowDown: boolean;
|
||||
defaultValue?: string;
|
||||
value?: string;
|
||||
onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
|
||||
onClickAdd?: () => void;
|
||||
onClickDown?: () => void;
|
||||
onClickUp?: () => void;
|
||||
onClickRemove?: () => void;
|
||||
onValueChange?: (value: string) => void;
|
||||
};
|
||||
|
||||
type MultipleInputItemInstance = {
|
||||
focus: () => void;
|
||||
blur: () => void;
|
||||
select: () => void;
|
||||
};
|
||||
|
||||
const MultipleInputItem = forwardRef<MultipleInputItemInstance, MultipleInputItemProps>(
|
||||
(
|
||||
{
|
||||
allowAdd,
|
||||
allowClear,
|
||||
allowDown,
|
||||
allowRemove,
|
||||
allowUp,
|
||||
disabled,
|
||||
showSortButton,
|
||||
onChange,
|
||||
onClickAdd,
|
||||
onClickDown,
|
||||
onClickUp,
|
||||
onClickRemove,
|
||||
...props
|
||||
}: MultipleInputItemProps,
|
||||
ref
|
||||
) => {
|
||||
const inputRef = useRef<InputRef>(null);
|
||||
|
||||
const [value, setValue] = useControllableValue<string>(props, {
|
||||
valuePropName: "value",
|
||||
defaultValue: "",
|
||||
defaultValuePropName: "defaultValue",
|
||||
trigger: "onValueChange",
|
||||
});
|
||||
|
||||
const upBtn = useMemo(() => {
|
||||
if (!showSortButton) return null;
|
||||
return <Button icon={<ArrowUpIcon size={14} />} color="default" disabled={disabled || !allowUp} shape="circle" variant="text" onClick={onClickUp} />;
|
||||
}, [allowUp, disabled, showSortButton, onClickUp]);
|
||||
const downBtn = useMemo(() => {
|
||||
if (!showSortButton) return null;
|
||||
return (
|
||||
<Button icon={<ArrowDownIcon size={14} />} color="default" disabled={disabled || !allowDown} shape="circle" variant="text" onClick={onClickDown} />
|
||||
);
|
||||
}, [allowDown, disabled, showSortButton, onClickDown]);
|
||||
const removeBtn = useMemo(() => {
|
||||
return (
|
||||
<Button icon={<MinusIcon size={14} />} color="default" disabled={disabled || !allowRemove} shape="circle" variant="text" onClick={onClickRemove} />
|
||||
);
|
||||
}, [allowRemove, disabled, onClickRemove]);
|
||||
const addBtn = useMemo(() => {
|
||||
return <Button icon={<PlusIcon size={14} />} color="default" disabled={disabled || !allowAdd} shape="circle" variant="text" onClick={onClickAdd} />;
|
||||
}, [allowAdd, disabled, onClickAdd]);
|
||||
|
||||
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
setValue(e.target.value);
|
||||
|
||||
onChange?.(e);
|
||||
};
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
focus: () => {
|
||||
inputRef.current?.focus();
|
||||
},
|
||||
blur: () => {
|
||||
inputRef.current?.blur();
|
||||
},
|
||||
select: () => {
|
||||
inputRef.current?.select();
|
||||
},
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="flex flex-nowrap items-center space-x-2">
|
||||
<div className="flex-grow">
|
||||
<Input
|
||||
{...props}
|
||||
ref={inputRef}
|
||||
className={undefined}
|
||||
style={undefined}
|
||||
allowClear={allowClear}
|
||||
defaultValue={undefined}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
{removeBtn}
|
||||
{upBtn}
|
||||
{downBtn}
|
||||
{addBtn}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default MultipleInput;
|
@ -33,8 +33,8 @@ export type NotifyTemplate = {
|
||||
};
|
||||
|
||||
export const defaultNotifyTemplate: NotifyTemplate = {
|
||||
subject: "您有 {COUNT} 张证书即将过期",
|
||||
message: "有 {COUNT} 张证书即将过期,域名分别为 {DOMAINS},请保持关注!",
|
||||
subject: "您有 ${COUNT} 张证书即将过期",
|
||||
message: "有 ${COUNT} 张证书即将过期,域名分别为 ${DOMAINS},请保持关注!",
|
||||
};
|
||||
// #endregion
|
||||
|
||||
|
@ -17,6 +17,9 @@ i18n
|
||||
backend: {
|
||||
loadPath: "/locales/{{lng}}.json",
|
||||
},
|
||||
detection: {
|
||||
lookupLocalStorage: "certimate-ui-lang",
|
||||
},
|
||||
});
|
||||
|
||||
export const localeNames = {
|
||||
|
@ -19,10 +19,10 @@
|
||||
"settings.notification.template.card.title": "Template",
|
||||
"settings.notification.template.form.subject.label": "Subject",
|
||||
"settings.notification.template.form.subject.placeholder": "Please enter notification subject",
|
||||
"settings.notification.template.form.subject.tooltip": "Optional variables ({COUNT}: number of expiring soon)",
|
||||
"settings.notification.template.form.subject.tooltip": "Optional variables (${COUNT}: number of expiring soon)",
|
||||
"settings.notification.template.form.message.label": "Message",
|
||||
"settings.notification.template.form.message.placeholder": "Please enter notification message",
|
||||
"settings.notification.template.form.message.tooltip": "Optional variables ({COUNT}: number of expiring soon. {DOMAINS}: Domain list)",
|
||||
"settings.notification.template.form.message.tooltip": "Optional variables (${COUNT}: number of expiring soon. ${DOMAINS}: Domain list)",
|
||||
"settings.notification.channels.card.title": "Channels",
|
||||
"settings.notification.channel.enabled.on": "On",
|
||||
"settings.notification.channel.enabled.off": "Off",
|
||||
|
@ -13,7 +13,9 @@
|
||||
"workflow.props.name.default": "Unnamed",
|
||||
"workflow.props.description": "Description",
|
||||
"workflow.props.description.placeholder": "Please enter description",
|
||||
"workflow.props.execution_method": "Execution Method",
|
||||
"workflow.props.trigger": "Trigger",
|
||||
"workflow.props.trigger.auto": "Auto",
|
||||
"workflow.props.trigger.manual": "Manual",
|
||||
"workflow.props.state": "State",
|
||||
"workflow.props.state.filter.enabled": "Enabled",
|
||||
"workflow.props.state.filter.disabled": "Disabled",
|
||||
|
@ -19,10 +19,10 @@
|
||||
"settings.notification.template.card.title": "通知模板",
|
||||
"settings.notification.template.form.subject.label": "通知主题",
|
||||
"settings.notification.template.form.subject.placeholder": "请输入通知主题",
|
||||
"settings.notification.template.form.subject.tooltip": "可选的变量({COUNT}: 即将过期张数)",
|
||||
"settings.notification.template.form.subject.tooltip": "可选的变量(${COUNT}: 即将过期张数)",
|
||||
"settings.notification.template.form.message.label": "通知内容",
|
||||
"settings.notification.template.form.message.placeholder": "请输入通知内容",
|
||||
"settings.notification.template.form.message.tooltip": "可选的变量({COUNT}: 即将过期张数;{DOMAINS}: 域名列表)",
|
||||
"settings.notification.template.form.message.tooltip": "可选的变量(${COUNT}: 即将过期张数;${DOMAINS}: 域名列表)",
|
||||
"settings.notification.channels.card.title": "通知渠道",
|
||||
"settings.notification.channel.enabled.on": "启用",
|
||||
"settings.notification.channel.enabled.off": "未启用",
|
||||
|
@ -13,7 +13,9 @@
|
||||
"workflow.props.name.default": "未命名工作流",
|
||||
"workflow.props.description": "描述",
|
||||
"workflow.props.description.placeholder": "请输入描述",
|
||||
"workflow.props.execution_method": "执行方式",
|
||||
"workflow.props.trigger": "触发方式",
|
||||
"workflow.props.trigger.auto": "自动",
|
||||
"workflow.props.trigger.manual": "手动",
|
||||
"workflow.props.state": "启用状态",
|
||||
"workflow.props.state.filter.enabled": "启用",
|
||||
"workflow.props.state.filter.disabled": "未启用",
|
||||
|
@ -61,19 +61,19 @@ const WorkflowList = () => {
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "type",
|
||||
title: t("workflow.props.execution_method"),
|
||||
key: "trigger",
|
||||
title: t("workflow.props.trigger"),
|
||||
ellipsis: true,
|
||||
render: (_, record) => {
|
||||
const method = record.type;
|
||||
if (!method) {
|
||||
const trigger = record.type;
|
||||
if (!trigger) {
|
||||
return "-";
|
||||
} else if (method === "manual") {
|
||||
return <Typography.Text>{t("workflow.node.start.form.executionMethod.options.manual")}</Typography.Text>;
|
||||
} else if (method === "auto") {
|
||||
} else if (trigger === "manual") {
|
||||
return <Typography.Text>{t("workflow.props.trigger.manual")}</Typography.Text>;
|
||||
} else if (trigger === "auto") {
|
||||
return (
|
||||
<Space className="max-w-full" direction="vertical" size={4}>
|
||||
<Typography.Text>{t("workflow.node.start.form.executionMethod.options.auto")}</Typography.Text>
|
||||
<Typography.Text>{t("workflow.props.trigger.auto")}</Typography.Text>
|
||||
<Typography.Text type="secondary">{record.crontab ?? ""}</Typography.Text>
|
||||
</Space>
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user