Sfoglia il codice sorgente

feat: add a option to select a acme user when obtaining a certificate.

Jacky 1 anno fa
parent
commit
f0dcd67004

+ 3 - 0
api/certificate/certificate.go

@@ -85,6 +85,7 @@ type certJson struct {
 	KeyType               certcrypto.KeyType `json:"key_type" binding:"omitempty,auto_cert_key_type"`
 	ChallengeMethod       string             `json:"challenge_method"`
 	DnsCredentialID       int                `json:"dns_credential_id"`
+	ACMEUserID            int                `json:"acme_user_id"`
 }
 
 func AddCert(c *gin.Context) {
@@ -101,6 +102,7 @@ func AddCert(c *gin.Context) {
 		KeyType:               json.KeyType,
 		ChallengeMethod:       json.ChallengeMethod,
 		DnsCredentialID:       json.DnsCredentialID,
+		ACMEUserID:            json.ACMEUserID,
 	}
 
 	err := certModel.Insert()
@@ -151,6 +153,7 @@ func ModifyCert(c *gin.Context) {
 		ChallengeMethod:       json.ChallengeMethod,
 		KeyType:               json.KeyType,
 		DnsCredentialID:       json.DnsCredentialID,
+		ACMEUserID:            json.ACMEUserID,
 	})
 
 	if err != nil {

+ 3 - 0
app/src/api/cert.ts

@@ -1,6 +1,7 @@
 import type { ModelBase } from '@/api/curd'
 import Curd from '@/api/curd'
 import type { DnsCredential } from '@/api/dns_credential'
+import type { AcmeUser } from '@/api/acme_user'
 
 export interface Cert extends ModelBase {
   name: string
@@ -14,6 +15,8 @@ export interface Cert extends ModelBase {
   challenge_method: string
   dns_credential_id: number
   dns_credential?: DnsCredential
+  acme_user_id: number
+  acme_user?: AcmeUser
   key_type: string
   log: string
   certificate_info: CertificateInfo

+ 86 - 0
app/src/views/certificate/ACMEUserSelector.vue

@@ -0,0 +1,86 @@
+<script setup lang="ts">
+import type { SelectProps } from 'ant-design-vue'
+import type { Ref } from 'vue'
+import type { AcmeUser } from '@/api/acme_user'
+import acme_user from '@/api/acme_user'
+import type { Cert } from '@/api/cert'
+
+const users = ref([]) as Ref<AcmeUser[]>
+
+// This data is provided by the Top StdCurd component,
+// is the object that you are trying to modify it
+// we externalize the dns_credential_id to the parent component,
+// this is used to tell the backend which dns_credential to use
+const data = inject('data') as Ref<Cert>
+
+const id = computed(() => {
+  return data.value.acme_user_id
+})
+
+const user_idx = ref()
+function init() {
+  users.value?.forEach((v: AcmeUser, k: number) => {
+    if (v.id === id.value)
+      user_idx.value = k
+  })
+}
+
+const current = computed(() => {
+  return users.value?.[user_idx.value]
+})
+
+const mounted = ref(false)
+
+watch(id, init)
+
+watch(current, () => {
+  data.value.acme_user_id = current.value.id
+  if (!mounted.value)
+    data.value.acme_user_id = 0
+})
+
+onMounted(async () => {
+  await acme_user.get_list().then(r => {
+    users.value = r.data
+  }).then(() => {
+    init()
+  })
+
+  // prevent the acme_user_id from being overwritten
+  mounted.value = true
+})
+
+const options = computed<SelectProps['options']>(() => {
+  const list: SelectProps['options'] = []
+
+  users.value.forEach((v, k: number) => {
+    list!.push({
+      value: k,
+      label: v.name,
+    })
+  })
+
+  return list
+})
+
+const filterOption = (input: string, option: { label: string }) => {
+  return option.label.toLowerCase().includes(input.toLowerCase())
+}
+</script>
+
+<template>
+  <AForm layout="vertical">
+    <AFormItem :label="$gettext('ACME User')">
+      <ASelect
+        v-model:value="user_idx"
+        show-search
+        :options="options"
+        :filter-option="filterOption"
+      />
+    </AFormItem>
+  </AForm>
+</template>
+
+<style lang="less" scoped>
+
+</style>

+ 1 - 0
app/src/views/certificate/Certificate.vue

@@ -137,6 +137,7 @@ const refTable = ref()
       ref="refTable"
       :api="cert"
       :columns="columns"
+      disabled-view
       @click-edit="id => $router.push(`/certificates/${id}`)"
     />
     <WildcardCertificate

+ 2 - 0
app/src/views/domain/cert/components/AutoCertStepOne.vue

@@ -3,6 +3,7 @@ import type { Ref } from 'vue'
 import type { DnsChallenge } from '@/api/auto_cert'
 import DNSChallenge from '@/views/domain/cert/components/DNSChallenge.vue'
 import type { Cert } from '@/api/cert'
+import ACMEUserSelector from '@/views/certificate/ACMEUserSelector.vue'
 
 defineProps<{
   hideNote?: boolean
@@ -114,6 +115,7 @@ onMounted(() => {
         </ASelect>
       </AFormItem>
     </AForm>
+    <ACMEUserSelector />
     <DNSChallenge v-if="data.challenge_method === 'dns01'" />
   </div>
 </template>

+ 2 - 0
model/cert.go

@@ -27,6 +27,8 @@ type Cert struct {
 	ChallengeMethod       string             `json:"challenge_method"`
 	DnsCredentialID       int                `json:"dns_credential_id"`
 	DnsCredential         *DnsCredential     `json:"dns_credential,omitempty"`
+	ACMEUserID            int                `json:"acme_user_id"`
+	ACMEUser              *AcmeUser          `json:"acme_user,omitempty"`
 	KeyType               certcrypto.KeyType `json:"key_type"`
 	Log                   string             `json:"log"`
 }

+ 5 - 1
query/acme_users.gen.go

@@ -36,6 +36,7 @@ func newAcmeUser(db *gorm.DB, opts ...gen.DOOption) acmeUser {
 	_acmeUser.Email = field.NewString(tableName, "email")
 	_acmeUser.CADir = field.NewString(tableName, "ca_dir")
 	_acmeUser.Registration = field.NewField(tableName, "registration")
+	_acmeUser.Key = field.NewField(tableName, "key")
 
 	_acmeUser.fillFieldMap()
 
@@ -54,6 +55,7 @@ type acmeUser struct {
 	Email        field.String
 	CADir        field.String
 	Registration field.Field
+	Key          field.Field
 
 	fieldMap map[string]field.Expr
 }
@@ -78,6 +80,7 @@ func (a *acmeUser) updateTableName(table string) *acmeUser {
 	a.Email = field.NewString(table, "email")
 	a.CADir = field.NewString(table, "ca_dir")
 	a.Registration = field.NewField(table, "registration")
+	a.Key = field.NewField(table, "key")
 
 	a.fillFieldMap()
 
@@ -94,7 +97,7 @@ func (a *acmeUser) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
 }
 
 func (a *acmeUser) fillFieldMap() {
-	a.fieldMap = make(map[string]field.Expr, 8)
+	a.fieldMap = make(map[string]field.Expr, 9)
 	a.fieldMap["id"] = a.ID
 	a.fieldMap["created_at"] = a.CreatedAt
 	a.fieldMap["updated_at"] = a.UpdatedAt
@@ -103,6 +106,7 @@ func (a *acmeUser) fillFieldMap() {
 	a.fieldMap["email"] = a.Email
 	a.fieldMap["ca_dir"] = a.CADir
 	a.fieldMap["registration"] = a.Registration
+	a.fieldMap["key"] = a.Key
 }
 
 func (a acmeUser) clone(db *gorm.DB) acmeUser {

+ 84 - 1
query/certs.gen.go

@@ -40,6 +40,7 @@ func newCert(db *gorm.DB, opts ...gen.DOOption) cert {
 	_cert.AutoCert = field.NewInt(tableName, "auto_cert")
 	_cert.ChallengeMethod = field.NewString(tableName, "challenge_method")
 	_cert.DnsCredentialID = field.NewInt(tableName, "dns_credential_id")
+	_cert.ACMEUserID = field.NewInt(tableName, "acme_user_id")
 	_cert.KeyType = field.NewString(tableName, "key_type")
 	_cert.Log = field.NewString(tableName, "log")
 	_cert.DnsCredential = certBelongsToDnsCredential{
@@ -48,6 +49,12 @@ func newCert(db *gorm.DB, opts ...gen.DOOption) cert {
 		RelationField: field.NewRelation("DnsCredential", "model.DnsCredential"),
 	}
 
+	_cert.ACMEUser = certBelongsToACMEUser{
+		db: db.Session(&gorm.Session{}),
+
+		RelationField: field.NewRelation("ACMEUser", "model.AcmeUser"),
+	}
+
 	_cert.fillFieldMap()
 
 	return _cert
@@ -69,10 +76,13 @@ type cert struct {
 	AutoCert              field.Int
 	ChallengeMethod       field.String
 	DnsCredentialID       field.Int
+	ACMEUserID            field.Int
 	KeyType               field.String
 	Log                   field.String
 	DnsCredential         certBelongsToDnsCredential
 
+	ACMEUser certBelongsToACMEUser
+
 	fieldMap map[string]field.Expr
 }
 
@@ -100,6 +110,7 @@ func (c *cert) updateTableName(table string) *cert {
 	c.AutoCert = field.NewInt(table, "auto_cert")
 	c.ChallengeMethod = field.NewString(table, "challenge_method")
 	c.DnsCredentialID = field.NewInt(table, "dns_credential_id")
+	c.ACMEUserID = field.NewInt(table, "acme_user_id")
 	c.KeyType = field.NewString(table, "key_type")
 	c.Log = field.NewString(table, "log")
 
@@ -118,7 +129,7 @@ func (c *cert) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
 }
 
 func (c *cert) fillFieldMap() {
-	c.fieldMap = make(map[string]field.Expr, 15)
+	c.fieldMap = make(map[string]field.Expr, 17)
 	c.fieldMap["id"] = c.ID
 	c.fieldMap["created_at"] = c.CreatedAt
 	c.fieldMap["updated_at"] = c.UpdatedAt
@@ -131,6 +142,7 @@ func (c *cert) fillFieldMap() {
 	c.fieldMap["auto_cert"] = c.AutoCert
 	c.fieldMap["challenge_method"] = c.ChallengeMethod
 	c.fieldMap["dns_credential_id"] = c.DnsCredentialID
+	c.fieldMap["acme_user_id"] = c.ACMEUserID
 	c.fieldMap["key_type"] = c.KeyType
 	c.fieldMap["log"] = c.Log
 
@@ -217,6 +229,77 @@ func (a certBelongsToDnsCredentialTx) Count() int64 {
 	return a.tx.Count()
 }
 
+type certBelongsToACMEUser struct {
+	db *gorm.DB
+
+	field.RelationField
+}
+
+func (a certBelongsToACMEUser) Where(conds ...field.Expr) *certBelongsToACMEUser {
+	if len(conds) == 0 {
+		return &a
+	}
+
+	exprs := make([]clause.Expression, 0, len(conds))
+	for _, cond := range conds {
+		exprs = append(exprs, cond.BeCond().(clause.Expression))
+	}
+	a.db = a.db.Clauses(clause.Where{Exprs: exprs})
+	return &a
+}
+
+func (a certBelongsToACMEUser) WithContext(ctx context.Context) *certBelongsToACMEUser {
+	a.db = a.db.WithContext(ctx)
+	return &a
+}
+
+func (a certBelongsToACMEUser) Session(session *gorm.Session) *certBelongsToACMEUser {
+	a.db = a.db.Session(session)
+	return &a
+}
+
+func (a certBelongsToACMEUser) Model(m *model.Cert) *certBelongsToACMEUserTx {
+	return &certBelongsToACMEUserTx{a.db.Model(m).Association(a.Name())}
+}
+
+type certBelongsToACMEUserTx struct{ tx *gorm.Association }
+
+func (a certBelongsToACMEUserTx) Find() (result *model.AcmeUser, err error) {
+	return result, a.tx.Find(&result)
+}
+
+func (a certBelongsToACMEUserTx) Append(values ...*model.AcmeUser) (err error) {
+	targetValues := make([]interface{}, len(values))
+	for i, v := range values {
+		targetValues[i] = v
+	}
+	return a.tx.Append(targetValues...)
+}
+
+func (a certBelongsToACMEUserTx) Replace(values ...*model.AcmeUser) (err error) {
+	targetValues := make([]interface{}, len(values))
+	for i, v := range values {
+		targetValues[i] = v
+	}
+	return a.tx.Replace(targetValues...)
+}
+
+func (a certBelongsToACMEUserTx) Delete(values ...*model.AcmeUser) (err error) {
+	targetValues := make([]interface{}, len(values))
+	for i, v := range values {
+		targetValues[i] = v
+	}
+	return a.tx.Delete(targetValues...)
+}
+
+func (a certBelongsToACMEUserTx) Clear() error {
+	return a.tx.Clear()
+}
+
+func (a certBelongsToACMEUserTx) Count() int64 {
+	return a.tx.Count()
+}
+
 type certDo struct{ gen.DO }
 
 // FirstByID Where("id=@id")