wip: dns credentials manager

This commit is contained in:
0xJacky 2023-04-13 11:07:12 +08:00
parent 0f259e4331
commit 418a53f4ad
No known key found for this signature in database
GPG key ID: B6E4A6E4A561BAF0
39 changed files with 758 additions and 151 deletions

View file

@ -0,0 +1,5 @@
import Curd from '@/api/curd'
const dns_credential = new Curd('/dns_credential')
export default dns_credential

View file

@ -22,11 +22,11 @@ let chartOptions = {
enabled: false enabled: false
}, },
animations: { animations: {
enabled: false, enabled: false
}, },
toolbar: { toolbar: {
show: false show: false
}, }
}, },
colors: ['#ff6385', '#36a3eb'], colors: ['#ff6385', '#36a3eb'],
fill: { fill: {
@ -41,7 +41,7 @@ let chartOptions = {
}, },
stroke: { stroke: {
curve: 'smooth', curve: 'smooth',
width: 0, width: 0
}, },
xaxis: { xaxis: {
type: 'datetime', type: 'datetime',
@ -75,7 +75,7 @@ let chartOptions = {
}, },
onItemHover: { onItemHover: {
highlightDataSeries: false highlightDataSeries: false
}, }
} }
} }
@ -114,7 +114,7 @@ const callback = () => {
}, },
onItemHover: { onItemHover: {
highlightDataSeries: false highlightDataSeries: false
}, }
} }
} }
} }

View file

@ -7,11 +7,10 @@ import {urlJoin} from '@/lib/helper'
import {marked} from 'marked' import {marked} from 'marked'
import hljs from 'highlight.js' import hljs from 'highlight.js'
import 'highlight.js/styles/vs2015.css' import 'highlight.js/styles/vs2015.css'
import {SendOutlined} from '@ant-design/icons-vue' import Icon, {SendOutlined} from '@ant-design/icons-vue'
import Template from '@/views/template/Template.vue' import Template from '@/views/template/Template.vue'
import openai from '@/api/openai' import openai from '@/api/openai'
import ChatGPT_logo from '@/assets/svg/ChatGPT_logo.svg' import ChatGPT_logo from '@/assets/svg/ChatGPT_logo.svg'
import Icon from '@ant-design/icons-vue'
const {$gettext} = useGettext() const {$gettext} = useGettext()

View file

