mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2026-05-06 14:03:40 +08:00
refactor: improve provider selection logic in DNSChallenge component and update column definition in ACMEUser view
This commit is contained in:
@@ -2,6 +2,7 @@ package certificate
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/internal/cert/dns"
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
@@ -23,28 +24,32 @@ func GetDnsCredential(c *gin.Context) {
|
||||
}
|
||||
type apiDnsCredential struct {
|
||||
model.Model
|
||||
Name string `json:"name"`
|
||||
Provider string `json:"provider"`
|
||||
Name string `json:"name"`
|
||||
Provider string `json:"provider"`
|
||||
ProviderCode string `json:"provider_code"`
|
||||
dns.Config
|
||||
}
|
||||
c.JSON(http.StatusOK, apiDnsCredential{
|
||||
Model: dnsCredential.Model,
|
||||
Name: dnsCredential.Name,
|
||||
Provider: dnsCredential.Provider,
|
||||
Config: *dnsCredential.Config,
|
||||
Model: dnsCredential.Model,
|
||||
Name: dnsCredential.Name,
|
||||
Provider: dnsCredential.Provider,
|
||||
ProviderCode: dnsCredential.ProviderCode,
|
||||
Config: *dnsCredential.Config,
|
||||
})
|
||||
}
|
||||
|
||||
func GetDnsCredentialList(c *gin.Context) {
|
||||
cosy.Core[model.DnsCredential](c).
|
||||
SetEqual("provider_code").
|
||||
SetEqual("provider").
|
||||
SetFussy("name").
|
||||
PagingList()
|
||||
}
|
||||
|
||||
type DnsCredentialManageJson struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Provider string `json:"provider"`
|
||||
Name string `json:"name" binding:"required"`
|
||||
Provider string `json:"provider"`
|
||||
ProviderCode string `json:"provider_code"`
|
||||
dns.Config
|
||||
}
|
||||
|
||||
@@ -54,11 +59,14 @@ func AddDnsCredential(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
providerCode := resolveProviderCode(json)
|
||||
json.Config.Code = providerCode
|
||||
json.Config.Name = json.Provider
|
||||
dnsCredential := model.DnsCredential{
|
||||
Name: json.Name,
|
||||
Config: &json.Config,
|
||||
Provider: json.Provider,
|
||||
Name: json.Name,
|
||||
Config: &json.Config,
|
||||
Provider: json.Provider,
|
||||
ProviderCode: providerCode,
|
||||
}
|
||||
|
||||
d := query.DnsCredential
|
||||
@@ -89,10 +97,12 @@ func EditDnsCredential(c *gin.Context) {
|
||||
}
|
||||
|
||||
json.Config.Name = json.Provider
|
||||
json.Config.Code = resolveProviderCode(json)
|
||||
_, err = d.Where(d.ID.Eq(dnsCredential.ID)).Updates(&model.DnsCredential{
|
||||
Name: json.Name,
|
||||
Config: &json.Config,
|
||||
Provider: json.Provider,
|
||||
Name: json.Name,
|
||||
Config: &json.Config,
|
||||
Provider: json.Provider,
|
||||
ProviderCode: resolveProviderCode(json),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -106,3 +116,17 @@ func EditDnsCredential(c *gin.Context) {
|
||||
func DeleteDnsCredential(c *gin.Context) {
|
||||
cosy.Core[model.DnsCredential](c).Destroy()
|
||||
}
|
||||
|
||||
func resolveProviderCode(payload DnsCredentialManageJson) string {
|
||||
if trimmed := normalizeProviderCode(payload.ProviderCode); trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
if trimmed := normalizeProviderCode(payload.Code); trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
return normalizeProviderCode(payload.Provider)
|
||||
}
|
||||
|
||||
func normalizeProviderCode(value string) string {
|
||||
return strings.TrimSpace(strings.ToLower(value))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "nginx-ui-app-next",
|
||||
"type": "module",
|
||||
"version": "2.3.1",
|
||||
"version": "2.3.2",
|
||||
"packageManager": "pnpm@10.24.0+sha512.01ff8ae71b4419903b65c60fb2dc9d34cf8bb6e06d03bde112ef38f7a34d6904c424ba66bea5cdcf12890230bf39f9580473140ed9c946fef328b6e5238a345a",
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
|
||||
@@ -30,6 +30,7 @@ export interface AutoCertOptions {
|
||||
key_type: string
|
||||
acme_user_id?: number
|
||||
provider?: string
|
||||
provider_code?: string
|
||||
must_staple?: boolean
|
||||
lego_disable_cname_support?: boolean
|
||||
revoke_old?: boolean
|
||||
|
||||
@@ -10,6 +10,7 @@ export interface DNSDomain extends ModelBase {
|
||||
id: number
|
||||
name: string
|
||||
provider: string
|
||||
provider_code?: string
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface DnsCredential extends ModelBase {
|
||||
name: string
|
||||
config?: DNSProvider
|
||||
provider: string
|
||||
provider_code?: string
|
||||
code: string
|
||||
configuration: DNSProvider['configuration']
|
||||
}
|
||||
|
||||
@@ -48,18 +48,20 @@ watch(current, () => {
|
||||
if (mounted.value) {
|
||||
data.value.code = undefined
|
||||
data.value.provider = undefined
|
||||
data.value.provider_code = undefined
|
||||
data.value.dns_credential_id = undefined
|
||||
}
|
||||
return
|
||||
}
|
||||
credentials.value = []
|
||||
data.value.code = current.value.code
|
||||
// Keep provider consistent with credential records (prefer provider/code over display name).
|
||||
data.value.provider = current.value.provider || current.value.code || current.value.name
|
||||
// Use display name for credential query; fall back to provider/code if missing.
|
||||
data.value.provider = current.value.name || current.value.provider || current.value.code
|
||||
data.value.provider_code = current.value.code
|
||||
if (mounted.value)
|
||||
data.value.dns_credential_id = undefined
|
||||
|
||||
dns_credential.getList({ provider: data.value.provider }).then(r => {
|
||||
dns_credential.getList({ provider_code: data.value.provider_code || current.value.code }).then(r => {
|
||||
r.data.forEach(v => {
|
||||
credentials.value?.push({
|
||||
value: v.id,
|
||||
@@ -82,12 +84,14 @@ onMounted(async () => {
|
||||
if (idx > -1) {
|
||||
data.value.code = r.code
|
||||
data.value.provider = r.provider
|
||||
data.value.provider_code = r.provider_code || r.code
|
||||
providerIdx.value = idx
|
||||
}
|
||||
else {
|
||||
// provider not supported anymore; clear existing selection to keep form consistent
|
||||
data.value.code = undefined
|
||||
data.value.provider = undefined
|
||||
data.value.provider_code = undefined
|
||||
data.value.dns_credential_id = undefined
|
||||
providerIdx.value = undefined
|
||||
}
|
||||
@@ -112,7 +116,10 @@ const options = computed<SelectProps['options']>(() => {
|
||||
})
|
||||
|
||||
function filterOption(input: string, option?: DefaultOptionType) {
|
||||
return option?.label.toLowerCase().includes(input.toLowerCase())
|
||||
const needle = input.toLowerCase()
|
||||
const label = option?.label?.toString().toLowerCase() ?? ''
|
||||
const value = option?.value?.toString().toLowerCase() ?? ''
|
||||
return label.includes(needle) || value.includes(needle)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":"2.3.1","build_id":1,"total_build":511}
|
||||
{"version":"2.3.2","build_id":1,"total_build":512}
|
||||
@@ -8,7 +8,7 @@ import acme_user from '@/api/acme_user'
|
||||
|
||||
const { message } = App.useApp()
|
||||
|
||||
const columns: StdTableColumn[] = [
|
||||
const columns: ComputedRef<StdTableColumn[]> = computed(() => [
|
||||
{
|
||||
title: () => $gettext('Name'),
|
||||
dataIndex: 'name',
|
||||
@@ -42,7 +42,7 @@ const columns: StdTableColumn[] = [
|
||||
edit: {
|
||||
type: 'autoComplete',
|
||||
autoComplete: {
|
||||
placeholder: () => $gettext('Select or enter a CA directory URL'),
|
||||
placeholder: $gettext('Select or enter a CA directory URL'),
|
||||
allowClear: true,
|
||||
options: [
|
||||
{
|
||||
@@ -132,7 +132,7 @@ const columns: StdTableColumn[] = [
|
||||
dataIndex: 'actions',
|
||||
fixed: 'right',
|
||||
},
|
||||
]
|
||||
])
|
||||
|
||||
function register(id: number, data: AcmeUser) {
|
||||
acme_user.register(id).then(r => {
|
||||
|
||||
@@ -24,7 +24,7 @@ const columns: StdTableColumn[] = [{
|
||||
search: true,
|
||||
}, {
|
||||
title: () => $gettext('Provider'),
|
||||
dataIndex: 'provider',
|
||||
dataIndex: 'provider_code',
|
||||
customRender: ({ record }: CustomRenderArgs) => {
|
||||
return record.provider
|
||||
},
|
||||
@@ -34,7 +34,7 @@ const columns: StdTableColumn[] = [{
|
||||
type: 'select',
|
||||
select: {
|
||||
remote: {
|
||||
valueKey: 'name',
|
||||
valueKey: 'code',
|
||||
labelKey: 'name',
|
||||
api: async () => {
|
||||
return {
|
||||
|
||||
@@ -31,11 +31,12 @@ const credentialLoadingMap = reactive<Record<string, boolean>>({})
|
||||
const providerOptions = computed<SelectOptionList>(() => {
|
||||
const list: SelectOptionList = []
|
||||
dnsProviders.value.forEach(provider => {
|
||||
const label = provider.name ?? provider.provider ?? ''
|
||||
if (label) {
|
||||
const code = provider.code ?? provider.provider ?? ''
|
||||
const label = provider.name ?? provider.provider ?? code
|
||||
if (code) {
|
||||
list.push({
|
||||
label,
|
||||
value: label,
|
||||
value: code,
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -57,20 +58,20 @@ function clearCredentialSelection(formData: DomainForm) {
|
||||
formData.dns_credential_id = undefined
|
||||
}
|
||||
|
||||
async function ensureCredentialOptions(provider: string) {
|
||||
if (!provider || credentialOptions[provider])
|
||||
async function ensureCredentialOptions(providerCode: string) {
|
||||
if (!providerCode || credentialOptions[providerCode])
|
||||
return
|
||||
credentialLoadingMap[provider] = true
|
||||
credentialLoadingMap[providerCode] = true
|
||||
try {
|
||||
const response = await dns_credential.getList({ provider })
|
||||
const response = await dns_credential.getList({ provider_code: providerCode })
|
||||
const list = response?.data ?? []
|
||||
credentialOptions[provider] = list.map(item => ({
|
||||
credentialOptions[providerCode] = list.map(item => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}))
|
||||
}
|
||||
finally {
|
||||
credentialLoadingMap[provider] = false
|
||||
credentialLoadingMap[providerCode] = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +91,11 @@ function resolveProviderName(record: DomainForm) {
|
||||
?? ''
|
||||
}
|
||||
|
||||
function resolveProviderCode(record: DomainForm) {
|
||||
return record.dns_credential?.provider_code
|
||||
?? ''
|
||||
}
|
||||
|
||||
function resolveCredentialName(record: DomainForm) {
|
||||
return record.dns_credential?.name ?? '-'
|
||||
}
|
||||
@@ -116,7 +122,7 @@ const columns: StdTableColumn[] = [{
|
||||
const formData = context.formData
|
||||
if (!formData.provider_initialized) {
|
||||
formData.selected_provider = context.mode === 'edit'
|
||||
? resolveProviderName(formData)
|
||||
? (resolveProviderCode(formData) || resolveProviderName(formData))
|
||||
: ''
|
||||
formData.provider_initialized = true
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ watch(current, () => {
|
||||
if (current.value) {
|
||||
data.value.code = current.value.code!
|
||||
data.value.provider = current.value.name!
|
||||
data.value.provider_code = current.value.code
|
||||
|
||||
auto_cert.get_dns_provider(data.value.code).then(r => {
|
||||
Object.assign(current.value!, r)
|
||||
@@ -50,7 +51,10 @@ const options = computed<SelectProps['options']>(() => {
|
||||
})
|
||||
|
||||
function filterOption(input: string, option?: DefaultOptionType) {
|
||||
return option?.label.toLowerCase().includes(input.toLowerCase())
|
||||
const needle = input.toLowerCase()
|
||||
const label = option?.label?.toString().toLowerCase() ?? ''
|
||||
const value = option?.value?.toString().toLowerCase() ?? ''
|
||||
return label.includes(needle) || value.includes(needle)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -315,11 +315,16 @@ func toProviderCredential(credential *model.DnsCredential) (*Credential, error)
|
||||
}
|
||||
}
|
||||
|
||||
code := credential.Config.Code
|
||||
if code == "" {
|
||||
code = credential.ProviderCode
|
||||
}
|
||||
|
||||
return &Credential{
|
||||
ID: credential.ID,
|
||||
Name: credential.Name,
|
||||
Provider: credential.Provider,
|
||||
Code: credential.Config.Code,
|
||||
Code: code,
|
||||
Values: values,
|
||||
Additional: additional,
|
||||
}, nil
|
||||
|
||||
Binary file not shown.
68
internal/migrate/7.add_provider_code_to_dns_credentials.go
Normal file
68
internal/migrate/7.add_provider_code_to_dns_credentials.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package migrate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/0xJacky/Nginx-UI/internal/cert/dns"
|
||||
"github.com/0xJacky/Nginx-UI/model"
|
||||
"github.com/go-gormigrate/gormigrate/v2"
|
||||
"gorm.io/datatypes"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var AddProviderCodeToDnsCredentials = &gormigrate.Migration{
|
||||
ID: "20251209000002",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if !tx.Migrator().HasColumn(&model.DnsCredential{}, "ProviderCode") {
|
||||
if err := tx.Migrator().AddColumn(&model.DnsCredential{}, "ProviderCode"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !tx.Migrator().HasIndex(&model.DnsCredential{}, "ProviderCode") {
|
||||
if err := tx.Migrator().CreateIndex(&model.DnsCredential{}, "ProviderCode"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Backfill provider_code from config.code (preferred) or provider/name fallback.
|
||||
type credentialRow struct {
|
||||
ID uint64 `gorm:"column:id"`
|
||||
Config datatypes.JSON `gorm:"column:config"`
|
||||
Provider string `gorm:"column:provider"`
|
||||
Name string `gorm:"column:name"`
|
||||
}
|
||||
|
||||
var rows []credentialRow
|
||||
if err := tx.Table("dns_credentials").Select("id, config, provider, name").Find(&rows).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, row := range rows {
|
||||
providerCode := normalizeProviderCode(row.Provider)
|
||||
|
||||
if len(row.Config) > 0 {
|
||||
var cfg dns.Config
|
||||
if err := json.Unmarshal(row.Config, &cfg); err == nil && strings.TrimSpace(cfg.Code) != "" {
|
||||
providerCode = normalizeProviderCode(cfg.Code)
|
||||
}
|
||||
}
|
||||
|
||||
if providerCode == "" {
|
||||
providerCode = normalizeProviderCode(row.Name)
|
||||
}
|
||||
|
||||
if err := tx.Table("dns_credentials").
|
||||
Where("id = ?", row.ID).
|
||||
Update("provider_code", providerCode).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func normalizeProviderCode(value string) string {
|
||||
return strings.TrimSpace(strings.ToLower(value))
|
||||
}
|
||||
@@ -10,6 +10,7 @@ var Migrations = []*gormigrate.Migration{
|
||||
UpdateCertDomains,
|
||||
RenameEnvGroupsToNamespaces,
|
||||
RenameEnvironmentsToNodes,
|
||||
AddProviderCodeToDnsCredentials,
|
||||
}
|
||||
|
||||
var BeforeAutoMigrate = []*gormigrate.Migration{
|
||||
|
||||
@@ -6,7 +6,8 @@ import (
|
||||
|
||||
type DnsCredential struct {
|
||||
Model
|
||||
Name string `json:"name"`
|
||||
Config *dns.Config `json:"config,omitempty" gorm:"serializer:json"`
|
||||
Provider string `json:"provider"`
|
||||
Name string `json:"name"`
|
||||
Config *dns.Config `json:"config,omitempty" gorm:"serializer:json"`
|
||||
Provider string `json:"provider"`
|
||||
ProviderCode string `json:"provider_code" gorm:"index"`
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ func newDnsCredential(db *gorm.DB, opts ...gen.DOOption) dnsCredential {
|
||||
_dnsCredential.Name = field.NewString(tableName, "name")
|
||||
_dnsCredential.Config = field.NewField(tableName, "config")
|
||||
_dnsCredential.Provider = field.NewString(tableName, "provider")
|
||||
_dnsCredential.ProviderCode = field.NewString(tableName, "provider_code")
|
||||
|
||||
_dnsCredential.fillFieldMap()
|
||||
|
||||
@@ -44,14 +45,15 @@ func newDnsCredential(db *gorm.DB, opts ...gen.DOOption) dnsCredential {
|
||||
type dnsCredential struct {
|
||||
dnsCredentialDo
|
||||
|
||||
ALL field.Asterisk
|
||||
ID field.Uint64
|
||||
CreatedAt field.Time
|
||||
UpdatedAt field.Time
|
||||
DeletedAt field.Field
|
||||
Name field.String
|
||||
Config field.Field
|
||||
Provider field.String
|
||||
ALL field.Asterisk
|
||||
ID field.Uint64
|
||||
CreatedAt field.Time
|
||||
UpdatedAt field.Time
|
||||
DeletedAt field.Field
|
||||
Name field.String
|
||||
Config field.Field
|
||||
Provider field.String
|
||||
ProviderCode field.String
|
||||
|
||||
fieldMap map[string]field.Expr
|
||||
}
|
||||
@@ -75,6 +77,7 @@ func (d *dnsCredential) updateTableName(table string) *dnsCredential {
|
||||
d.Name = field.NewString(table, "name")
|
||||
d.Config = field.NewField(table, "config")
|
||||
d.Provider = field.NewString(table, "provider")
|
||||
d.ProviderCode = field.NewString(table, "provider_code")
|
||||
|
||||
d.fillFieldMap()
|
||||
|
||||
@@ -91,7 +94,7 @@ func (d *dnsCredential) GetFieldByName(fieldName string) (field.OrderExpr, bool)
|
||||
}
|
||||
|
||||
func (d *dnsCredential) fillFieldMap() {
|
||||
d.fieldMap = make(map[string]field.Expr, 7)
|
||||
d.fieldMap = make(map[string]field.Expr, 8)
|
||||
d.fieldMap["id"] = d.ID
|
||||
d.fieldMap["created_at"] = d.CreatedAt
|
||||
d.fieldMap["updated_at"] = d.UpdatedAt
|
||||
@@ -99,6 +102,7 @@ func (d *dnsCredential) fillFieldMap() {
|
||||
d.fieldMap["name"] = d.Name
|
||||
d.fieldMap["config"] = d.Config
|
||||
d.fieldMap["provider"] = d.Provider
|
||||
d.fieldMap["provider_code"] = d.ProviderCode
|
||||
}
|
||||
|
||||
func (d dnsCredential) clone(db *gorm.DB) dnsCredential {
|
||||
|
||||
Reference in New Issue
Block a user