feat: deploy site config to remote server

This commit is contained in:
0xJacky 2023-05-16 19:45:38 +08:00
parent 0bae0e0912
commit 4135146b67
No known key found for this signature in database
GPG key ID: B6E4A6E4A561BAF0
16 changed files with 350 additions and 158 deletions

View file

@ -63,6 +63,7 @@ declare module '@vue/runtime-core' {
ATabs: typeof import('ant-design-vue/es')['Tabs']
ATag: typeof import('ant-design-vue/es')['Tag']
ATextarea: typeof import('ant-design-vue/es')['Textarea']
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
BreadcrumbBreadcrumb: typeof import('./src/components/Breadcrumb/Breadcrumb.vue')['default']
ChartAreaChart: typeof import('./src/components/Chart/AreaChart.vue')['default']
ChartRadialBarChart: typeof import('./src/components/Chart/RadialBarChart.vue')['default']

View file

@ -185,93 +185,74 @@ async function regenerate(index: number) {
const editing_idx = ref(-1)
const show = computed(() => messages?.value?.length > 1)
const show = computed(() => messages?.value?.length === 0)
</script>
<template>
<a-card class="chatgpt" title="ChatGPT" v-if="show">
<div class="chatgpt-container">
<a-list
class="chatgpt-log"
item-layout="horizontal"
:data-source="messages"
>
<template #renderItem="{ item, index }">
<a-list-item>
<a-comment :author="item.role" :avatar="item.avatar">
<template #content>
<div class="content" v-if="item.role==='assistant'||editing_idx!=index"
v-html="marked.parse(item.content)"></div>
<a-input style="padding: 0" v-else v-model:value="item.content"
:bordered="false"/>
</template>
<template #actions>
<div class="chat-start" v-if="show">
<a-button @click="send" :loading="loading">
<Icon v-if="!loading" :component="ChatGPT_logo"/>
{{ $gettext('Ask ChatGPT for Help') }}
</a-button>
</div>
<div class="chatgpt-container" v-else>
<a-list
class="chatgpt-log"
item-layout="horizontal"
:data-source="messages"
>
<template #renderItem="{ item, index }">
<a-list-item>
<a-comment :author="item.role==='assistant'?$gettext('Assistant'):$gettext('User')">
<template #content>
<div class="content" v-if="item.role==='assistant'||editing_idx!=index"
v-html="marked.parse(item.content)"></div>
<a-input style="padding: 0" v-else v-model:value="item.content"
:bordered="false"/>
</template>
<template #actions>
<span v-if="item.role==='user'&&editing_idx!==index" @click="editing_idx=index">
{{ $gettext('Modify') }}
</span>
<template v-else-if="editing_idx==index">
<span @click="regenerate(index+1)">{{ $gettext('Save') }}</span>
<span @click="editing_idx=-1">{{ $gettext('Cancel') }}</span>
</template>
<span v-else-if="!loading" @click="regenerate(index)" :disabled="loading">
<template v-else-if="editing_idx==index">
<span @click="regenerate(index+1)">{{ $gettext('Save') }}</span>
<span @click="editing_idx=-1">{{ $gettext('Cancel') }}</span>
</template>
<span v-else-if="!loading" @click="regenerate(index)" :disabled="loading">
{{ $gettext('Reload') }}
</span>
</template>
</a-comment>
</a-list-item>
</template>
</a-list>
<div class="input-msg">
<div class="control-btn">
<a-space v-show="!loading">
<a-popconfirm
:cancelText="$gettext('No')"
:okText="$gettext('OK')"
:title="$gettext('Are you sure you want to clear the record of chat?')"
@confirm="clear_record">
<a-button type="text">{{ $gettext('Clear') }}</a-button>
</a-popconfirm>
<a-button type="text" @click="regenerate(messages?.length-1)">
{{ $gettext('Regenerate response') }}
</a-button>
</a-space>
</div>
<a-textarea auto-size v-model:value="ask_buffer"/>
<div class="sned-btn">
<a-button size="small" type="text" :loading="loading" @click="send">
<send-outlined/>
</template>
</a-comment>
</a-list-item>
</template>
</a-list>
<div class="input-msg">
<div class="control-btn">
<a-space v-show="!loading">
<a-popconfirm
:cancelText="$gettext('No')"
:okText="$gettext('OK')"
:title="$gettext('Are you sure you want to clear the record of chat?')"
@confirm="clear_record">
<a-button type="text">{{ $gettext('Clear') }}</a-button>
</a-popconfirm>
<a-button type="text" @click="regenerate(messages?.length-1)">
{{ $gettext('Regenerate response') }}
</a-button>
</div>
</a-space>
</div>
<a-textarea auto-size v-model:value="ask_buffer"/>
<div class="sned-btn">
<a-button size="small" type="text" :loading="loading" @click="send">
<send-outlined/>
</a-button>
</div>
</div>
</a-card>
<template v-else>
<div class="chat-start">
<a-button size="large" shape="circle" @click="send" :loading="loading">
<Icon v-if="!loading" :component="ChatGPT_logo"/>
</a-button>
</div>
</template>
</div>
</template>
<style lang="less" scoped>
.chatgpt {
position: sticky;
top: 78px;
:deep(.ant-card-body) {
max-height: 100vh;
overflow-y: scroll;
}
}
.chat-start {
position: fixed !important;
right: 36px;
bottom: 78px;
}
.chatgpt-container {
margin: 0 auto;
max-width: 800px;
@ -285,6 +266,10 @@ const show = computed(() => messages?.value?.length > 1)
}
}
:deep(.ant-list-item) {
padding: 0;
}
:deep(.ant-comment-content) {
width: 100%;
}

View file

@ -12,9 +12,8 @@ const settingsStore = useSettingsStore()
const {environment} = storeToRefs(settingsStore)
const router = useRouter()
function clear_env() {
router.push('/dashboard')
location.reload()
async function clear_env() {
await router.push('/dashboard')
settingsStore.clear_environment()
}
@ -24,8 +23,8 @@ const is_local = computed(() => {
const node_id = computed(() => environment.value.id)
watch(node_id, () => {
router.push('/dashboard')
watch(node_id, async () => {
await router.push('/dashboard')
location.reload()
})
</script>

View file

@ -5,7 +5,7 @@ import {useGettext} from 'vue3-gettext'
const {$gettext} = useGettext()
const props = defineProps(['target', 'map'])
const props = defineProps(['target', 'map', 'hidden_local'])
const emit = defineEmits(['update:target'])
const data = ref([])
@ -35,15 +35,15 @@ const value = computed({
<template>
<a-checkbox-group v-model:value="value" style="width: 100%">
<a-row>
<a-col :span="8">
<a-row :gutter="[16,16]">
<a-col :span="8" v-if="!hidden_local">
<a-checkbox :value="0">{{ $gettext('Local') }}</a-checkbox>
<a-badge color="green"/>
<a-tag color="blue">{{ $gettext('Online') }}</a-tag>
</a-col>
<a-col :span="8" v-for="node in data">
<a-checkbox :value="node.id">{{ node.name }}</a-checkbox>
<a-badge color="green" v-if="node.status"/>
<a-badge color="red" v-else/>
<a-tag color="blue" v-if="node.status">{{ $gettext('Online') }}</a-tag>
<a-tag color="error" v-else>{{ $gettext('Offline') }}</a-tag>
</a-col>
</a-row>
</a-checkbox-group>

View file

@ -65,15 +65,12 @@ function format_code() {
})
}
const editor_md = computed(() => history_chatgpt_record?.value?.length > 1 ? 16 : 24)
const chat_md = computed(() => history_chatgpt_record?.value?.length > 1 ? 8 : 24)
</script>
<template>
<a-row :gutter="16">
<a-col :xs="24" :sm="24" :md="editor_md">
<a-col :xs="24" :sm="24" :md="18">
<a-card :title="$gettext('Edit Configuration')">
<inspect-config ref="inspect_config"/>
<code-editor v-model:content="configText"/>
@ -93,9 +90,11 @@ const chat_md = computed(() => history_chatgpt_record?.value?.length > 1 ? 8 : 2
</a-card>
</a-col>
<a-col class="col-right" :xs="24" :sm="24" :md="chat_md">
<chat-g-p-t :content="configText" :path="file_path"
v-model:history_messages="history_chatgpt_record"/>
<a-col class="col-right" :xs="24" :sm="24" :md="6">
<a-card>
<chat-g-p-t :content="configText" :path="file_path"
v-model:history_messages="history_chatgpt_record"/>
</a-card>
</a-col>
</a-row>
</template>

View file

@ -58,8 +58,10 @@ const visible = computed(() => {
<a-tag color="blue" v-if="item.status">{{ $gettext('Online') }}</a-tag>
<a-tag color="error" v-else>{{ $gettext('Offline') }}</a-tag>
<div class="runtime-meta">
<span><Icon :component="pulse"/> {{ formatDateTime(item.response_at) }}</span>
<span><thunderbolt-outlined/>{{ item.version }}</span>
<template v-if="item.status">
<span><Icon :component="pulse"/> {{ formatDateTime(item.response_at) }}</span>
<span><thunderbolt-outlined/>{{ item.version }}</span>
</template>
<span><link-outlined/>{{ item.url }}</span>
</div>
</template>
@ -85,7 +87,6 @@ const visible = computed(() => {
.runtime-meta {
display: inline-flex;
margin-left: 8px;
span {
font-weight: 400;

View file

@ -8,10 +8,9 @@ import {computed, provide, reactive, ref, watch} from 'vue'
import {useRoute, useRouter} from 'vue-router'
import domain from '@/api/domain'
import ngx from '@/api/ngx'
import Modal from 'ant-design-vue/lib/modal'
import {message} from 'ant-design-vue'
import config from '@/api/config'
import ChatGPT from '@/components/ChatGPT/ChatGPT.vue'
import RightSettings from '@/views/domain/components/RightSettings.vue'
const {$gettext, interpolate} = useGettext()
@ -42,6 +41,7 @@ const saving = ref(false)
const filename = ref('')
const parse_error_status = ref(false)
const parse_error_message = ref('')
const data = ref({})
init()
@ -74,6 +74,7 @@ function handle_response(r: any) {
enabled.value = r.enabled
auto_cert.value = r.auto_cert
history_chatgpt_record.value = r.chatgpt_messages
data.value = r
Object.assign(ngx_config, r.tokenized)
Object.assign(cert_info_map, r.cert_info)
}
@ -149,49 +150,18 @@ const save = async () => {
})
}
function enable() {
domain.enable(name.value).then(() => {
message.success($gettext('Enabled successfully'))
enabled.value = true
}).catch(r => {
message.error(interpolate($gettext('Failed to enable %{msg}'), {msg: r.message ?? ''}), 10)
})
}
function disable() {
domain.disable(name.value).then(() => {
message.success($gettext('Disabled successfully'))
enabled.value = false
}).catch(r => {
message.error(interpolate($gettext('Failed to disable %{msg}'), {msg: r.message ?? ''}))
})
}
function on_change_enabled(checked: boolean) {
Modal.confirm({
title: checked ? $gettext('Do you want to enable this site?') : $gettext('Do you want to disable this site?'),
mask: false,
centered: true,
okText: $gettext('OK'),
cancelText: $gettext('Cancel'),
async onOk() {
if (checked) {
enable()
} else {
disable()
}
}
})
}
const editor_md = computed(() => history_chatgpt_record?.value?.length > 1 ? 16 : 24)
const chat_md = computed(() => history_chatgpt_record?.value?.length > 1 ? 8 : 24)
provide('save_site_config', save)
provide('configText', configText)
provide('ngx_config', ngx_config)
provide('history_chatgpt_record', history_chatgpt_record)
provide('enabled', enabled)
provide('name', name)
provide('filename', filename)
provide('data', data)
</script>
<template>
<a-row :gutter="16">
<a-col :xs="24" :sm="24" :md="editor_md">
<a-col :xs="24" :sm="24" :md="18">
<a-card :bordered="false">
<template #title>
<span style="margin-right: 10px">{{ interpolate($gettext('Edit %{n}'), {n: name}) }}</span>
@ -217,13 +187,6 @@ provide('save_site_config', save)
</div>
</template>
<a-form-item :label="$gettext('Enabled')">
<a-switch :checked="enabled" @change="on_change_enabled"/>
</a-form-item>
<a-form-item :label="$gettext('Name')">
<a-input v-model:value="filename"/>
</a-form-item>
<transition name="slide-fade">
<div v-if="advance_mode" key="advance">
<div class="parse-error-alert-wrapper" v-if="parse_error_status">
@ -252,9 +215,8 @@ provide('save_site_config', save)
</a-card>
</a-col>
<a-col class="col-right" :xs="24" :sm="24" :md="chat_md">
<chat-g-p-t :content="configText" :path="ngx_config.file_name"
v-model:history_messages="history_chatgpt_record"/>
<a-col class="col-right" :xs="24" :sm="24" :md="6">
<right-settings/>
</a-col>
<footer-tool-bar>

View file

@ -7,7 +7,7 @@ import domain from '@/api/domain'
import {Badge, message} from 'ant-design-vue'
import {h, ref} from 'vue'
import {input} from '@/components/StdDataEntry'
import SiteDuplicate from '@/views/domain/SiteDuplicate.vue'
import SiteDuplicate from '@/views/domain/components/SiteDuplicate.vue'
const {$gettext, interpolate} = useGettext()

View file

@ -0,0 +1,108 @@
<script setup lang="ts">
import NodeSelector from '@/components/NodeSelector/NodeSelector.vue'
import {useGettext} from 'vue3-gettext'
import {inject, reactive, ref} from 'vue'
import {InfoCircleOutlined} from '@ant-design/icons-vue'
import Modal from 'ant-design-vue/lib/modal'
import domain from '@/api/domain'
import {notification} from 'ant-design-vue'
import template from '@/api/template'
const {$gettext, $ngettext} = useGettext()
const node_map = reactive({})
const target = ref([])
const overwrite = ref(false)
const enabled = ref(false)
const name = inject('name')
function deploy() {
Modal.confirm({
title: () => $ngettext('Do you want to deploy this file to remote server?',
'Do you want to deploy this file to remote servers?', target.value.length),
mask: false,
centered: true,
okText: $gettext('OK'),
cancelText: $gettext('Cancel'),
onOk() {
target.value.forEach(id => {
const node_name = node_map[id]
// get source content
domain.get(name.value).then(r => {
domain.save(name.value, {
name: name.value,
content: r.config,
overwrite: overwrite.value
}, {headers: {'X-Node-ID': id}}).then(async () => {
notification.success({
message: $gettext('Deploy successfully'),
description:
$gettext('Deploy %{conf_name} to %{node_name} successfully',
{conf_name: name.value, node_name: node_name})
})
if (enabled.value) {
domain.enable(name.value).then(() => {
notification.success({
message: $gettext('Enable successfully'),
description:
$gettext(`Enable %{conf_name} in %{node_name} successfully`,
{conf_name: name.value, node_name: node_name})
})
}).catch(e => {
notification.error({
message: $gettext('Enable %{conf_name} in %{node_name} failed', {
conf_name: name.value,
node_name: node_name
}),
description: $gettext(e?.message ?? 'Server error')
})
})
}
}).catch(e => {
notification.error({
message: $gettext('Deploy %{conf_name} to %{node_name} failed', {
conf_name: name.value,
node_name: node_name
}),
description: $gettext(e?.message ?? 'Server error')
})
})
})
})
}
})
}
</script>
<template>
<node-selector v-model:target="target" :hidden_local="true" :map="node_map"/>
<div class="node-deploy-control">
<a-checkbox v-model:checked="enabled">{{ $gettext('Enabled') }}</a-checkbox>
<div class="overwrite">
<a-checkbox v-model:checked="overwrite">{{ $gettext('Overwrite') }}</a-checkbox>
<a-tooltip placement="bottom">
<template #title>{{ $gettext('Overwrite exist file') }}</template>
<info-circle-outlined/>
</a-tooltip>
</div>
<a-button :disabled="target.length===0" type="primary" @click="deploy" ghost>{{ $gettext('Deploy') }}</a-button>
</div>
</template>
<style scoped lang="less">
.overwrite {
margin-right: 15px;
span {
color: #9b9b9b;
}
}
.node-deploy-control {
display: flex;
justify-content: flex-end;
margin-top: 10px;
align-items: center;
}
</style>

View file

@ -0,0 +1,104 @@
<script setup lang="ts">
import ChatGPT from '@/components/ChatGPT/ChatGPT.vue'
import {useGettext} from 'vue3-gettext'
import {inject, ref} from 'vue'
import Modal from 'ant-design-vue/lib/modal'
import domain from '@/api/domain'
import {message} from 'ant-design-vue'
import {formatDateTime} from '@/lib/helper'
import Deploy from '@/views/domain/components/Deploy.vue'
import {useSettingsStore} from '@/pinia'
const settings = useSettingsStore()
const {$gettext} = useGettext()
const configText = inject('configText')
const ngx_config = inject('ngx_config')
const enabled = inject('enabled')
const name = inject('name')
const history_chatgpt_record = inject('history_chatgpt_record')
const filename = inject('filename')
const data: any = inject('data')
const active_key = ref('1')
function enable() {
domain.enable(name.value).then(() => {
message.success($gettext('Enabled successfully'))
enabled.value = true
}).catch(r => {
message.error($gettext('Failed to enable %{msg}', {msg: r.message ?? ''}), 10)
})
}
function disable() {
domain.disable(name.value).then(() => {
message.success($gettext('Disabled successfully'))
enabled.value = false
}).catch(r => {
message.error($gettext('Failed to disable %{msg}', {msg: r.message ?? ''}))
})
}
function on_change_enabled(checked: boolean) {
Modal.confirm({
title: checked ? $gettext('Do you want to enable this site?') : $gettext('Do you want to disable this site?'),
mask: false,
centered: true,
okText: $gettext('OK'),
cancelText: $gettext('Cancel'),
async onOk() {
if (checked) {
enable()
} else {
disable()
}
}
})
}
</script>
<template>
<a-card class="right-settings">
<a-collapse v-model:activeKey="active_key" ghost>
<a-collapse-panel key="1" :header="$gettext('Basic')">
<a-form-item :label="$gettext('Enabled')">
<a-switch :checked="enabled" @change="on_change_enabled"/>
</a-form-item>
<a-form-item :label="$gettext('Name')">
<a-input v-model:value="filename"/>
</a-form-item>
<a-form-item :label="$gettext('Updated at')">
{{ formatDateTime(data.modified_at) }}
</a-form-item>
</a-collapse-panel>
<a-collapse-panel key="2" header="Deploy" v-if="!settings.is_remote">
<deploy/>
</a-collapse-panel>
<a-collapse-panel key="3" header="ChatGPT">
<chat-g-p-t :content="configText" :path="ngx_config.file_name"
v-model:history_messages="history_chatgpt_record"/>
</a-collapse-panel>
</a-collapse>
</a-card>
</template>
<style scoped lang="less">
.right-settings {
position: sticky;
top: 78px;
:deep(.ant-card-body) {
max-height: 100vh;
overflow-y: scroll;
}
}
:deep(.ant-collapse-ghost > .ant-collapse-item > .ant-collapse-content > .ant-collapse-content-box) {
padding: 0;
}
:deep(.ant-collapse > .ant-collapse-item > .ant-collapse-header) {
padding: 0 0 10px 0;
}
</style>

View file

@ -1 +1 @@
{"version":"1.9.9","build_id":115,"total_build":185}
{"version":"1.9.9","build_id":116,"total_build":186}

16
go.mod
View file

@ -19,9 +19,10 @@ require (
github.com/jpillora/overseer v1.1.6
github.com/lib/pq v1.10.9
github.com/pkg/errors v0.9.1
github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308
github.com/sashabaranov/go-openai v1.9.4
github.com/shirou/gopsutil/v3 v3.23.4
github.com/spf13/cast v1.5.0
github.com/spf13/cast v1.5.1
github.com/tufanbarisyildirim/gonginx v0.0.0-20230508164033-d7b72d6cd0d5
github.com/unknwon/com v1.0.1
go.uber.org/zap v1.24.0
@ -50,10 +51,10 @@ require (
github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
github.com/StackExchange/wmi v1.2.1 // indirect
github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.62.318 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.62.320 // indirect
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/aws/aws-sdk-go v1.44.262 // indirect
github.com/aws/aws-sdk-go v1.44.263 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bytedance/sonic v1.8.8 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
@ -139,7 +140,6 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/pquerna/otp v1.4.0 // indirect
github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/sacloud/api-client-go v0.2.7 // indirect
github.com/sacloud/go-http v0.1.5 // indirect
@ -154,8 +154,8 @@ require (
github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect
github.com/stretchr/objx v0.5.0 // indirect
github.com/stretchr/testify v1.8.2 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.655 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.655 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.657 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.657 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/transip/gotransip/v6 v6.20.0 // indirect
@ -164,8 +164,8 @@ require (
github.com/ultradns/ultradns-go-sdk v1.5.0-20230427130837-23c9b0c // indirect
github.com/vinyldns/go-vinyldns v0.9.16 // indirect
github.com/vultr/govultr/v2 v2.17.2 // indirect
github.com/yandex-cloud/go-genproto v0.0.0-20230511103421-ecb0cd1514ab // indirect
github.com/yandex-cloud/go-sdk v0.0.0-20230511104317-0ccfef4d3a91 // indirect
github.com/yandex-cloud/go-genproto v0.0.0-20230515103554-c6064682c41e // indirect
github.com/yandex-cloud/go-sdk v0.0.0-20230515104003-a4cf880c2959 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.11.0 // indirect

14
go.sum
View file

@ -70,6 +70,8 @@ github.com/aliyun/alibaba-cloud-sdk-go v1.62.281 h1:sN94THxWQA+nPMDZD0esg1PGy6pm
github.com/aliyun/alibaba-cloud-sdk-go v1.62.281/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.318 h1:1ntKWopst53IVWKlEVrgutJpEgQN+FyNZXO+h6ePgXw=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.318/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.320 h1:KiT5EgbU/rxcx4wiH1sFKaR3KyzGqB89D7JSN1vH40A=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.320/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs=
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9orim59UnfUTLRjMpd09C5uEVQ6RPGeCaVI=
github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
@ -84,6 +86,8 @@ github.com/aws/aws-sdk-go v1.44.242 h1:bb6Rqd7dxh1gTUoVXLJTNC2c+zNaHpLRlNKk0kGN3
github.com/aws/aws-sdk-go v1.44.242/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.44.262 h1:gyXpcJptWoNkK+DiAiaBltlreoWKQXjAIh6FRh60F+I=
github.com/aws/aws-sdk-go v1.44.262/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/aws/aws-sdk-go v1.44.263 h1:Dkt5fcdtL8QtK3cz0bOTQ84m9dGx+YDeTsDl+wY2yW4=
github.com/aws/aws-sdk-go v1.44.263/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@ -702,6 +706,8 @@ github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
@ -732,10 +738,14 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.637 h1:qFqi
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.637/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.655 h1:wXBlXLfBbqTBpsiKBBULW63KvMy3wsu3/CD25cR9NEA=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.655/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.657 h1:daDlYUdKRzgi2PxIcXj4vU1enWs6aqrL7K5qD3fKpmo=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.657/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.637 h1:9r85LEYF4CcKDbQQhJ5b3hYh5vj1WNvjsHrWHAV3c60=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.637/go.mod h1:5z3RG36i3UQvMr3aHVjPfrEzLdmk+sTiLgip3aFvKBo=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.655 h1:LgLA3nzvsBggdt1NRDNi6KVk9HRHLwBUltxXupdRMeM=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.655/go.mod h1:v8wyOnL22mqDNeBqsasAQzP6eQI0Lpa+cAxFtVThHTk=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.657 h1:9FAIqzmy29PS+CVlec2LaTbwSg0j8Zk55GxPMjrZUqM=
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.657/go.mod h1:O2Xg2eAwl+TLAso+0F7Iao9ru2Abf7Mj+Dgv++pvQFw=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
@ -776,10 +786,14 @@ github.com/yandex-cloud/go-genproto v0.0.0-20230410092700-15216dc82345 h1:GpSllt
github.com/yandex-cloud/go-genproto v0.0.0-20230410092700-15216dc82345/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
github.com/yandex-cloud/go-genproto v0.0.0-20230511103421-ecb0cd1514ab h1:Y9sWstUXfHwHufw95mI58ZEvZ720KWyR+niLQbd2q1k=
github.com/yandex-cloud/go-genproto v0.0.0-20230511103421-ecb0cd1514ab/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
github.com/yandex-cloud/go-genproto v0.0.0-20230515103554-c6064682c41e h1:2jQIfPgSk+/6zl44MEYLehRLRtGRGYvVyfKLXeNFGUM=
github.com/yandex-cloud/go-genproto v0.0.0-20230515103554-c6064682c41e/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
github.com/yandex-cloud/go-sdk v0.0.0-20230403093608-cc5174142a48 h1:C3yjOqP3gGxwiW3bXDAGI8tS+eKjxySJ9Ix7lpdtKZw=
github.com/yandex-cloud/go-sdk v0.0.0-20230403093608-cc5174142a48/go.mod h1:+bvtdW+7bn1Yc7xUCbITnEalQ+hwkAAbUFHpeIY2wUQ=
github.com/yandex-cloud/go-sdk v0.0.0-20230511104317-0ccfef4d3a91 h1:bYY90Y33XH7xJh8Qa5ZIgmjyWDp2S6sixTRxYbHCQLU=
github.com/yandex-cloud/go-sdk v0.0.0-20230511104317-0ccfef4d3a91/go.mod h1:QOnqdE3DjwgoKvhw4Scx6HTCfAlYHZMoUzyaC8kcdzk=
github.com/yandex-cloud/go-sdk v0.0.0-20230515104003-a4cf880c2959 h1:jFoq7f55et+ssQYFgZCWbUV2kUcDx22e1jZx+KhnBcU=
github.com/yandex-cloud/go-sdk v0.0.0-20230515104003-a4cf880c2959/go.mod h1:JNuOWjkSmssXYwJXPpOxc3IhjWbPKkODDm1gAqPFD9Q=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=

View file

@ -9,6 +9,7 @@ import (
"github.com/0xJacky/Nginx-UI/server/model"
"github.com/0xJacky/Nginx-UI/server/query"
"github.com/gin-gonic/gin"
"github.com/sashabaranov/go-openai"
"net/http"
"os"
"strings"
@ -88,8 +89,16 @@ func GetDomain(c *gin.Context) {
}
path := nginx.GetConfPath("sites-available", name)
file, err := os.Stat(path)
if os.IsNotExist(err) {
c.JSON(http.StatusNotFound, gin.H{
"message": "file not found",
})
return
}
enabled := true
if _, err := os.Stat(nginx.GetConfPath("sites-enabled", name)); os.IsNotExist(err) {
enabled = false
}
@ -102,6 +111,10 @@ func GetDomain(c *gin.Context) {
return
}
if chatgpt.Content == nil {
chatgpt.Content = make([]openai.ChatCompletionMessage, 0)
}
s := query.Site
site, err := s.Where(s.Path.Eq(path)).FirstOrInit()
@ -110,7 +123,11 @@ func GetDomain(c *gin.Context) {
return
}
certModel, _ := model.FirstCert(name)
certModel, err := model.FirstCert(name)
if err != nil {
logger.Warn("cert", err)
}
if site.Advanced {
origContent, err := os.ReadFile(path)
@ -120,6 +137,7 @@ func GetDomain(c *gin.Context) {
}
c.JSON(http.StatusOK, gin.H{
"modified_at": file.ModTime(),
"advanced": site.Advanced,
"enabled": enabled,
"name": name,
@ -167,6 +185,7 @@ func GetDomain(c *gin.Context) {
c.Set("maybe_error", "nginx_config_syntax_error")
c.JSON(http.StatusOK, gin.H{
"modified_at": file.ModTime(),
"advanced": site.Advanced,
"enabled": enabled,
"name": name,
@ -253,7 +272,7 @@ func SaveDomain(c *gin.Context) {
if helper.FileExists(enabledConfigFilePath) {
// Test nginx configuration
output := nginx.TestConf()
if nginx.GetLogLevel(output) >= nginx.Warn {
if nginx.GetLogLevel(output) > nginx.Warn {
c.JSON(http.StatusInternalServerError, gin.H{
"message": output,
"error": "nginx_config_syntax_error",
@ -263,7 +282,7 @@ func SaveDomain(c *gin.Context) {
output = nginx.Reload()
if nginx.GetLogLevel(output) >= nginx.Warn {
if nginx.GetLogLevel(output) > nginx.Warn {
c.JSON(http.StatusInternalServerError, gin.H{
"message": output,
})

View file

@ -17,7 +17,7 @@ func (j *JSON) Scan(value interface{}) error {
return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
}
var result []openai.ChatCompletionMessage
result := make([]openai.ChatCompletionMessage, 0)
err := json.Unmarshal(bytes, &result)
*j = result
return err