@ -1,7 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import gettext from '@/gettext' import gettext from '@/gettext'
const {$gettext} = gettext
import ngx from '@/api/ngx' import ngx from '@/api/ngx'
import logLevel from '@/views/config/constants' import logLevel from '@/views/config/constants'
import {message} from 'ant-design-vue' import {message} from 'ant-design-vue'
@ -9,6 +7,8 @@ import {ReloadOutlined} from '@ant-design/icons-vue'
import Template from '@/views/template/Template.vue' import Template from '@/views/template/Template.vue'
import {ref, watch} from 'vue' import {ref, watch} from 'vue'
const {$gettext} = gettext
function get_status() { function get_status() {
ngx.status().then(r => { ngx.status().then(r => {
if (r?.running === true) { if (r?.running === true) {

View file

@ -1,12 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import {reactive, ref} from 'vue' import {reactive, ref} from 'vue'
import gettext from '@/gettext' import gettext from '@/gettext'
const {$gettext} = gettext
import StdDataEntry from '@/components/StdDataEntry' import StdDataEntry from '@/components/StdDataEntry'
import {message} from 'ant-design-vue' import {message} from 'ant-design-vue'
const {$gettext} = gettext
const emit = defineEmits(['onSave']) const emit = defineEmits(['onSave'])
const props = defineProps(['api', 'beforeSave']) const props = defineProps(['api', 'beforeSave'])
@ -49,23 +48,23 @@ async function ok() {
<template> <template>
<a-modal <a-modal
class="std-curd-edit-modal" class="std-curd-edit-modal"
:mask="false" :mask="false"
:title="$gettext('Batch Modify')" :title="$gettext('Batch Modify')"
v-model:visible="visible" v-model:visible="visible"
:cancel-text="$gettext('Cancel')" :cancel-text="$gettext('Cancel')"
:ok-text="$gettext('OK')" :ok-text="$gettext('OK')"
@ok="ok" @ok="ok"
:confirm-loading="loading" :confirm-loading="loading"
:width="600" :width="600"
destroyOnClose destroyOnClose
> >
<std-data-entry <std-data-entry
ref="std_data_entry" ref="std_data_entry"
:data-list="batchColumns" :data-list="batchColumns"
v-model:data-source="data" v-model:data-source="data"
:error="error" :error="error"
/> />
<slot name="extra"/> <slot name="extra"/>
@ -74,4 +73,4 @@ async function ok() {
<style scoped> <style scoped>
</style> </style>

View file

@ -4,7 +4,7 @@ import StdTable from './StdTable.vue'
import StdDataEntry from '@/components/StdDataEntry' import StdDataEntry from '@/components/StdDataEntry'
import {reactive, ref} from 'vue' import {provide, reactive, ref} from 'vue'
import {message} from 'ant-design-vue' import {message} from 'ant-design-vue'
const {$gettext} = gettext const {$gettext} = gettext
@ -62,6 +62,7 @@ const props = defineProps({
const visible = ref(false) const visible = ref(false)
const update = ref(0) const update = ref(0)
const data: any = reactive({id: null}) const data: any = reactive({id: null})
provide('data', data)
const error: any = reactive({}) const error: any = reactive({})
const selected = ref([]) const selected = ref([])
@ -146,12 +147,12 @@ const selectedRowKeys = ref([])
</template> </template>
<std-table <std-table
ref="table" ref="table"
v-model:selected-row-keys="selectedRowKeys" v-model:selected-row-keys="selectedRowKeys"
v-bind="props" v-bind="props"
@clickEdit="edit" @clickEdit="edit"
@selected="onSelect" @selected="onSelect"
:key="update" :key="update"
> >
<template v-slot:actions="slotProps"> <template v-slot:actions="slotProps">
<slot name="actions" :actions="slotProps.record"/> <slot name="actions" :actions="slotProps.record"/>
@ -160,26 +161,26 @@ const selectedRowKeys = ref([])
</a-card> </a-card>
<a-modal <a-modal
class="std-curd-edit-modal" class="std-curd-edit-modal"
:mask="false" :mask="false"
:title="edit_text?edit_text:(data.id ? $gettext('Modify') : $gettext('Add'))" :title="edit_text?edit_text:(data.id ? $gettext('Modify') : $gettext('Add'))"
:visible="visible" :visible="visible"
:cancel-text="$gettext('Cancel')" :cancel-text="$gettext('Cancel')"
:ok-text="$gettext('OK')" :ok-text="$gettext('OK')"
@cancel="cancel" @cancel="cancel"
@ok="ok" @ok="ok"
:width="modalWidth" :width="modalWidth"
destroyOnClose destroyOnClose
> >
<div class="before-edit" v-if="$slots.beforeEdit"> <div class="before-edit" v-if="$slots.beforeEdit">
<slot name="beforeEdit" :data="data"/> <slot name="beforeEdit" :data="data"/>
</div> </div>
<std-data-entry <std-data-entry
ref="std_data_entry" ref="std_data_entry"
:data-list="editableColumns()" :data-list="editableColumns()"
v-model:data-source="data" v-model:data-source="data"
:error="error" :error="error"
/> />
<slot name="edit" :data="data"/> <slot name="edit" :data="data"/>

View file

@ -24,11 +24,11 @@ const pageSize = computed({
<template> <template>
<div class="pagination-container" v-if="pagination.total>pagination.per_page"> <div class="pagination-container" v-if="pagination.total>pagination.per_page">
<a-pagination <a-pagination
:current="pagination.current_page" :current="pagination.current_page"
v-model:pageSize="pageSize" v-model:pageSize="pageSize"
:size="size" :size="size"
:total="pagination.total" :total="pagination.total"
@change="change" @change="change"
/> />
</div> </div>
</template> </template>

View file

@ -34,9 +34,9 @@ function handle_generate() {
<template> <template>
<a-input-group compact> <a-input-group compact>
<a-input-password <a-input-password
v-if="!visibility" v-if="!visibility"
:class="{compact: generate}" :class="{compact: generate}"
v-model:value="M_value" :placeholoder="placeholder"/> v-model:value="M_value" :placeholoder="placeholder"/>
<a-input v-else :class="{compact: generate}" v-model:value="M_value" :placeholoder="placeholder"/> <a-input v-else :class="{compact: generate}" v-model:value="M_value" :placeholoder="placeholder"/>
<a-button @click="handle_generate" v-if="generate" type="primary"> <a-button @click="handle_generate" v-if="generate" type="primary">
<translate>Generate</translate> <translate>Generate</translate>
@ -48,4 +48,4 @@ function handle_generate() {
.compact { .compact {
width: calc(100% - 91px) width: calc(100% - 91px)
} }
</style> </style>

View file

@ -1,6 +1,6 @@
import StdDataEntry from './StdDataEntry.js' import StdDataEntry from './StdDataEntry.js'
import {h} from 'vue' import {h} from 'vue'
import {Input, Textarea, InputPassword, InputNumber} from 'ant-design-vue' import {Input, InputNumber, Textarea} from 'ant-design-vue'
import StdSelector from './components/StdSelector.vue' import StdSelector from './components/StdSelector.vue'
import StdSelect from './components/StdSelect.vue' import StdSelect from './components/StdSelect.vue'
import StdPassword from './components/StdPassword.vue' import StdPassword from './components/StdPassword.vue'

View file

@ -1,4 +1,4 @@
import {createRouter, createWebHashHistory, createWebHistory} from 'vue-router' import {createRouter, createWebHashHistory} from 'vue-router'
import gettext from '../gettext' import gettext from '../gettext'
import {useUserStore} from '@/pinia' import {useUserStore} from '@/pinia'
@ -6,12 +6,12 @@ import {
CloudOutlined, CloudOutlined,
CodeOutlined, CodeOutlined,
FileOutlined, FileOutlined,
FileTextOutlined,
HomeOutlined, HomeOutlined,
InfoCircleOutlined, InfoCircleOutlined,
UserOutlined, SafetyCertificateOutlined,
FileTextOutlined,
SettingOutlined, SettingOutlined,
SafetyCertificateOutlined UserOutlined
} from '@ant-design/icons-vue' } from '@ant-design/icons-vue'
import NProgress from 'nprogress' import NProgress from 'nprogress'
import 'nprogress/nprogress.css' import 'nprogress/nprogress.css'
@ -87,10 +87,22 @@ export const routes = [
{ {
path: 'cert', path: 'cert',
name: () => $gettext('Certification'), name: () => $gettext('Certification'),
component: () => import('@/views/cert/Cert.vue'), component: () => import('@/layouts/BaseRouterView.vue'),
meta: { meta: {
icon: SafetyCertificateOutlined icon: SafetyCertificateOutlined
} },
children: [
{
path: 'list',
name: () => $gettext('Certification List'),
component: () => import('@/views/cert/Cert.vue')
},
{
path: 'dns_credential',
name: () => $gettext('DNS Credentials'),
component: () => import('@/views/cert/DNSCredential.vue')
}
]
}, },
{ {
path: 'terminal', path: 'terminal',

View file

@ -0,0 +1,62 @@
<script setup lang="tsx">
import {useGettext} from 'vue3-gettext'
import {datetime} from '@/components/StdDataDisplay/StdTableTransformer'
import dns_credential from '@/api/dns_credential'
import StdCurd from '@/components/StdDataDisplay/StdCurd.vue'
import Template from '@/views/template/Template.vue'
import DNSChallenge from '@/views/domain/cert/components/DNSChallenge.vue'
import {input} from '@/components/StdDataEntry'
const {$gettext, interpolate} = useGettext()
const columns = [{
title: () => $gettext('Name'),
dataIndex: 'name',
sorter: true,
pithy: true,
edit: {
type: input
}
}, {
title: () => $gettext('Provider'),
dataIndex: ['config', 'name'],
sorter: true,
pithy: true
}, {
title: () => $gettext('Updated at'),
dataIndex: 'updated_at',
customRender: datetime,
sorter: true,
pithy: true
}, {
title: () => $gettext('Action'),
dataIndex: 'action'
}]
</script>
<template>
<std-curd :title="$gettext('DNS Credentials')" :api="dns_credential" :columns="columns"
row-key="name"
>
<template #beforeEdit>
<a-alert type="info" show-icon :message="$gettext('Note')">
<template #description>
<p v-translate>
Please fill in the API authentication credentials provided by your DNS provider.
We will add one or more TXT records to the DNS records of your domain for ownership
verification.
Once the verification is complete, the records will be removed.
Please note that the time configurations below are all in seconds.
</p>
</template>
</a-alert>
</template>
<template #edit="{data}">
<d-n-s-challenge/>
</template>
</std-curd>
</template>
<style lang="less" scoped>
</style>

View file

@ -2,19 +2,17 @@
import StdTable from '@/components/StdDataDisplay/StdTable.vue' import StdTable from '@/components/StdDataDisplay/StdTable.vue'
import gettext from '@/gettext' import gettext from '@/gettext'
import config from '@/api/config' import config from '@/api/config'
import {customRender, datetime} from '@/components/StdDataDisplay/StdTableTransformer' import {computed, ref, watch} from 'vue'
import {computed, h, nextTick, ref, watch} from 'vue'
const {$gettext} = gettext
const api = config
import configColumns from '@/views/config/config' import configColumns from '@/views/config/config'
import {useRoute} from 'vue-router' import {useRoute} from 'vue-router'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue' import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import router from '@/routes' import router from '@/routes'
import InspectConfig from '@/views/config/InspectConfig.vue' import InspectConfig from '@/views/config/InspectConfig.vue'
const {$gettext} = gettext
const api = config
const table = ref(null) const table = ref(null)
const route = useRoute() const route = useRoute()

View file

@ -1,10 +1,9 @@
import {customRender, datetime} from '@/components/StdDataDisplay/StdTableTransformer' import {customRender, datetime} from '@/components/StdDataDisplay/StdTableTransformer'
import gettext from '@/gettext' import gettext from '@/gettext'
import {h} from 'vue'
const {$gettext} = gettext const {$gettext} = gettext
import {h} from 'vue'
const configColumns = [{ const configColumns = [{
title: () => $gettext('Name'), title: () => $gettext('Name'),
dataIndex: 'name', dataIndex: 'name',

View file

@ -8,7 +8,6 @@ import ngx from '@/api/ngx'
import {computed, reactive, ref} from 'vue' import {computed, reactive, ref} from 'vue'
import {message} from 'ant-design-vue' import {message} from 'ant-design-vue'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'
import template from '@/api/template'
const {$gettext, interpolate} = useGettext() const {$gettext, interpolate} = useGettext()

View file

@ -3,15 +3,14 @@ import StdTable from '@/components/StdDataDisplay/StdTable.vue'
import {customRender, datetime} from '@/components/StdDataDisplay/StdTableTransformer' import {customRender, datetime} from '@/components/StdDataDisplay/StdTableTransformer'
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
const {$gettext, interpolate} = useGettext()
import domain from '@/api/domain' import domain from '@/api/domain'
import {Badge, message} from 'ant-design-vue' import {Badge, message} from 'ant-design-vue'
import {h, ref} from 'vue' import {h, ref} from 'vue'
import {input} from '@/components/StdDataEntry' import {input} from '@/components/StdDataEntry'
import SiteDuplicate from '@/views/domain/SiteDuplicate.vue' import SiteDuplicate from '@/views/domain/SiteDuplicate.vue'
const {$gettext, interpolate} = useGettext()
const columns = [{ const columns = [{
title: () => $gettext('Name'), title: () => $gettext('Name'),
dataIndex: 'name', dataIndex: 'name',

View file

@ -1,10 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import CertInfo from '@/views/domain/cert/CertInfo.vue' import CertInfo from '@/views/domain/cert/CertInfo.vue'
import IssueCert from '@/views/domain/cert/IssueCert.vue' import IssueCert from '@/views/domain/cert/IssueCert.vue'
import {computed, ref} from 'vue' import {computed} from 'vue'
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
import ChangeCert from '@/views/domain/cert/ChangeCert.vue' import ChangeCert from '@/views/domain/cert/ChangeCert.vue'
import DNSChallenge from '@/views/domain/cert/components/DNSChallenge.vue'
const {$gettext} = useGettext() const {$gettext} = useGettext()

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import {CloseCircleOutlined, CheckCircleOutlined} from '@ant-design/icons-vue' import {CheckCircleOutlined, CloseCircleOutlined} from '@ant-design/icons-vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
const props = defineProps(['cert']) const props = defineProps(['cert'])

View file

@ -3,7 +3,7 @@ import {useGettext} from 'vue3-gettext'
import {h, ref} from 'vue' import {h, ref} from 'vue'
import StdTable from '@/components/StdDataDisplay/StdTable.vue' import StdTable from '@/components/StdDataDisplay/StdTable.vue'
import cert from '@/api/cert' import cert from '@/api/cert'
import {customRender, datetime} from '@/components/StdDataDisplay/StdTableTransformer' import {customRender} from '@/components/StdDataDisplay/StdTableTransformer'
import {input} from '@/components/StdDataEntry' import {input} from '@/components/StdDataEntry'
import {Badge} from 'ant-design-vue' import {Badge} from 'ant-design-vue'

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
import {computed, inject, nextTick, provide, ref, watch} from 'vue' import {computed, nextTick, provide, ref, watch} from 'vue'
import Template from '@/views/template/Template.vue' import Template from '@/views/template/Template.vue'
import ObtainCert from '@/views/domain/cert/components/ObtainCert.vue' import ObtainCert from '@/views/domain/cert/components/ObtainCert.vue'

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import {inject, ref, Ref} from 'vue' import {inject, Ref} from 'vue'
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
import DNSChallenge from '@/views/domain/cert/components/DNSChallenge.vue' import DNSChallenge from '@/views/domain/cert/components/DNSChallenge.vue'

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import {computed, inject, Ref, ref, watch} from 'vue' import {computed, inject, ref, watch} from 'vue'
import auto_cert from '@/api/auto_cert' import auto_cert from '@/api/auto_cert'
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
import {SelectProps} from 'ant-design-vue' import {SelectProps} from 'ant-design-vue'
@ -9,8 +9,22 @@ const providers: any = ref([])
const data: any = inject('data')! const data: any = inject('data')!
const code = computed(() => {
return data.code
})
function init() {
providers.value?.forEach((v: any, k: number) => {
if (v.code === code.value) {
provider_idx.value = k
}
})
}
auto_cert.get_dns_providers().then(r => { auto_cert.get_dns_providers().then(r => {
providers.value = r providers.value = r
}).then(() => {
init()
}) })
const provider_idx = ref() const provider_idx = ref()
@ -19,8 +33,12 @@ const current: any = computed(() => {
return providers.value?.[provider_idx.value] return providers.value?.[provider_idx.value]
}) })
watch(code, init)
watch(current, () => { watch(current, () => {
data.code = current.value.code data.code = current.value.code
data.provider = current.value.name
auto_cert.get_dns_provider(current.value.code).then(r => { auto_cert.get_dns_provider(current.value.code).then(r => {
Object.assign(current.value, r) Object.assign(current.value, r)
}) })

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
import {computed, inject, nextTick, provide, reactive, Ref, ref, watch} from 'vue' import {computed, inject, nextTick, provide, reactive, Ref, ref} from 'vue'
import websocket from '@/lib/websocket' import websocket from '@/lib/websocket'
import {message, Modal} from 'ant-design-vue' import {message, Modal} from 'ant-design-vue'
import template from '@/api/template' import template from '@/api/template'

View file

@ -3,7 +3,6 @@ import CodeEditor from '@/components/CodeEditor'
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
import {reactive, ref} from 'vue' import {reactive, ref} from 'vue'
import {DeleteOutlined, HolderOutlined} from '@ant-design/icons-vue' import {DeleteOutlined, HolderOutlined} from '@ant-design/icons-vue'
import draggable from 'vuedraggable'
const {$gettext} = useGettext() const {$gettext} = useGettext()

View file

@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import {FileTextOutlined, FileExclamationOutlined} from '@ant-design/icons-vue' import {FileExclamationOutlined, FileTextOutlined} from '@ant-design/icons-vue'
import {computed, ref} from 'vue' import {computed, ref} from 'vue'
import {useRouter} from 'vue-router' import {useRouter} from 'vue-router'

View file

@ -8,10 +8,9 @@ import Cert from '@/views/domain/cert/Cert.vue'
import LogEntry from '@/views/domain/ngx_conf/LogEntry.vue' import LogEntry from '@/views/domain/ngx_conf/LogEntry.vue'
import ConfigTemplate from '@/views/domain/ngx_conf/config_template/ConfigTemplate.vue' import ConfigTemplate from '@/views/domain/ngx_conf/config_template/ConfigTemplate.vue'
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue' import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
import {PlusOutlined} from '@ant-design/icons-vue' import {MoreOutlined, PlusOutlined} from '@ant-design/icons-vue'
import {Modal} from 'ant-design-vue' import {Modal} from 'ant-design-vue'
import template from '@/api/template' import template from '@/api/template'
import {MoreOutlined} from '@ant-design/icons-vue'
const {$gettext} = useGettext() const {$gettext} = useGettext()

View file

@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
import template from '@/api/template' import template from '@/api/template'
import {computed, provide, ref, watch} from 'vue' import {computed, provide, ref} from 'vue'
import {storeToRefs} from 'pinia' import {storeToRefs} from 'pinia'
import {useSettingsStore} from '@/pinia' import {useSettingsStore} from '@/pinia'
import Template from '@/views/template/Template.vue' import Template from '@/views/template/Template.vue'
@ -9,8 +9,6 @@ import DirectiveEditor from '@/views/domain/ngx_conf/directive/DirectiveEditor.v
import LocationEditor from '@/views/domain/ngx_conf/LocationEditor.vue' import LocationEditor from '@/views/domain/ngx_conf/LocationEditor.vue'
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue' import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
import TemplateForm from '@/views/domain/ngx_conf/config_template/TemplateForm.vue' import TemplateForm from '@/views/domain/ngx_conf/config_template/TemplateForm.vue'
import * as wasi from 'wasi'
import _ from 'lodash'
const {$gettext} = useGettext() const {$gettext} = useGettext()
const {language} = storeToRefs(useSettingsStore()) const {language} = storeToRefs(useSettingsStore())

View file

@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import {If} from '@/views/domain/ngx_conf'
import CodeEditor from '@/components/CodeEditor' import CodeEditor from '@/components/CodeEditor'
import {reactive, ref} from 'vue' import {reactive, ref} from 'vue'
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'

View file

@ -2,7 +2,6 @@
import DirectiveAdd from '@/views/domain/ngx_conf/directive/DirectiveAdd' import DirectiveAdd from '@/views/domain/ngx_conf/directive/DirectiveAdd'
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
import {reactive, ref} from 'vue' import {reactive, ref} from 'vue'
import draggable from 'vuedraggable'
import DirectiveEditorItem from '@/views/domain/ngx_conf/directive/DirectiveEditorItem.vue' import DirectiveEditorItem from '@/views/domain/ngx_conf/directive/DirectiveEditorItem.vue'
const {$gettext} = useGettext() const {$gettext} = useGettext()

View file

@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import CodeEditor from '@/components/CodeEditor' import CodeEditor from '@/components/CodeEditor'
import {DeleteOutlined, HolderOutlined} from '@ant-design/icons-vue' import {DeleteOutlined, HolderOutlined} from '@ant-design/icons-vue'
import {If} from '@/views/domain/ngx_conf'
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
import {onMounted, ref, watch} from 'vue' import {onMounted, ref, watch} from 'vue'

View file

@ -5,7 +5,7 @@ import {reactive, ref} from 'vue'
import gettext from '@/gettext' import gettext from '@/gettext'
import install from '@/api/install' import install from '@/api/install'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
import {MailOutlined, UserOutlined, LockOutlined, DatabaseOutlined} from '@ant-design/icons-vue' import {DatabaseOutlined, LockOutlined, MailOutlined, UserOutlined} from '@ant-design/icons-vue'
const {$gettext, interpolate} = gettext const {$gettext, interpolate} = gettext
@ -33,19 +33,19 @@ const rulesRef = reactive({
{ {
required: true, required: true,
type: 'email', type: 'email',
message: () => $gettext('Please input your E-mail!'), message: () => $gettext('Please input your E-mail!')
} }
], ],
username: [ username: [
{ {
required: true, required: true,
message: () => $gettext('Please input your username!'), message: () => $gettext('Please input your username!')
} }
], ],
password: [ password: [
{ {
required: true, required: true,
message: () => $gettext('Please input your password!'), message: () => $gettext('Please input your password!')
} }
], ],
database: [ database: [
@ -53,9 +53,9 @@ const rulesRef = reactive({
message: () => interpolate( message: () => interpolate(
$gettext('The filename cannot contain the following characters: %{c}'), $gettext('The filename cannot contain the following characters: %{c}'),
{c: '& &quot; ? < > # {} % ~ / \\'} {c: '& &quot; ? < > # {} % ~ / \\'}
), )
} }
], ]
}) })
const {validate, validateInfos} = Form.useForm(modelRef, rulesRef) const {validate, validateInfos} = Form.useForm(modelRef, rulesRef)

View file

@ -1,8 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import {useUserStore} from '@/pinia' import {useUserStore} from '@/pinia'
const thisYear = new Date().getFullYear()
import {LockOutlined, UserOutlined} from '@ant-design/icons-vue' import {LockOutlined, UserOutlined} from '@ant-design/icons-vue'
import {reactive, ref, watch} from 'vue' import {reactive, ref, watch} from 'vue'
import {useRoute, useRouter} from 'vue-router' import {useRoute, useRouter} from 'vue-router'
@ -12,6 +9,8 @@ import auth from '@/api/auth'
import install from '@/api/install' import install from '@/api/install'
import SetLanguage from '@/components/SetLanguage/SetLanguage.vue' import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'
const thisYear = new Date().getFullYear()
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import {useGettext} from 'vue3-gettext' import {useGettext} from 'vue3-gettext'
import {provide, reactive, ref} from 'vue' import {provide, ref} from 'vue'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue' import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
import {useSettingsStore} from '@/pinia' import {useSettingsStore} from '@/pinia'
import {dark_mode} from '@/lib/theme' import {dark_mode} from '@/lib/theme'

View file

@ -0,0 +1,122 @@
package api
import (
"github.com/0xJacky/Nginx-UI/server/model"
"github.com/0xJacky/Nginx-UI/server/pkg/cert/dns"
"github.com/0xJacky/Nginx-UI/server/query"
"github.com/gin-gonic/gin"
"github.com/spf13/cast"
"net/http"
)
func GetDnsCredential(c *gin.Context) {
id := cast.ToInt(c.Param("id"))
d := query.DnsCredential
dnsCredential, err := d.FirstByID(id)
if err != nil {
ErrHandler(c, err)
return
}
type apiDnsCredential struct {
model.Model
Name string `json:"name"`
dns.Config
}
c.JSON(http.StatusOK, apiDnsCredential{
Model: dnsCredential.Model,
Name: dnsCredential.Name,
Config: *dnsCredential.Config,
})
}
func GetDnsCredentialList(c *gin.Context) {
d := query.DnsCredential
data, err := d.Find()
if err != nil {
ErrHandler(c, err)
return
}
c.JSON(http.StatusOK, gin.H{
"data": data,
})
}
type DnsCredentialManageJson struct {
Name string `json:"name" binding:"required"`
Provider string `json:"provider"`
dns.Config
}
func AddDnsCredential(c *gin.Context) {
var json DnsCredentialManageJson
if !BindAndValid(c, &json) {
return
}
json.Config.Name = json.Provider
dnsCredential := model.DnsCredential{
Name: json.Name,
Config: &json.Config,
Provider: json.Provider,
}
d := query.DnsCredential
err := d.Create(&dnsCredential)
if err != nil {
ErrHandler(c, err)
return
}
c.JSON(http.StatusOK, dnsCredential)
}
func EditDnsCredential(c *gin.Context) {
id := cast.ToInt(c.Param("id"))
var json DnsCredentialManageJson
if !BindAndValid(c, &json) {
return
}
d := query.DnsCredential
dnsCredential, err := d.FirstByID(id)
if err != nil {
ErrHandler(c, err)
return
}
json.Config.Name = json.Provider
_, err = d.Where(d.ID.Eq(dnsCredential.ID)).Updates(&model.DnsCredential{
Name: json.Name,
Config: &json.Config,
Provider: json.Provider,
})
if err != nil {
ErrHandler(c, err)
return
}
GetDnsCredential(c)
}
func DeleteDnsCredential(c *gin.Context) {
id := cast.ToInt(c.Param("id"))
d := query.DnsCredential
dnsCredential, err := d.FirstByID(id)
if err != nil {
ErrHandler(c, err)
return
}
err = d.DeleteByID(dnsCredential.ID)
if err != nil {
ErrHandler(c, err)
return
}
c.JSON(http.StatusNoContent, nil)
}

View file

@ -0,0 +1,12 @@
package model
import (
"github.com/0xJacky/Nginx-UI/server/pkg/cert/dns"
)
type DnsCredential struct {
Model
Name string `json:"name"`
Config *dns.Config `json:"config,omitempty" gorm:"serializer:json"`
Provider string `json:"provider"`
}

View file

@ -31,6 +31,7 @@ func GenerateAllModel() []any {
Cert{}, Cert{},
ChatGPTLog{}, ChatGPTLog{},
Site{}, Site{},
DnsCredential{},
} }
} }

View file

@ -0,0 +1,374 @@
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
// Code generated by gorm.io/gen. DO NOT EDIT.
package query
import (
"context"
"strings"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/schema"
"gorm.io/gen"
"gorm.io/gen/field"
"gorm.io/plugin/dbresolver"
"github.com/0xJacky/Nginx-UI/server/model"
)
func newDnsCredential(db *gorm.DB, opts ...gen.DOOption) dnsCredential {
_dnsCredential := dnsCredential{}
_dnsCredential.dnsCredentialDo.UseDB(db, opts...)
_dnsCredential.dnsCredentialDo.UseModel(&model.DnsCredential{})
tableName := _dnsCredential.dnsCredentialDo.TableName()
_dnsCredential.ALL = field.NewAsterisk(tableName)
_dnsCredential.ID = field.NewInt(tableName, "id")
_dnsCredential.CreatedAt = field.NewTime(tableName, "created_at")
_dnsCredential.UpdatedAt = field.NewTime(tableName, "updated_at")
_dnsCredential.DeletedAt = field.NewTime(tableName, "deleted_at")
_dnsCredential.Name = field.NewString(tableName, "name")
_dnsCredential.Config = field.NewField(tableName, "config")
_dnsCredential.fillFieldMap()
return _dnsCredential
}
type dnsCredential struct {
dnsCredentialDo
ALL field.Asterisk
ID field.Int
CreatedAt field.Time
UpdatedAt field.Time
DeletedAt field.Time
Name field.String
Config field.Field
fieldMap map[string]field.Expr
}
func (d dnsCredential) Table(newTableName string) *dnsCredential {
d.dnsCredentialDo.UseTable(newTableName)
return d.updateTableName(newTableName)
}
func (d dnsCredential) As(alias string) *dnsCredential {
d.dnsCredentialDo.DO = *(d.dnsCredentialDo.As(alias).(*gen.DO))
return d.updateTableName(alias)
}
func (d *dnsCredential) updateTableName(table string) *dnsCredential {
d.ALL = field.NewAsterisk(table)
d.ID = field.NewInt(table, "id")
d.CreatedAt = field.NewTime(table, "created_at")
d.UpdatedAt = field.NewTime(table, "updated_at")
d.DeletedAt = field.NewTime(table, "deleted_at")
d.Name = field.NewString(table, "name")
d.Config = field.NewField(table, "config")
d.fillFieldMap()
return d
}
func (d *dnsCredential) GetFieldByName(fieldName string) (field.OrderExpr, bool) {
_f, ok := d.fieldMap[fieldName]
if !ok || _f == nil {
return nil, false
}
_oe, ok := _f.(field.OrderExpr)
return _oe, ok
}
func (d *dnsCredential) fillFieldMap() {
d.fieldMap = make(map[string]field.Expr, 6)
d.fieldMap["id"] = d.ID
d.fieldMap["created_at"] = d.CreatedAt
d.fieldMap["updated_at"] = d.UpdatedAt
d.fieldMap["deleted_at"] = d.DeletedAt
d.fieldMap["name"] = d.Name
d.fieldMap["config"] = d.Config
}
func (d dnsCredential) clone(db *gorm.DB) dnsCredential {
d.dnsCredentialDo.ReplaceConnPool(db.Statement.ConnPool)
return d
}
func (d dnsCredential) replaceDB(db *gorm.DB) dnsCredential {
d.dnsCredentialDo.ReplaceDB(db)
return d
}
type dnsCredentialDo struct{ gen.DO }
// FirstByID Where("id=@id")
func (d dnsCredentialDo) FirstByID(id int) (result *model.DnsCredential, err error) {
var params []interface{}
var generateSQL strings.Builder
params = append(params, id)
generateSQL.WriteString("id=? ")
var executeSQL *gorm.DB
executeSQL = d.UnderlyingDB().Where(generateSQL.String(), params...).Take(&result) // ignore_security_alert
err = executeSQL.Error
return
}
// DeleteByID update @@table set deleted_at=NOW() where id=@id
func (d dnsCredentialDo) DeleteByID(id int) (err error) {
var params []interface{}
var generateSQL strings.Builder
params = append(params, id)
generateSQL.WriteString("update dns_credentials set deleted_at=NOW() where id=? ")
var executeSQL *gorm.DB
executeSQL = d.UnderlyingDB().Exec(generateSQL.String(), params...) // ignore_security_alert
err = executeSQL.Error
return
}
func (d dnsCredentialDo) Debug() *dnsCredentialDo {
return d.withDO(d.DO.Debug())
}
func (d dnsCredentialDo) WithContext(ctx context.Context) *dnsCredentialDo {
return d.withDO(d.DO.WithContext(ctx))
}
func (d dnsCredentialDo) ReadDB() *dnsCredentialDo {
return d.Clauses(dbresolver.Read)
}
func (d dnsCredentialDo) WriteDB() *dnsCredentialDo {
return d.Clauses(dbresolver.Write)
}
func (d dnsCredentialDo) Session(config *gorm.Session) *dnsCredentialDo {
return d.withDO(d.DO.Session(config))
}
func (d dnsCredentialDo) Clauses(conds ...clause.Expression) *dnsCredentialDo {
return d.withDO(d.DO.Clauses(conds...))
}
func (d dnsCredentialDo) Returning(value interface{}, columns ...string) *dnsCredentialDo {
return d.withDO(d.DO.Returning(value, columns...))
}
func (d dnsCredentialDo) Not(conds ...gen.Condition) *dnsCredentialDo {
return d.withDO(d.DO.Not(conds...))
}
func (d dnsCredentialDo) Or(conds ...gen.Condition) *dnsCredentialDo {
return d.withDO(d.DO.Or(conds...))
}
func (d dnsCredentialDo) Select(conds ...field.Expr) *dnsCredentialDo {
return d.withDO(d.DO.Select(conds...))
}
func (d dnsCredentialDo) Where(conds ...gen.Condition) *dnsCredentialDo {
return d.withDO(d.DO.Where(conds...))
}
func (d dnsCredentialDo) Exists(subquery interface{ UnderlyingDB() *gorm.DB }) *dnsCredentialDo {
return d.Where(field.CompareSubQuery(field.ExistsOp, nil, subquery.UnderlyingDB()))
}
func (d dnsCredentialDo) Order(conds ...field.Expr) *dnsCredentialDo {
return d.withDO(d.DO.Order(conds...))
}
func (d dnsCredentialDo) Distinct(cols ...field.Expr) *dnsCredentialDo {
return d.withDO(d.DO.Distinct(cols...))
}
func (d dnsCredentialDo) Omit(cols ...field.Expr) *dnsCredentialDo {
return d.withDO(d.DO.Omit(cols...))
}
func (d dnsCredentialDo) Join(table schema.Tabler, on ...field.Expr) *dnsCredentialDo {
return d.withDO(d.DO.Join(table, on...))
}
func (d dnsCredentialDo) LeftJoin(table schema.Tabler, on ...field.Expr) *dnsCredentialDo {
return d.withDO(d.DO.LeftJoin(table, on...))
}
func (d dnsCredentialDo) RightJoin(table schema.Tabler, on ...field.Expr) *dnsCredentialDo {
return d.withDO(d.DO.RightJoin(table, on...))
}
func (d dnsCredentialDo) Group(cols ...field.Expr) *dnsCredentialDo {
return d.withDO(d.DO.Group(cols...))
}
func (d dnsCredentialDo) Having(conds ...gen.Condition) *dnsCredentialDo {
return d.withDO(d.DO.Having(conds...))
}
func (d dnsCredentialDo) Limit(limit int) *dnsCredentialDo {
return d.withDO(d.DO.Limit(limit))
}
func (d dnsCredentialDo) Offset(offset int) *dnsCredentialDo {
return d.withDO(d.DO.Offset(offset))
}
func (d dnsCredentialDo) Scopes(funcs ...func(gen.Dao) gen.Dao) *dnsCredentialDo {
return d.withDO(d.DO.Scopes(funcs...))
}
func (d dnsCredentialDo) Unscoped() *dnsCredentialDo {
return d.withDO(d.DO.Unscoped())
}
func (d dnsCredentialDo) Create(values ...*model.DnsCredential) error {
if len(values) == 0 {
return nil
}
return d.DO.Create(values)
}
func (d dnsCredentialDo) CreateInBatches(values []*model.DnsCredential, batchSize int) error {
return d.DO.CreateInBatches(values, batchSize)
}
// Save : !!! underlying implementation is different with GORM
// The method is equivalent to executing the statement: db.Clauses(clause.OnConflict{UpdateAll: true}).Create(values)
func (d dnsCredentialDo) Save(values ...*model.DnsCredential) error {
if len(values) == 0 {
return nil
}
return d.DO.Save(values)
}
func (d dnsCredentialDo) First() (*model.DnsCredential, error) {
if result, err := d.DO.First(); err != nil {
return nil, err
} else {
return result.(*model.DnsCredential), nil
}
}
func (d dnsCredentialDo) Take() (*model.DnsCredential, error) {
if result, err := d.DO.Take(); err != nil {
return nil, err
} else {
return result.(*model.DnsCredential), nil
}
}
func (d dnsCredentialDo) Last() (*model.DnsCredential, error) {
if result, err := d.DO.Last(); err != nil {
return nil, err
} else {
return result.(*model.DnsCredential), nil
}
}
func (d dnsCredentialDo) Find() ([]*model.DnsCredential, error) {
result, err := d.DO.Find()
return result.([]*model.DnsCredential), err
}
func (d dnsCredentialDo) FindInBatch(batchSize int, fc func(tx gen.Dao, batch int) error) (results []*model.DnsCredential, err error) {
buf := make([]*model.DnsCredential, 0, batchSize)
err = d.DO.FindInBatches(&buf, batchSize, func(tx gen.Dao, batch int) error {
defer func() { results = append(results, buf...) }()
return fc(tx, batch)
})
return results, err
}
func (d dnsCredentialDo) FindInBatches(result *[]*model.DnsCredential, batchSize int, fc func(tx gen.Dao, batch int) error) error {
return d.DO.FindInBatches(result, batchSize, fc)
}
func (d dnsCredentialDo) Attrs(attrs ...field.AssignExpr) *dnsCredentialDo {
return d.withDO(d.DO.Attrs(attrs...))
}
func (d dnsCredentialDo) Assign(attrs ...field.AssignExpr) *dnsCredentialDo {
return d.withDO(d.DO.Assign(attrs...))
}
func (d dnsCredentialDo) Joins(fields ...field.RelationField) *dnsCredentialDo {
for _, _f := range fields {
d = *d.withDO(d.DO.Joins(_f))
}
return &d
}
func (d dnsCredentialDo) Preload(fields ...field.RelationField) *dnsCredentialDo {
for _, _f := range fields {
d = *d.withDO(d.DO.Preload(_f))
}
return &d
}
func (d dnsCredentialDo) FirstOrInit() (*model.DnsCredential, error) {
if result, err := d.DO.FirstOrInit(); err != nil {
return nil, err
} else {
return result.(*model.DnsCredential), nil
}
}
func (d dnsCredentialDo) FirstOrCreate() (*model.DnsCredential, error) {
if result, err := d.DO.FirstOrCreate(); err != nil {
return nil, err
} else {
return result.(*model.DnsCredential), nil
}
}
func (d dnsCredentialDo) FindByPage(offset int, limit int) (result []*model.DnsCredential, count int64, err error) {
result, err = d.Offset(offset).Limit(limit).Find()
if err != nil {
return
}
if size := len(result); 0 < limit && 0 < size && size < limit {
count = int64(size + offset)
return
}
count, err = d.Offset(-1).Limit(-1).Count()
return
}
func (d dnsCredentialDo) ScanByPage(result interface{}, offset int, limit int) (count int64, err error) {
count, err = d.Count()
if err != nil {
return
}
err = d.Offset(offset).Limit(limit).Scan(result)
return
}
func (d dnsCredentialDo) Scan(result interface{}) (err error) {
return d.DO.Scan(result)
}
func (d dnsCredentialDo) Delete(models ...*model.DnsCredential) (result gen.ResultInfo, err error) {
return d.DO.Delete(models)
}
func (d *dnsCredentialDo) withDO(do gen.Dao) *dnsCredentialDo {
d.DO = *do.(*gen.DO)
return d
}

View file

@ -16,13 +16,14 @@ import (
) )
var ( var (
Q = new(Query) Q = new(Query)
Auth *auth Auth *auth
AuthToken *authToken AuthToken *authToken
Cert *cert Cert *cert
ChatGPTLog *chatGPTLog ChatGPTLog *chatGPTLog
ConfigBackup *configBackup ConfigBackup *configBackup
Site *site DnsCredential *dnsCredential
Site *site
) )
func SetDefault(db *gorm.DB, opts ...gen.DOOption) { func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
@ -32,43 +33,47 @@ func SetDefault(db *gorm.DB, opts ...gen.DOOption) {
Cert = &Q.Cert Cert = &Q.Cert
ChatGPTLog = &Q.ChatGPTLog ChatGPTLog = &Q.ChatGPTLog
ConfigBackup = &Q.ConfigBackup ConfigBackup = &Q.ConfigBackup
DnsCredential = &Q.DnsCredential
Site = &Q.Site Site = &Q.Site
} }
func Use(db *gorm.DB, opts ...gen.DOOption) *Query { func Use(db *gorm.DB, opts ...gen.DOOption) *Query {
return &Query{ return &Query{
db: db, db: db,
Auth: newAuth(db, opts...), Auth: newAuth(db, opts...),
AuthToken: newAuthToken(db, opts...), AuthToken: newAuthToken(db, opts...),
Cert: newCert(db, opts...), Cert: newCert(db, opts...),
ChatGPTLog: newChatGPTLog(db, opts...), ChatGPTLog: newChatGPTLog(db, opts...),
ConfigBackup: newConfigBackup(db, opts...), ConfigBackup: newConfigBackup(db, opts...),
Site: newSite(db, opts...), DnsCredential: newDnsCredential(db, opts...),
Site: newSite(db, opts...),
} }
} }
type Query struct { type Query struct {
db *gorm.DB db *gorm.DB
Auth auth Auth auth
AuthToken authToken AuthToken authToken
Cert cert Cert cert
ChatGPTLog chatGPTLog ChatGPTLog chatGPTLog
ConfigBackup configBackup ConfigBackup configBackup
Site site DnsCredential dnsCredential
Site site
} }
func (q *Query) Available() bool { return q.db != nil } func (q *Query) Available() bool { return q.db != nil }
func (q *Query) clone(db *gorm.DB) *Query { func (q *Query) clone(db *gorm.DB) *Query {
return &Query{ return &Query{
db: db, db: db,
Auth: q.Auth.clone(db), Auth: q.Auth.clone(db),
AuthToken: q.AuthToken.clone(db), AuthToken: q.AuthToken.clone(db),
Cert: q.Cert.clone(db), Cert: q.Cert.clone(db),
ChatGPTLog: q.ChatGPTLog.clone(db), ChatGPTLog: q.ChatGPTLog.clone(db),
ConfigBackup: q.ConfigBackup.clone(db), ConfigBackup: q.ConfigBackup.clone(db),
Site: q.Site.clone(db), DnsCredential: q.DnsCredential.clone(db),
Site: q.Site.clone(db),
} }
} }
@ -82,33 +87,36 @@ func (q *Query) WriteDB() *Query {
func (q *Query) ReplaceDB(db *gorm.DB) *Query { func (q *Query) ReplaceDB(db *gorm.DB) *Query {
return &Query{ return &Query{
db: db, db: db,
Auth: q.Auth.replaceDB(db), Auth: q.Auth.replaceDB(db),
AuthToken: q.AuthToken.replaceDB(db), AuthToken: q.AuthToken.replaceDB(db),
Cert: q.Cert.replaceDB(db), Cert: q.Cert.replaceDB(db),
ChatGPTLog: q.ChatGPTLog.replaceDB(db), ChatGPTLog: q.ChatGPTLog.replaceDB(db),
ConfigBackup: q.ConfigBackup.replaceDB(db), ConfigBackup: q.ConfigBackup.replaceDB(db),
Site: q.Site.replaceDB(db), DnsCredential: q.DnsCredential.replaceDB(db),
Site: q.Site.replaceDB(db),
} }
} }
type queryCtx struct { type queryCtx struct {
Auth *authDo Auth *authDo
AuthToken *authTokenDo AuthToken *authTokenDo
Cert *certDo Cert *certDo
ChatGPTLog *chatGPTLogDo ChatGPTLog *chatGPTLogDo
ConfigBackup *configBackupDo ConfigBackup *configBackupDo
Site *siteDo DnsCredential *dnsCredentialDo
Site *siteDo
} }
func (q *Query) WithContext(ctx context.Context) *queryCtx { func (q *Query) WithContext(ctx context.Context) *queryCtx {
return &queryCtx{ return &queryCtx{
Auth: q.Auth.WithContext(ctx), Auth: q.Auth.WithContext(ctx),
AuthToken: q.AuthToken.WithContext(ctx), AuthToken: q.AuthToken.WithContext(ctx),
Cert: q.Cert.WithContext(ctx), Cert: q.Cert.WithContext(ctx),
ChatGPTLog: q.ChatGPTLog.WithContext(ctx), ChatGPTLog: q.ChatGPTLog.WithContext(ctx),
ConfigBackup: q.ConfigBackup.WithContext(ctx), ConfigBackup: q.ConfigBackup.WithContext(ctx),
Site: q.Site.WithContext(ctx), DnsCredential: q.DnsCredential.WithContext(ctx),
Site: q.Site.WithContext(ctx),
} }
} }

View file

@ -96,6 +96,14 @@ func InitRouter() *gin.Engine {
g.DELETE("auto_cert/:name", api.RemoveDomainFromAutoCert) g.DELETE("auto_cert/:name", api.RemoveDomainFromAutoCert)
g.GET("auto_cert/dns/providers", api.GetDNSProvidersList) g.GET("auto_cert/dns/providers", api.GetDNSProvidersList)
g.GET("auto_cert/dns/provider/:code", api.GetDNSProvider) g.GET("auto_cert/dns/provider/:code", api.GetDNSProvider)
// DNS Credential
g.GET("dns_credentials", api.GetDnsCredentialList)
g.GET("dns_credential/:id", api.GetDnsCredential)
g.POST("dns_credential", api.AddDnsCredential)
g.POST("dns_credential/:id", api.EditDnsCredential)
g.DELETE("dns_credential/:id", api.DeleteDnsCredential)
// pty // pty
g.GET("pty", api.Pty) g.GET("pty", api.Pty)