mirror of https://github.com/1Panel-dev/1Panel
feat: 网站选择证书可以通过 acme 账号过滤 (#1530)
parent
6fea06729e
commit
f70b0049d9
|
@ -35,7 +35,7 @@ func (b *BaseApi) PageWebsiteSSL(c *gin.Context) {
|
||||||
Items: accounts,
|
Items: accounts,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
list, err := websiteSSLService.Search()
|
list, err := websiteSSLService.Search(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -4,6 +4,7 @@ import "github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
|
|
||||||
type WebsiteSSLSearch struct {
|
type WebsiteSSLSearch struct {
|
||||||
dto.PageInfo
|
dto.PageInfo
|
||||||
|
AcmeAccountID uint `json:"acmeAccountId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type WebsiteSSLCreate struct {
|
type WebsiteSSLCreate struct {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
"github.com/1Panel-dev/1Panel/backend/global"
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
|
@ -21,7 +22,7 @@ type WebsiteSSLService struct {
|
||||||
type IWebsiteSSLService interface {
|
type IWebsiteSSLService interface {
|
||||||
Page(search request.WebsiteSSLSearch) (int64, []response.WebsiteSSLDTO, error)
|
Page(search request.WebsiteSSLSearch) (int64, []response.WebsiteSSLDTO, error)
|
||||||
GetSSL(id uint) (*response.WebsiteSSLDTO, error)
|
GetSSL(id uint) (*response.WebsiteSSLDTO, error)
|
||||||
Search() ([]response.WebsiteSSLDTO, error)
|
Search(req request.WebsiteSSLSearch) ([]response.WebsiteSSLDTO, error)
|
||||||
Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error)
|
Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error)
|
||||||
Renew(sslId uint) error
|
Renew(sslId uint) error
|
||||||
GetDNSResolve(req request.WebsiteDNSReq) ([]response.WebsiteDNSRes, error)
|
GetDNSResolve(req request.WebsiteDNSReq) ([]response.WebsiteDNSRes, error)
|
||||||
|
@ -35,17 +36,19 @@ func NewIWebsiteSSLService() IWebsiteSSLService {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w WebsiteSSLService) Page(search request.WebsiteSSLSearch) (int64, []response.WebsiteSSLDTO, error) {
|
func (w WebsiteSSLService) Page(search request.WebsiteSSLSearch) (int64, []response.WebsiteSSLDTO, error) {
|
||||||
|
var (
|
||||||
|
result []response.WebsiteSSLDTO
|
||||||
|
)
|
||||||
total, sslList, err := websiteSSLRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
|
total, sslList, err := websiteSSLRepo.Page(search.Page, search.PageSize, commonRepo.WithOrderBy("created_at desc"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
var sslDTOs []response.WebsiteSSLDTO
|
for _, sslModel := range sslList {
|
||||||
for _, ssl := range sslList {
|
result = append(result, response.WebsiteSSLDTO{
|
||||||
sslDTOs = append(sslDTOs, response.WebsiteSSLDTO{
|
WebsiteSSL: sslModel,
|
||||||
WebsiteSSL: ssl,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return total, sslDTOs, err
|
return total, result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w WebsiteSSLService) GetSSL(id uint) (*response.WebsiteSSLDTO, error) {
|
func (w WebsiteSSLService) GetSSL(id uint) (*response.WebsiteSSLDTO, error) {
|
||||||
|
@ -58,18 +61,25 @@ func (w WebsiteSSLService) GetSSL(id uint) (*response.WebsiteSSLDTO, error) {
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w WebsiteSSLService) Search() ([]response.WebsiteSSLDTO, error) {
|
func (w WebsiteSSLService) Search(search request.WebsiteSSLSearch) ([]response.WebsiteSSLDTO, error) {
|
||||||
sslList, err := websiteSSLRepo.List()
|
var (
|
||||||
|
opts []repo.DBOption
|
||||||
|
result []response.WebsiteSSLDTO
|
||||||
|
)
|
||||||
|
opts = append(opts, commonRepo.WithOrderBy("created_at desc"))
|
||||||
|
if search.AcmeAccountID >= 0 {
|
||||||
|
opts = append(opts, websiteSSLRepo.WithByAcmeAccountId(search.AcmeAccountID))
|
||||||
|
}
|
||||||
|
sslList, err := websiteSSLRepo.List(opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var sslDTOs []response.WebsiteSSLDTO
|
for _, sslModel := range sslList {
|
||||||
for _, ssl := range sslList {
|
result = append(result, response.WebsiteSSLDTO{
|
||||||
sslDTOs = append(sslDTOs, response.WebsiteSSLDTO{
|
WebsiteSSL: sslModel,
|
||||||
WebsiteSSL: ssl,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return sslDTOs, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error) {
|
func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.WebsiteSSLCreate, error) {
|
||||||
|
|
|
@ -160,6 +160,7 @@ export namespace Website {
|
||||||
provider: string;
|
provider: string;
|
||||||
websites?: Website.Website[];
|
websites?: Website.Website[];
|
||||||
autoRenew: boolean;
|
autoRenew: boolean;
|
||||||
|
acmeAccountId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SSLCreate {
|
export interface SSLCreate {
|
||||||
|
@ -207,6 +208,7 @@ export namespace Website {
|
||||||
|
|
||||||
export interface SSLReq {
|
export interface SSLReq {
|
||||||
name?: string;
|
name?: string;
|
||||||
|
acmeAccountID?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HTTPSReq {
|
export interface HTTPSReq {
|
||||||
|
|
|
@ -1412,6 +1412,8 @@ const message = {
|
||||||
disableLeech: 'Disable anti-leech',
|
disableLeech: 'Disable anti-leech',
|
||||||
ipv6: 'Listen IPV6',
|
ipv6: 'Listen IPV6',
|
||||||
leechReturnError: 'Please fill in the HTTP status code',
|
leechReturnError: 'Please fill in the HTTP status code',
|
||||||
|
selectAcme: 'Select Acme account',
|
||||||
|
localSSL: 'Imported',
|
||||||
},
|
},
|
||||||
php: {
|
php: {
|
||||||
short_open_tag: 'Short tag support',
|
short_open_tag: 'Short tag support',
|
||||||
|
|
|
@ -1339,6 +1339,8 @@ const message = {
|
||||||
disableLeech: '禁用防盜鏈',
|
disableLeech: '禁用防盜鏈',
|
||||||
ipv6: '監聽 IPV6 端口',
|
ipv6: '監聽 IPV6 端口',
|
||||||
leechReturnError: '請填寫 HTTP 狀態碼',
|
leechReturnError: '請填寫 HTTP 狀態碼',
|
||||||
|
selectAcme: '選擇 Acme 賬號',
|
||||||
|
localSSL: '已導入',
|
||||||
},
|
},
|
||||||
php: {
|
php: {
|
||||||
short_open_tag: '短標簽支持',
|
short_open_tag: '短標簽支持',
|
||||||
|
|
|
@ -1345,6 +1345,8 @@ const message = {
|
||||||
disableLeech: '禁用防盗链',
|
disableLeech: '禁用防盗链',
|
||||||
ipv6: '监听 IPV6 端口',
|
ipv6: '监听 IPV6 端口',
|
||||||
leechReturnError: '请填写 HTTP 状态码',
|
leechReturnError: '请填写 HTTP 状态码',
|
||||||
|
selectAcme: '选择 acme 账号',
|
||||||
|
localSSL: '已导入',
|
||||||
},
|
},
|
||||||
php: {
|
php: {
|
||||||
short_open_tag: '短标签支持',
|
short_open_tag: '短标签支持',
|
||||||
|
|
|
@ -27,12 +27,23 @@
|
||||||
<el-option :label="$t('website.manualSSL')" :value="'manual'"></el-option>
|
<el-option :label="$t('website.manualSSL')" :value="'manual'"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item
|
<div v-if="form.type === 'existed'">
|
||||||
:label="$t('website.ssl')"
|
<el-form-item :label="$t('website.acmeAccountManage')" prop="acmeAccountID">
|
||||||
prop="websiteSSLId"
|
<el-select
|
||||||
v-if="form.type === 'existed'"
|
v-model="form.acmeAccountID"
|
||||||
:hide-required-asterisk="true"
|
:placeholder="$t('website.selectAcme')"
|
||||||
|
@change="listSSL"
|
||||||
>
|
>
|
||||||
|
<el-option :key="0" :label="$t('website.localSSL')" :value="0"></el-option>
|
||||||
|
<el-option
|
||||||
|
v-for="(acme, index) in acmeAccounts"
|
||||||
|
:key="index"
|
||||||
|
:label="acme.email"
|
||||||
|
:value="acme.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('website.ssl')" prop="websiteSSLId" :hide-required-asterisk="true">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="form.websiteSSLId"
|
v-model="form.websiteSSLId"
|
||||||
:placeholder="$t('website.selectSSL')"
|
:placeholder="$t('website.selectSSL')"
|
||||||
|
@ -46,6 +57,7 @@
|
||||||
></el-option>
|
></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
</div>
|
||||||
<div v-if="form.type === 'manual'">
|
<div v-if="form.type === 'manual'">
|
||||||
<el-form-item :label="$t('website.privateKey')" prop="privateKey">
|
<el-form-item :label="$t('website.privateKey')" prop="privateKey">
|
||||||
<el-input v-model="form.privateKey" :rows="6" type="textarea" />
|
<el-input v-model="form.privateKey" :rows="6" type="textarea" />
|
||||||
|
@ -118,7 +130,7 @@
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { Website } from '@/api/interface/website';
|
import { Website } from '@/api/interface/website';
|
||||||
import { GetHTTPSConfig, ListSSL, UpdateHTTPSConfig } from '@/api/modules/website';
|
import { GetHTTPSConfig, ListSSL, SearchAcmeAccount, UpdateHTTPSConfig } from '@/api/modules/website';
|
||||||
import { ElMessageBox, FormInstance } from 'element-plus';
|
import { ElMessageBox, FormInstance } from 'element-plus';
|
||||||
import { computed, onMounted, reactive, ref } from 'vue';
|
import { computed, onMounted, reactive, ref } from 'vue';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
|
@ -137,6 +149,7 @@ const id = computed(() => {
|
||||||
});
|
});
|
||||||
const httpsForm = ref<FormInstance>();
|
const httpsForm = ref<FormInstance>();
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
|
acmeAccountID: 0,
|
||||||
enable: false,
|
enable: false,
|
||||||
websiteId: id.value,
|
websiteId: id.value,
|
||||||
websiteSSLId: undefined,
|
websiteSSLId: undefined,
|
||||||
|
@ -150,6 +163,7 @@ const form = reactive({
|
||||||
});
|
});
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const ssls = ref();
|
const ssls = ref();
|
||||||
|
const acmeAccounts = ref();
|
||||||
const websiteSSL = ref();
|
const websiteSSL = ref();
|
||||||
const rules = ref({
|
const rules = ref({
|
||||||
type: [Rules.requiredSelect],
|
type: [Rules.requiredSelect],
|
||||||
|
@ -159,13 +173,30 @@ const rules = ref({
|
||||||
httpConfig: [Rules.requiredSelect],
|
httpConfig: [Rules.requiredSelect],
|
||||||
SSLProtocol: [Rules.requiredSelect],
|
SSLProtocol: [Rules.requiredSelect],
|
||||||
algorithm: [Rules.requiredInput],
|
algorithm: [Rules.requiredInput],
|
||||||
|
acmeAccountID: [Rules.requiredInput],
|
||||||
});
|
});
|
||||||
const resData = ref();
|
const resData = ref();
|
||||||
|
const sslReq = reactive({
|
||||||
|
acmeAccountID: 0,
|
||||||
|
});
|
||||||
|
|
||||||
const listSSL = () => {
|
const listSSL = () => {
|
||||||
ListSSL({}).then((res) => {
|
sslReq.acmeAccountID = form.acmeAccountID;
|
||||||
ssls.value = res.data;
|
ListSSL(sslReq).then((res) => {
|
||||||
|
ssls.value = res.data || [];
|
||||||
|
if (ssls.value.length > 0) {
|
||||||
|
form.websiteSSLId = ssls.value[0].id;
|
||||||
changeSSl(form.websiteSSLId);
|
changeSSl(form.websiteSSLId);
|
||||||
|
} else {
|
||||||
|
websiteSSL.value = {};
|
||||||
|
form.websiteSSLId = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const listAcmeAccount = () => {
|
||||||
|
SearchAcmeAccount({ page: 1, pageSize: 100 }).then((res) => {
|
||||||
|
acmeAccounts.value = res.data.items || [];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -200,9 +231,12 @@ const get = () => {
|
||||||
if (res.data.SSL && res.data.SSL.id > 0) {
|
if (res.data.SSL && res.data.SSL.id > 0) {
|
||||||
form.websiteSSLId = res.data.SSL.id;
|
form.websiteSSLId = res.data.SSL.id;
|
||||||
websiteSSL.value = res.data.SSL;
|
websiteSSL.value = res.data.SSL;
|
||||||
|
sslReq.acmeAccountID = res.data.SSL.acmeAccountId;
|
||||||
|
form.acmeAccountID = res.data.SSL.acmeAccountId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
listSSL();
|
listSSL();
|
||||||
|
listAcmeAccount();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const submit = async (formEl: FormInstance | undefined) => {
|
const submit = async (formEl: FormInstance | undefined) => {
|
||||||
|
|
Loading…
Reference in New Issue