feat: 数据库增加 ServiceName 显示 (#573)

This commit is contained in:
ssongliu 2023-04-11 10:26:25 +08:00 committed by GitHub
parent 52030dbea0
commit 7c236ccc3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 273 additions and 124 deletions

View File

@ -93,24 +93,24 @@ func (b *BaseApi) LoadPort(c *gin.Context) {
// @Tags App
// @Summary Search app password by key
// @Description 获取应用密码
// @Description 获取应用连接信息
// @Accept json
// @Param key path string true "request"
// @Success 200 {string} password
// @Success 200 {string} response.DatabaseConn
// @Security ApiKeyAuth
// @Router /apps/installed/loadpassword/:key [get]
func (b *BaseApi) LoadPassword(c *gin.Context) {
// @Router /apps/installed/conninfo/:key [get]
func (b *BaseApi) LoadConnInfo(c *gin.Context) {
key, ok := c.Params.Get("key")
if !ok {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error key in path"))
return
}
password, err := appInstallService.LoadPassword(key)
conn, err := appInstallService.LoadConnInfo(key)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, password)
helper.SuccessWithData(c, conn)
}
// @Tags App

View File

@ -1,8 +1,9 @@
package response
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
)
type AppRes struct {
@ -55,6 +56,11 @@ type AppInstalledDTO struct {
CanUpdate bool `json:"canUpdate"`
}
type DatabaseConn struct {
Password string `json:"password"`
ServiceName string `json:"serviceName"`
}
type AppService struct {
Label string `json:"label"`
Value string `json:"value"`

View File

@ -148,6 +148,7 @@ type RootInfo struct {
Password string `json:"password"`
UserPassword string `json:"userPassword"`
ContainerName string `json:"containerName"`
ServiceName string `json:"serviceName"`
Param string `json:"param"`
Env string `json:"env"`
Key string `json:"key"`
@ -187,6 +188,7 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
info.Port = int64(appInstall.HttpPort)
info.HttpsPort = int64(appInstall.HttpsPort)
info.ID = appInstall.ID
info.ServiceName = appInstall.ServiceName
info.ContainerName = appInstall.ContainerName
info.Name = appInstall.Name
info.Env = appInstall.Env

View File

@ -38,7 +38,7 @@ type IAppInstallService interface {
Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error)
CheckExist(key string) (*response.AppInstalledCheck, error)
LoadPort(key string) (int64, error)
LoadPassword(key string) (string, error)
LoadConnInfo(key string) (response.DatabaseConn, error)
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error)
Operate(ctx context.Context, req request.AppInstalledOperate) error
Update(req request.AppInstalledUpdate) error
@ -133,12 +133,15 @@ func (a *AppInstallService) LoadPort(key string) (int64, error) {
return app.Port, nil
}
func (a *AppInstallService) LoadPassword(key string) (string, error) {
func (a *AppInstallService) LoadConnInfo(key string) (response.DatabaseConn, error) {
var data response.DatabaseConn
app, err := appInstallRepo.LoadBaseInfo(key, "")
if err != nil {
return "", nil
return data, nil
}
return app.Password, nil
data.Password = app.Password
data.ServiceName = app.ServiceName
return data, nil
}
func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {

View File

@ -26,7 +26,7 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) {
appRouter.GET("/installed/:appInstallId/versions", baseApi.GetUpdateVersions)
appRouter.GET("/installed/check/:key", baseApi.CheckAppInstalled)
appRouter.GET("/installed/loadport/:key", baseApi.LoadPort)
appRouter.GET("/installed/loadpassword/:key", baseApi.LoadPassword)
appRouter.GET("/installed/conninfo/:key", baseApi.LoadConnInfo)
appRouter.GET("/installed/delete/check/:appInstallId", baseApi.DeleteCheck)
appRouter.POST("/installed/search", baseApi.SearchAppInstalled)
appRouter.POST("/installed/op", baseApi.OperateInstalled)

View File

@ -326,6 +326,40 @@ var doc = `{
}
}
},
"/apps/installed/conninfo/:key": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取应用连接信息",
"consumes": [
"application/json"
],
"tags": [
"App"
],
"summary": "Search app password by key",
"parameters": [
{
"type": "string",
"description": "request",
"name": "key",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/apps/installed/delete/check/:appInstallId": {
"get": {
"security": [
@ -360,40 +394,6 @@ var doc = `{
}
}
},
"/apps/installed/loadpassword/:key": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取应用密码",
"consumes": [
"application/json"
],
"tags": [
"App"
],
"summary": "Search app password by key",
"parameters": [
{
"type": "string",
"description": "request",
"name": "key",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/apps/installed/loadport/:key": {
"get": {
"security": [
@ -9832,6 +9832,12 @@ var doc = `{
"type": "string"
}
},
"iptables": {
"type": "boolean"
},
"isSwarm": {
"type": "boolean"
},
"liveRestore": {
"type": "boolean"
},
@ -10215,6 +10221,9 @@ var doc = `{
"key"
]
},
"passPhrase": {
"type": "string"
},
"password": {
"type": "string"
},
@ -10258,9 +10267,21 @@ var doc = `{
"name": {
"type": "string"
},
"passPhrase": {
"type": "string"
},
"password": {
"type": "string"
},
"port": {
"type": "integer"
},
"privateKey": {
"type": "string"
},
"rememberPassword": {
"type": "boolean"
},
"user": {
"type": "string"
}
@ -10296,6 +10317,9 @@ var doc = `{
"name": {
"type": "string"
},
"passPhrase": {
"type": "string"
},
"password": {
"type": "string"
},
@ -10307,6 +10331,9 @@ var doc = `{
"privateKey": {
"type": "string"
},
"rememberPassword": {
"type": "boolean"
},
"user": {
"type": "string"
}
@ -11569,6 +11596,9 @@ var doc = `{
"required": {
"type": "string"
},
"resource": {
"type": "string"
},
"shortDescEn": {
"type": "string"
},
@ -12939,6 +12969,9 @@ var doc = `{
"required": {
"type": "string"
},
"resource": {
"type": "string"
},
"shortDescEn": {
"type": "string"
},
@ -13269,6 +13302,9 @@ var doc = `{
"runtimeID": {
"type": "integer"
},
"runtimeName": {
"type": "string"
},
"sitePath": {
"type": "string"
},

View File

@ -312,6 +312,40 @@
}
}
},
"/apps/installed/conninfo/:key": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取应用连接信息",
"consumes": [
"application/json"
],
"tags": [
"App"
],
"summary": "Search app password by key",
"parameters": [
{
"type": "string",
"description": "request",
"name": "key",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/apps/installed/delete/check/:appInstallId": {
"get": {
"security": [
@ -346,40 +380,6 @@
}
}
},
"/apps/installed/loadpassword/:key": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取应用密码",
"consumes": [
"application/json"
],
"tags": [
"App"
],
"summary": "Search app password by key",
"parameters": [
{
"type": "string",
"description": "request",
"name": "key",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/apps/installed/loadport/:key": {
"get": {
"security": [
@ -9818,6 +9818,12 @@
"type": "string"
}
},
"iptables": {
"type": "boolean"
},
"isSwarm": {
"type": "boolean"
},
"liveRestore": {
"type": "boolean"
},
@ -10201,6 +10207,9 @@
"key"
]
},
"passPhrase": {
"type": "string"
},
"password": {
"type": "string"
},
@ -10244,9 +10253,21 @@
"name": {
"type": "string"
},
"passPhrase": {
"type": "string"
},
"password": {
"type": "string"
},
"port": {
"type": "integer"
},
"privateKey": {
"type": "string"
},
"rememberPassword": {
"type": "boolean"
},
"user": {
"type": "string"
}
@ -10282,6 +10303,9 @@
"name": {
"type": "string"
},
"passPhrase": {
"type": "string"
},
"password": {
"type": "string"
},
@ -10293,6 +10317,9 @@
"privateKey": {
"type": "string"
},
"rememberPassword": {
"type": "boolean"
},
"user": {
"type": "string"
}
@ -11555,6 +11582,9 @@
"required": {
"type": "string"
},
"resource": {
"type": "string"
},
"shortDescEn": {
"type": "string"
},
@ -12925,6 +12955,9 @@
"required": {
"type": "string"
},
"resource": {
"type": "string"
},
"shortDescEn": {
"type": "string"
},
@ -13255,6 +13288,9 @@
"runtimeID": {
"type": "integer"
},
"runtimeName": {
"type": "string"
},
"sitePath": {
"type": "string"
},

View File

@ -448,6 +448,10 @@ definitions:
items:
type: string
type: array
iptables:
type: boolean
isSwarm:
type: boolean
liveRestore:
type: boolean
registryMirrors:
@ -701,6 +705,8 @@ definitions:
- password
- key
type: string
passPhrase:
type: string
password:
type: string
port:
@ -734,8 +740,16 @@ definitions:
type: integer
name:
type: string
passPhrase:
type: string
password:
type: string
port:
type: integer
privateKey:
type: string
rememberPassword:
type: boolean
user:
type: string
type: object
@ -756,6 +770,8 @@ definitions:
type: integer
name:
type: string
passPhrase:
type: string
password:
type: string
port:
@ -764,6 +780,8 @@ definitions:
type: integer
privateKey:
type: string
rememberPassword:
type: boolean
user:
type: string
required:
@ -1605,6 +1623,8 @@ definitions:
type: integer
required:
type: string
resource:
type: string
shortDescEn:
type: string
shortDescZh:
@ -2520,6 +2540,8 @@ definitions:
type: integer
required:
type: string
resource:
type: string
shortDescEn:
type: string
shortDescZh:
@ -2738,6 +2760,8 @@ definitions:
type: string
runtimeID:
type: integer
runtimeName:
type: string
sitePath:
type: string
status:
@ -2991,6 +3015,27 @@ paths:
summary: Search default config by key
tags:
- App
/apps/installed/conninfo/:key:
get:
consumes:
- application/json
description: 获取应用连接信息
parameters:
- description: request
in: path
name: key
required: true
type: string
responses:
"200":
description: OK
schema:
type: string
security:
- ApiKeyAuth: []
summary: Search app password by key
tags:
- App
/apps/installed/delete/check/:appInstallId:
get:
consumes:
@ -3012,27 +3057,6 @@ paths:
summary: Check before delete
tags:
- App
/apps/installed/loadpassword/:key:
get:
consumes:
- application/json
description: 获取应用密码
parameters:
- description: request
in: path
name: key
required: true
type: string
responses:
"200":
description: OK
schema:
type: string
security:
- ApiKeyAuth: []
summary: Search app password by key
tags:
- App
/apps/installed/loadport/:key:
get:
consumes:

View File

@ -127,6 +127,10 @@ export namespace App {
installPath: string;
}
export interface DatabaseConnInfo {
password: string;
serviceName: string;
}
export interface AppInstallResource {
type: string;
name: string;

View File

@ -46,8 +46,8 @@ export const GetAppPort = (key: string) => {
return http.get<number>(`apps/installed/loadport/${key}`);
};
export const GetAppPassword = (key: string) => {
return http.get<string>(`apps/installed/loadpassword/${key}`);
export const GetAppConnInfo = (key: string) => {
return http.get<App.DatabaseConnInfo>(`apps/installed/conninfo/${key}`);
};
export const CheckAppInstalled = (key: string) => {

View File

@ -294,7 +294,10 @@ const message = {
permission: 'Permission',
permissionForIP: 'IP',
permissionAll: 'All of them(%)',
databaseConnInfo: 'Conn info',
rootPassword: 'Root password',
serviceName: 'Service Name',
serviceNameHelper: 'Access between containers in the same network.',
backupList: 'Backup',
backList: 'Return',
loadBackup: 'Import',

View File

@ -299,7 +299,10 @@ const message = {
permission: '权限',
permissionForIP: '指定 IP',
permissionAll: '所有人(%)',
databaseConnInfo: '连接信息',
rootPassword: 'root 密码',
serviceName: '服务名称',
serviceNameHelper: '用于同一 network 下的容器间访问',
backupList: '备份列表',
backList: '返回列表',
loadBackup: '导入备份',

View File

@ -18,7 +18,7 @@
{{ $t('database.create') }}
</el-button>
<el-button @click="onChangeRootPassword" type="primary" plain>
{{ $t('database.rootPassword') }}
{{ $t('database.databaseConnInfo') }}
</el-button>
<el-button @click="onChangeAccess" type="primary" plain>
{{ $t('database.remoteAccess') }}

View File

@ -1,7 +1,7 @@
<template>
<el-drawer v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header>
<DrawerHeader :header="$t('database.rootPassword')" :back="handleClose" />
<DrawerHeader :header="$t('database.databaseConnInfo')" :back="handleClose" />
</template>
<el-form v-loading="loading" ref="formRef" :model="form" label-position="top">
<el-row type="flex" justify="center">
@ -14,6 +14,10 @@
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('database.serviceName')" prop="serviceName">
<el-tag>{{ form.serviceName }}</el-tag>
<span class="input-help">{{ $t('database.serviceNameHelper') }}</span>
</el-form-item>
</el-col>
</el-row>
</el-form>
@ -34,22 +38,24 @@
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { ref } from 'vue';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { ElForm } from 'element-plus';
import { updateMysqlPassword } from '@/api/modules/database';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { GetAppPassword } from '@/api/modules/app';
import { GetAppConnInfo } from '@/api/modules/app';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { MsgSuccess } from '@/utils/message';
import { getRandomStr } from '@/utils/util';
import { App } from '@/api/interface/app';
const loading = ref(false);
const dialogVisiable = ref(false);
const form = reactive({
const form = ref<App.DatabaseConnInfo>({
password: '',
serviceName: '',
});
const confirmDialogRef = ref();
@ -58,18 +64,18 @@ type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
const acceptParams = (): void => {
form.password = '';
form.value.password = '';
loadPassword();
dialogVisiable.value = true;
};
const random = async () => {
form.password = getRandomStr(16);
form.value.password = getRandomStr(16);
};
const copy = async () => {
let input = document.createElement('input');
input.value = form.password;
input.value = form.value.password;
document.body.appendChild(input);
input.select();
document.execCommand('Copy');
@ -82,14 +88,14 @@ const handleClose = () => {
};
const loadPassword = async () => {
const res = await GetAppPassword('mysql');
form.password = res.data;
const res = await GetAppConnInfo('mysql');
form.value = res.data;
};
const onSubmit = async () => {
let param = {
id: 0,
value: form.password,
value: form.value.password,
};
loading.value = true;
await updateMysqlPassword(param)

View File

@ -15,7 +15,7 @@
<div :class="{ mask: redisStatus != 'Running' }">
<el-button type="primary" plain @click="goDashboard" icon="Position">Redis-Commander</el-button>
<el-button type="primary" plain @click="onChangePassword">
{{ $t('database.changePassword') }}
{{ $t('database.databaseConnInfo') }}
</el-button>
</div>
</template>

View File

@ -1,13 +1,22 @@
<template>
<el-drawer v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
<template #header>
<DrawerHeader :header="$t('database.requirepass')" :back="handleClose" />
<DrawerHeader :header="$t('database.databaseConnInfo')" :back="handleClose" />
</template>
<el-form v-loading="loading" ref="formRef" :model="form" label-position="top">
<el-row type="flex" justify="center">
<el-col :span="22">
<el-form-item :label="$t('database.requirepass')" :rules="Rules.requiredInput" prop="password">
<el-input type="password" show-password clearable v-model="form.password" />
<el-input type="password" show-password clearable v-model="form.password">
<template #append>
<el-button @click="copy" icon="DocumentCopy"></el-button>
<el-button style="margin-left: 1px" @click="random" icon="RefreshRight"></el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('database.serviceName')" prop="serviceName">
<el-tag>{{ form.serviceName }}</el-tag>
<span class="input-help">{{ $t('database.serviceNameHelper') }}</span>
</el-form-item>
</el-col>
</el-row>
@ -29,21 +38,24 @@
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { ref } from 'vue';
import { Rules } from '@/global/form-rules';
import i18n from '@/lang';
import { ElForm } from 'element-plus';
import { changeRedisPassword } from '@/api/modules/database';
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import { GetAppPassword } from '@/api/modules/app';
import { GetAppConnInfo } from '@/api/modules/app';
import { MsgSuccess } from '@/utils/message';
import DrawerHeader from '@/components/drawer-header/index.vue';
import { App } from '@/api/interface/app';
import { getRandomStr } from '@/utils/util';
const loading = ref(false);
const dialogVisiable = ref(false);
const form = reactive({
const form = ref<App.DatabaseConnInfo>({
password: '',
serviceName: '',
});
const confirmDialogRef = ref();
@ -54,7 +66,7 @@ type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>();
const acceptParams = (): void => {
form.password = '';
form.value.password = '';
loadPassword();
dialogVisiable.value = true;
};
@ -62,15 +74,29 @@ const handleClose = () => {
dialogVisiable.value = false;
};
const random = async () => {
form.value.password = getRandomStr(16);
};
const copy = async () => {
let input = document.createElement('input');
input.value = form.value.password;
document.body.appendChild(input);
input.select();
document.execCommand('Copy');
document.body.removeChild(input);
MsgSuccess(i18n.global.t('commons.msg.copySuccess'));
};
const loadPassword = async () => {
const res = await GetAppPassword('redis');
form.password = res.data;
const res = await GetAppConnInfo('redis');
form.value = res.data;
};
const onSubmit = async () => {
let param = {
id: 0,
value: form.password,
value: form.value.password,
};
loading.value = true;
emit('closeTerminal');