mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-09 11:55:52 +08:00
fix: Merge dev code up to pr-8598 (#8602)
This commit is contained in:
parent
ac922ae879
commit
32b9b3f31f
35 changed files with 242 additions and 191 deletions
|
|
@ -410,11 +410,20 @@ func (b *BaseApi) CheckFile(c *gin.Context) {
|
|||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if _, err := os.Stat(req.Path); err != nil {
|
||||
helper.SuccessWithData(c, false)
|
||||
fileOp := files.NewFileOp()
|
||||
if fileOp.Stat(req.Path) {
|
||||
helper.SuccessWithData(c, true)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, true)
|
||||
if req.WithInit {
|
||||
if err := fileOp.CreateDir(req.Path, 0644); err != nil {
|
||||
helper.SuccessWithData(c, false)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, true)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, false)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
|
|
|
|||
|
|
@ -59,10 +59,8 @@ func (b *BaseApi) WsSSH(c *gin.Context) {
|
|||
|
||||
<-quitChan
|
||||
|
||||
global.LOG.Info("websocket finished")
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
dt := time.Now().Add(time.Second)
|
||||
_ = wsConn.WriteControl(websocket.CloseMessage, nil, dt)
|
||||
}
|
||||
|
||||
func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
|
||||
|
|
@ -125,9 +123,8 @@ func (b *BaseApi) ContainerWsSSH(c *gin.Context) {
|
|||
<-quitChan
|
||||
|
||||
global.LOG.Info("websocket finished")
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
dt := time.Now().Add(time.Second)
|
||||
_ = wsConn.WriteControl(websocket.CloseMessage, nil, dt)
|
||||
}
|
||||
|
||||
func loadRedisInitCmd(c *gin.Context) (string, []string, error) {
|
||||
|
|
|
|||
|
|
@ -76,7 +76,8 @@ type FileRename struct {
|
|||
}
|
||||
|
||||
type FilePathCheck struct {
|
||||
Path string `json:"path" validate:"required"`
|
||||
Path string `json:"path" validate:"required"`
|
||||
WithInit bool `json:"withInit"`
|
||||
}
|
||||
|
||||
type FilePathsCheck struct {
|
||||
|
|
|
|||
|
|
@ -869,6 +869,9 @@ func updateInstallInfoInDB(appKey, appName, param string, value interface{}) err
|
|||
"param": strings.ReplaceAll(appInstall.Param, oldVal, newVal),
|
||||
"env": strings.ReplaceAll(appInstall.Env, oldVal, newVal),
|
||||
}, repo.WithByID(appInstall.ID))
|
||||
if appKey == "mysql" || appKey == "postgresql" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if param == "user-password" {
|
||||
oldVal = fmt.Sprintf("\"PANEL_DB_USER_PASSWORD\":\"%v\"", appInstall.UserPassword)
|
||||
|
|
|
|||
|
|
@ -210,7 +210,9 @@ func (u *CronjobService) CleanRecord(req dto.CronjobClean) error {
|
|||
}
|
||||
}
|
||||
cronjob.RetainCopies = 0
|
||||
u.removeExpiredBackup(cronjob, accountMap, model.BackupRecord{})
|
||||
if len(accountMap) != 0 {
|
||||
u.removeExpiredBackup(cronjob, accountMap, model.BackupRecord{})
|
||||
}
|
||||
}
|
||||
}
|
||||
if req.IsDelete {
|
||||
|
|
|
|||
|
|
@ -258,7 +258,8 @@ func (u *CronjobService) uploadCronjobBackFile(cronjob model.Cronjob, accountMap
|
|||
if len(account) != 0 {
|
||||
global.LOG.Debugf("start upload file to %s, dir: %s", accountMap[account].name, pathUtils.Join(accountMap[account].backupPath, cloudSrc))
|
||||
if _, err := accountMap[account].client.Upload(file, pathUtils.Join(accountMap[account].backupPath, cloudSrc)); err != nil {
|
||||
return "", err
|
||||
global.LOG.Errorf("upload file to %s failed, err: %v", accountMap[account].name, err)
|
||||
continue
|
||||
}
|
||||
global.LOG.Debugf("upload successful!")
|
||||
}
|
||||
|
|
@ -285,6 +286,9 @@ func (u *CronjobService) removeExpiredBackup(cronjob model.Cronjob, accountMap m
|
|||
if cronjob.Type == "snapshot" {
|
||||
for _, account := range accounts {
|
||||
if len(account) != 0 {
|
||||
if _, ok := accountMap[account]; !ok {
|
||||
continue
|
||||
}
|
||||
_, _ = accountMap[account].client.Delete(pathUtils.Join(accountMap[account].backupPath, "system_snapshot", records[i].FileName))
|
||||
}
|
||||
}
|
||||
|
|
@ -292,6 +296,9 @@ func (u *CronjobService) removeExpiredBackup(cronjob model.Cronjob, accountMap m
|
|||
} else {
|
||||
for _, account := range accounts {
|
||||
if len(account) != 0 {
|
||||
if _, ok := accountMap[account]; !ok {
|
||||
continue
|
||||
}
|
||||
_, _ = accountMap[account].client.Delete(pathUtils.Join(accountMap[account].backupPath, records[i].FileDir, records[i].FileName))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -316,9 +316,8 @@ func (b *BaseApi) WsSsh(c *gin.Context) {
|
|||
|
||||
<-quitChan
|
||||
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
dt := time.Now().Add(time.Second)
|
||||
_ = wsConn.WriteControl(websocket.CloseMessage, nil, dt)
|
||||
}
|
||||
|
||||
var upGrader = websocket.Upgrader{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/core/app/api/v2/helper"
|
||||
"github.com/1Panel-dev/1Panel/core/app/dto"
|
||||
|
|
@ -15,6 +16,7 @@ import (
|
|||
"github.com/1Panel-dev/1Panel/core/utils/terminal"
|
||||
"github.com/1Panel-dev/1Panel/core/utils/xpack"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
|
@ -216,7 +218,7 @@ func (b *BaseApi) RunScript(c *gin.Context) {
|
|||
<-quitChan
|
||||
|
||||
global.LOG.Info("websocket finished")
|
||||
if wshandleError(wsConn, err) {
|
||||
return
|
||||
}
|
||||
global.LOG.Info("websocket finished")
|
||||
dt := time.Now().Add(time.Second)
|
||||
_ = wsConn.WriteControl(websocket.CloseMessage, nil, dt)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,4 +99,5 @@ func (lcmd *LocalCommand) Wait(quitChan chan bool) {
|
|||
global.LOG.Errorf("ssh session wait failed, err: %v", err)
|
||||
setQuit(quitChan)
|
||||
}
|
||||
setQuit(quitChan)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ export const saveFileContent = (params: File.FileEdit) => {
|
|||
return http.post<File.File>('files/save', params);
|
||||
};
|
||||
|
||||
export const checkFile = (path: string) => {
|
||||
return http.post<boolean>('files/check', { path: path });
|
||||
export const checkFile = (path: string, withInit: boolean) => {
|
||||
return http.post<boolean>('files/check', { path: path, withInit: withInit });
|
||||
};
|
||||
|
||||
export const uploadFileData = (params: FormData, config: AxiosRequestConfig) => {
|
||||
|
|
|
|||
|
|
@ -124,7 +124,9 @@ function onClose(isKeepShow: boolean = false) {
|
|||
term.value.dispose();
|
||||
} catch {}
|
||||
}
|
||||
terminalElement.value.innerHTML = '';
|
||||
if (terminalElement.value) {
|
||||
terminalElement.value.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
// terminal 相关代码 start
|
||||
|
|
@ -224,8 +226,8 @@ const closeRealTerminal = (ev: CloseEvent) => {
|
|||
if (heartbeatTimer.value) {
|
||||
clearInterval(Number(heartbeatTimer.value));
|
||||
}
|
||||
term.value.write('The connection has been disconnected.');
|
||||
term.value.write(ev.reason);
|
||||
term.value?.write('The connection has been disconnected.');
|
||||
term.value?.write(ev.reason);
|
||||
};
|
||||
|
||||
const isWsOpen = () => {
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ const onSubmit = async () => {
|
|||
MsgError(i18n.global.t('commons.msg.fileNameErr'));
|
||||
return;
|
||||
}
|
||||
const res = await checkFile(baseDir.value + file.raw.name);
|
||||
const res = await checkFile(baseDir.value + file.raw.name, false);
|
||||
if (res.data) {
|
||||
MsgError(i18n.global.t('commons.msg.fileExist'));
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -138,7 +138,8 @@ const checkIllegal = (rule: any, value: any, callback: any) => {
|
|||
value.indexOf('`') !== -1 ||
|
||||
value.indexOf('(') !== -1 ||
|
||||
value.indexOf(')') !== -1 ||
|
||||
value.indexOf("'") !== -1
|
||||
value.indexOf('>') !== -1 ||
|
||||
value.indexOf('<') !== -1
|
||||
) {
|
||||
callback(new Error(i18n.global.t('commons.rule.illegalInput')));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -207,6 +207,7 @@ const message = {
|
|||
rePassword: 'The passwords are inconsistent. Please check and re-enter the password',
|
||||
requiredInput: 'Please enter the required fields',
|
||||
requiredSelect: 'Please select the required fields',
|
||||
illegalChar: 'Injection of characters & ; $ \' ` ( ) " > < | is currently not supported',
|
||||
illegalInput: 'There are illegal characters in the input box.',
|
||||
commonName:
|
||||
'Supports non-special characters starting with English, Chinese, numbers, .- and _, length 1-128',
|
||||
|
|
@ -441,6 +442,8 @@ const message = {
|
|||
permission: 'Permission',
|
||||
permissionForIP: 'IP',
|
||||
permissionAll: 'All of them(%)',
|
||||
localhostHelper:
|
||||
'Configuring database permissions as "localhost" for container deployment will prevent external access to the container. Please choose carefully!',
|
||||
databaseConnInfo: 'Conn info',
|
||||
rootPassword: 'Root password',
|
||||
serviceName: 'Service Name',
|
||||
|
|
@ -452,6 +455,7 @@ const message = {
|
|||
remoteConnHelper:
|
||||
'Remote connection to mysql as user root may have security risks. Therefore, perform this operation with caution.',
|
||||
changePassword: 'Password',
|
||||
changeConnHelper: 'This operation will modify the current database {0}. Do you want to continue?',
|
||||
changePasswordHelper:
|
||||
'The database has been associated with an application. Changing the password will change the database password of the application at the same time. The change takes effect after the application restarts.',
|
||||
|
||||
|
|
@ -1457,6 +1461,7 @@ const message = {
|
|||
existFileHelper: 'The uploaded file contains a file with the same name, do you want to overwrite it?',
|
||||
existFileSize: 'File size (new -> old)',
|
||||
existFileDirHelper: 'The selected file/folder has a duplicate name. Please proceed with caution!',
|
||||
noSuchFile: 'The file or directory was not found. Please check and try again.',
|
||||
},
|
||||
ssh: {
|
||||
autoStart: 'Auto Start',
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ const message = {
|
|||
rePassword: 'パスワードがパスワードと矛盾することを確認してください。',
|
||||
requiredInput: 'この項目は必須です。',
|
||||
requiredSelect: 'リスト内のアイテムを選択します',
|
||||
illegalChar: '現在、文字 & ; $ \' ` ( ) " > < | の注入はサポートされていません',
|
||||
illegalInput: `このフィールドには違法なキャラクターが含まれてはなりません。`,
|
||||
commonName:
|
||||
'このフィールドは、特別なキャラクターではなく、英語、中国語、数字で構成されている必要があります。「。」、「」、および「_」文字が1〜128の文字で構成されている必要があります。',
|
||||
|
|
@ -430,6 +431,8 @@ const message = {
|
|||
permission: '権限',
|
||||
permissionForIP: 'ip',
|
||||
permissionAll: 'それらすべて(%)',
|
||||
localhostHelper:
|
||||
'コンテナ展開でデータベース権限を"localhost"に設定すると、コンテナ外部からのアクセスができなくなります。慎重に選択してください!',
|
||||
databaseConnInfo: '接続情報',
|
||||
rootPassword: 'ルートパスワード',
|
||||
serviceName: 'サービス名',
|
||||
|
|
@ -441,6 +444,7 @@ const message = {
|
|||
remoteConnHelper:
|
||||
'ユーザールートとしてのMySQLへのリモート接続には、セキュリティリスクがある場合があります。したがって、この操作を慎重に実行します。',
|
||||
changePassword: 'パスワード',
|
||||
changeConnHelper: 'この操作は現在のデータベース {0} を変更します。続行しますか?',
|
||||
changePasswordHelper:
|
||||
'データベースはアプリケーションに関連付けられています。パスワードを変更すると、アプリケーションのデータベースパスワードが同時に変更されます。アプリケーションが再起動した後、変更は有効になります。',
|
||||
|
||||
|
|
@ -1398,6 +1402,7 @@ const message = {
|
|||
existFileHelper: 'アップロードしたファイルに同じ名前のファイルが含まれています。上書きしますか?',
|
||||
existFileSize: 'ファイルサイズ(新しい -> 古い)',
|
||||
existFileDirHelper: '選択したファイル/フォルダーには同じ名前のものが既に存在します。慎重に操作してください!',
|
||||
noSuchFile: 'ファイルまたはディレクトリが見つかりませんでした。確認して再試行してください。',
|
||||
},
|
||||
ssh: {
|
||||
setting: '設定',
|
||||
|
|
|
|||
|
|
@ -196,6 +196,7 @@ const message = {
|
|||
rePassword: '확인 비밀번호가 비밀번호와 일치하지 않습니다.',
|
||||
requiredInput: '이 필드는 필수 항목입니다.',
|
||||
requiredSelect: '목록에서 항목을 선택하세요',
|
||||
illegalChar: '현재 & ; $ \' ` ( ) " > < | 문자 주입은 지원되지 않습니다',
|
||||
illegalInput: '이 필드에는 유효하지 않은 문자가 포함될 수 없습니다.',
|
||||
commonName:
|
||||
'이 필드는 특수 문자로 시작할 수 없으며, 영어, 한자, 숫자, ".", "-", "_" 문자로 구성되어야 하며 길이는 1-128자여야 합니다.',
|
||||
|
|
@ -433,6 +434,8 @@ const message = {
|
|||
permission: '권한',
|
||||
permissionForIP: 'IP',
|
||||
permissionAll: '모두(%)',
|
||||
localhostHelper:
|
||||
'컨테이너 배포 시 데이터베이스 권한을 "localhost"로 설정하면 컨테이너 외부에서 접근할 수 없게 됩니다. 신중하게 선택하세요!',
|
||||
databaseConnInfo: '연결 정보',
|
||||
rootPassword: '루트 비밀번호',
|
||||
serviceName: '서비스 이름',
|
||||
|
|
@ -444,6 +447,7 @@ const message = {
|
|||
remoteConnHelper:
|
||||
'MySQL 의 root 사용자로 원격 접속은 보안 위험을 초래할 수 있습니다. 따라서 이 작업은 신중히 수행해야 합니다.',
|
||||
changePassword: '비밀번호',
|
||||
changeConnHelper: '이 작업은 현재 데이터베이스 {0}을(를) 수정합니다. 계속하시겠습니까?',
|
||||
changePasswordHelper:
|
||||
'데이터베이스가 애플리케이션과 연결되어 있습니다. 비밀번호를 변경하면 애플리케이션의 데이터베이스 비밀번호도 변경됩니다. 변경 사항은 애플리케이션이 재시작된 후에 적용됩니다.',
|
||||
confChange: '설정',
|
||||
|
|
@ -1384,6 +1388,7 @@ const message = {
|
|||
existFileHelper: '업로드한 파일에 동일한 이름의 파일이 포함되어 있습니다. 덮어쓰시겠습니까?',
|
||||
existFileSize: '파일 크기 (새로운 -> 오래된)',
|
||||
existFileDirHelper: '선택한 파일/폴더에 동일한 이름이 이미 존재합니다. 신중하게 작업하세요!',
|
||||
noSuchFile: '파일 또는 디렉터리를 찾을 수 없습니다. 확인 후 다시 시도하세요.',
|
||||
},
|
||||
ssh: {
|
||||
setting: '설정',
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ const message = {
|
|||
rePassword: 'Pengesahan kata laluan tidak sepadan dengan kata laluan.',
|
||||
requiredInput: 'Ruangan ini wajib diisi.',
|
||||
requiredSelect: 'Pilih satu item dalam senarai',
|
||||
illegalChar: 'Suntikan aksara & ; $ \' ` ( ) " > < | tidak disokong buat masa ini',
|
||||
illegalInput: 'Ruangan ini tidak boleh mengandungi aksara tidak sah.',
|
||||
commonName:
|
||||
'Ruangan ini mesti bermula dengan aksara bukan khas dan mesti terdiri daripada aksara rumi, Cina, nombor, ".", "-", dan "_" dengan panjang 1-128 aksara.',
|
||||
|
|
@ -439,6 +440,8 @@ const message = {
|
|||
permission: 'Kebenaran',
|
||||
permissionForIP: 'IP',
|
||||
permissionAll: 'Kesemuanya(%)',
|
||||
localhostHelper:
|
||||
'Mengkonfigurasi kebenaran pangkalan data sebagai "localhost" untuk penyebaran kontena akan menghalang akses luar ke kontena. Sila pilih dengan teliti!',
|
||||
databaseConnInfo: 'Maklumat sambungan',
|
||||
rootPassword: 'Kata laluan root',
|
||||
serviceName: 'Nama Perkhidmatan',
|
||||
|
|
@ -450,6 +453,7 @@ const message = {
|
|||
remoteConnHelper:
|
||||
'Sambungan jauh ke MySQL sebagai pengguna root mungkin mempunyai risiko keselamatan. Oleh itu, lakukan operasi ini dengan berhati-hati.',
|
||||
changePassword: 'Kata laluan',
|
||||
changeConnHelper: 'Operasi ini akan mengubah pangkalan data semasa {0}. Adakah anda ingin meneruskan?',
|
||||
changePasswordHelper:
|
||||
'Pangkalan data telah dikaitkan dengan aplikasi. Menukar kata laluan akan menukar kata laluan pangkalan data aplikasi pada masa yang sama. Perubahan ini akan berkuat kuasa selepas aplikasi dimulakan semula.',
|
||||
|
||||
|
|
@ -1442,6 +1446,7 @@ const message = {
|
|||
existFileHelper: 'Fail yang dimuat naik mengandungi fail dengan nama yang sama. Adakah anda mahu menimpanya?',
|
||||
existFileSize: 'Saiz fail (baru -> lama)',
|
||||
existFileDirHelper: 'Fail/folder yang dipilih mempunyai nama yang sama. Sila berhati-hati!',
|
||||
noSuchFile: 'Fail atau direktori tidak ditemui. Sila periksa dan cuba lagi.',
|
||||
},
|
||||
ssh: {
|
||||
setting: 'tetapan',
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ const message = {
|
|||
rePassword: 'A confirmação da senha não corresponde à senha.',
|
||||
requiredInput: 'Este campo é obrigatório.',
|
||||
requiredSelect: 'Selecione um item na lista',
|
||||
illegalChar: 'Atualmente não há suporte para injeção dos caracteres & ; $ \' ` ( ) " > < |',
|
||||
illegalInput: 'Este campo não deve conter caracteres ilegais.',
|
||||
commonName:
|
||||
'Este campo deve começar com caracteres não especiais e consistir em letras, números, ".", "-", e "_" com comprimento de 1-128.',
|
||||
|
|
@ -437,6 +438,8 @@ const message = {
|
|||
permission: 'Permissões',
|
||||
permissionForIP: 'IP',
|
||||
permissionAll: 'Todos (% de)',
|
||||
localhostHelper:
|
||||
'Configurar permissões de banco de dados como "localhost" para implantação em contêiner impedirá o acesso externo ao contêiner. Por favor, escolha com cuidado!',
|
||||
databaseConnInfo: 'Informações de conexão',
|
||||
rootPassword: 'Senha root',
|
||||
serviceName: 'Nome do serviço',
|
||||
|
|
@ -448,6 +451,7 @@ const message = {
|
|||
remoteConnHelper:
|
||||
'Conectar-se ao MySQL como usuário root pode representar riscos de segurança. Realize esta operação com cautela.',
|
||||
changePassword: 'Senha',
|
||||
changeConnHelper: 'Esta operação modificará o banco de dados atual {0}. Deseja continuar?',
|
||||
changePasswordHelper:
|
||||
'O banco de dados está associado a um aplicativo. Alterar a senha alterará a senha do banco de dados do aplicativo ao mesmo tempo. A mudança surtirá efeito após a reinicialização do aplicativo.',
|
||||
|
||||
|
|
@ -1428,6 +1432,7 @@ const message = {
|
|||
existFileHelper: 'O arquivo enviado contém um arquivo com o mesmo nome. Deseja substituí-lo?',
|
||||
existFileSize: 'Tamanho do arquivo (novo -> antigo)',
|
||||
existFileDirHelper: 'O arquivo/pasta selecionado tem um nome duplicado. Por favor, prossiga com cautela!',
|
||||
noSuchFile: 'O arquivo ou diretório não foi encontrado. Por favor, verifique e tente novamente.',
|
||||
},
|
||||
ssh: {
|
||||
setting: 'configuração',
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ const message = {
|
|||
rePassword: 'Подтверждение пароля не совпадает с паролем.',
|
||||
requiredInput: 'Это поле обязательно для заполнения.',
|
||||
requiredSelect: 'Выберите элемент из списка',
|
||||
illegalChar: 'В настоящее время не поддерживается вставка символов & ; $ \' ` ( ) " > < |',
|
||||
illegalInput: 'Это поле не должно содержать недопустимых символов.',
|
||||
commonName:
|
||||
'Это поле должно начинаться с неспециальных символов и должно состоять из английских букв, китайских иероглифов, цифр, ".", "-" и "_" длиной 1-128.',
|
||||
|
|
@ -1431,6 +1432,7 @@ const message = {
|
|||
existFileHelper: 'Загруженный файл содержит файл с таким же именем. Заменить его?',
|
||||
existFileSize: 'Размер файла (новый -> старый)',
|
||||
existFileDirHelper: 'Выбранный файл/папка имеет дублирующееся имя. Пожалуйста, действуйте осторожно!',
|
||||
noSuchFile: 'Файл или каталог не найдены. Пожалуйста, проверьте и повторите попытку.',
|
||||
},
|
||||
ssh: {
|
||||
setting: 'настройка',
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ const message = {
|
|||
rePassword: '密碼不一致,請檢查後重新輸入',
|
||||
requiredInput: '請填寫必填項',
|
||||
requiredSelect: '請選擇必選項',
|
||||
illegalChar: '暫不支援注入字元 & ; $ \' ` ( ) " > < |',
|
||||
illegalInput: '輸入框中存在不合法字符',
|
||||
commonName: '支持非特殊字元開頭,英文、中文、數字、.-和_,長度1-128',
|
||||
userName: '支持非特殊字符開頭、英文、中文、數字和_,長度3-30',
|
||||
|
|
@ -433,6 +434,7 @@ const message = {
|
|||
permission: '權限',
|
||||
permissionForIP: '指定 IP',
|
||||
permissionAll: '所有人(%)',
|
||||
localhostHelper: '將容器部署的資料庫權限配置為"localhost"會導致容器外部無法存取,請謹慎選擇!',
|
||||
databaseConnInfo: '連接信息',
|
||||
rootPassword: 'root 密碼',
|
||||
serviceName: '服務名稱',
|
||||
|
|
@ -443,6 +445,7 @@ const message = {
|
|||
remoteHelper: '多個 ip 以逗號分隔,例:172.16.10.111,172.16.10.112',
|
||||
remoteConnHelper: 'root 帳號遠程連接 mysql 有安全風險,開啟需謹慎!',
|
||||
changePassword: '改密',
|
||||
changeConnHelper: '此操作將修改當前資料庫 {0},是否繼續?',
|
||||
changePasswordHelper: '當前數據庫已經關聯應用,修改密碼將同步修改應用中數據庫密碼,修改後重啟生效。',
|
||||
|
||||
portHelper: '該端口為容器對外暴露端口,修改需要單獨保存並且重啟容器!',
|
||||
|
|
@ -1384,6 +1387,7 @@ const message = {
|
|||
existFileHelper: '上傳的檔案存在同名檔案,是否覆蓋?',
|
||||
existFileSize: '文件大小(新->舊)',
|
||||
existFileDirHelper: '選擇的檔案/資料夾存在同名,請謹慎操作!',
|
||||
noSuchFile: '找不到該檔案或目錄,請檢查後重試。',
|
||||
},
|
||||
ssh: {
|
||||
autoStart: '開機自啟',
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ const message = {
|
|||
rePassword: '密码不一致,请检查后重新输入',
|
||||
requiredInput: '请填写必填项',
|
||||
requiredSelect: '请选择必选项',
|
||||
illegalChar: '暂不支持注入字符 & ; $ \' ` ( ) " > < |',
|
||||
illegalInput: '输入框中存在不合法字符',
|
||||
commonName: '支持非特殊字符开头,英文、中文、数字、.-和_,长度1-128',
|
||||
userName: '支持非特殊字符开头、英文、中文、数字和_,长度3-30',
|
||||
|
|
@ -431,6 +432,7 @@ const message = {
|
|||
permission: '权限',
|
||||
permissionForIP: '指定 IP',
|
||||
permissionAll: '所有人(%)',
|
||||
localhostHelper: '将容器部署的数据库权限配置为 localhost 会导致容器外部无法访问,请谨慎选择!',
|
||||
databaseConnInfo: '连接信息',
|
||||
rootPassword: 'root 密码',
|
||||
serviceName: '服务名称',
|
||||
|
|
@ -441,6 +443,7 @@ const message = {
|
|||
remoteHelper: '多个 ip 以逗号分隔,例:172.16.10.111,172.16.10.112',
|
||||
remoteConnHelper: 'root 帐号远程连接 mysql 有安全风险,开启需谨慎!',
|
||||
changePassword: '改密',
|
||||
changeConnHelper: '此操作将修改当前数据库 {0},是否继续?',
|
||||
changePasswordHelper: '当前数据库已经关联应用,修改密码将同步修改应用中数据库密码,修改后重启生效。',
|
||||
|
||||
portHelper: '该端口为容器对外暴露端口,修改需要单独保存并且重启容器!',
|
||||
|
|
@ -1380,6 +1383,7 @@ const message = {
|
|||
existFileHelper: '上传的文件存在同名文件,是否覆盖?',
|
||||
existFileSize: '文件大小 (新 -> 旧)',
|
||||
existFileDirHelper: '选择的文件/文件夹存在同名,请谨慎操作!',
|
||||
noSuchFile: '未能找到该文件或目录,请检查后重试',
|
||||
},
|
||||
ssh: {
|
||||
autoStart: '开机自启',
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ const onDelete = async (row: Cronjob.CronjobInfo | null) => {
|
|||
let ids = [];
|
||||
showClean.value = false;
|
||||
cleanData.value = false;
|
||||
cleanRemoteData.value = true;
|
||||
if (row) {
|
||||
ids = [row.id];
|
||||
names = [row.name];
|
||||
|
|
|
|||
|
|
@ -13,13 +13,21 @@
|
|||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.login.password')" prop="password">
|
||||
<el-input type="password" clearable show-password v-model="form.password"></el-input>
|
||||
<span class="input-help">{{ $t('commons.rule.illegalChar') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('database.permission')" prop="permission">
|
||||
<el-select v-model="form.permission">
|
||||
<el-option value="%" :label="$t('database.permissionAll')" />
|
||||
<el-option v-if="form.from !== 'local'" value="localhost" :label="$t('terminal.localhost')" />
|
||||
<el-option
|
||||
v-if="form.from !== 'local'"
|
||||
value="localhost"
|
||||
:label="$t('terminal.localhost') + '(localhost)'"
|
||||
/>
|
||||
<el-option value="ip" :label="$t('database.permissionForIP')" />
|
||||
</el-select>
|
||||
<span v-if="form.from !== 'local'" class="input-help">
|
||||
{{ $t('database.localhostHelper') }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.permission === 'ip'" prop="permissionIPs">
|
||||
<el-input clearable :rows="3" type="textarea" v-model="form.permissionIPs" />
|
||||
|
|
@ -47,7 +55,6 @@ import { ElForm } from 'element-plus';
|
|||
import { bindUser } from '@/api/modules/database';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { checkIp } from '@/utils/util';
|
||||
|
||||
const loading = ref();
|
||||
const bindVisible = ref(false);
|
||||
|
|
@ -66,21 +73,11 @@ const confirmDialogRef = ref();
|
|||
|
||||
const rules = reactive({
|
||||
username: [Rules.requiredInput, Rules.name],
|
||||
password: [Rules.paramComplexity],
|
||||
password: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
permission: [Rules.requiredSelect],
|
||||
permissionIPs: [{ validator: checkIPs, trigger: 'blur', required: true }],
|
||||
permissionIPs: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
});
|
||||
|
||||
function checkIPs(rule: any, value: any, callback: any) {
|
||||
let ips = form.permissionIPs.split(',');
|
||||
for (const item of ips) {
|
||||
if (checkIp(item)) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.ip')));
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
interface DialogProps {
|
||||
from: string;
|
||||
database: string;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<DrawerPro v-model="dialogVisible" :header="$t('database.databaseConnInfo')" @close="handleClose" size="small">
|
||||
<el-form @submit.prevent v-loading="loading" ref="formRef" :model="form" label-position="top">
|
||||
<el-form @submit.prevent v-loading="loading" ref="formRef" :rules="rules" :model="form" label-position="top">
|
||||
<el-form-item :label="$t('database.containerConn')" v-if="form.from === 'local'">
|
||||
<el-card class="mini-border-card">
|
||||
<el-descriptions :column="1">
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
<el-switch v-model="form.privilege" :disabled="form.status !== 'Running'" @change="onSaveAccess" />
|
||||
<span class="input-help">{{ $t('database.remoteConnHelper') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('database.rootPassword')" :rules="Rules.paramComplexity" prop="password">
|
||||
<el-form-item :label="$t('database.rootPassword')" prop="password">
|
||||
<el-input
|
||||
style="width: calc(100% - 205px)"
|
||||
type="password"
|
||||
|
|
@ -74,6 +74,7 @@
|
|||
{{ $t('commons.button.random') }}
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
<span class="input-help">{{ $t('commons.rule.illegalChar') }}</span>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-if="form.from !== 'local'">
|
||||
|
|
@ -87,8 +88,6 @@
|
|||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit" @cancel="loadPassword"></ConfirmDialog>
|
||||
<ConfirmDialog ref="confirmAccessDialogRef" @confirm="onSubmitAccess" @cancel="loadAccess"></ConfirmDialog>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="dialogVisible = false">
|
||||
|
|
@ -108,7 +107,6 @@ import { Rules } from '@/global/form-rules';
|
|||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { getDatabase, loadRemoteAccess, updateMysqlAccess, updateMysqlPassword } from '@/api/modules/database';
|
||||
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
||||
import { getAppConnInfo } from '@/api/modules/app';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { getRandomStr } from '@/utils/util';
|
||||
|
|
@ -125,6 +123,7 @@ const form = reactive({
|
|||
password: '',
|
||||
serviceName: '',
|
||||
containerName: '',
|
||||
oldPrivilege: false,
|
||||
privilege: false,
|
||||
port: 0,
|
||||
|
||||
|
|
@ -134,9 +133,9 @@ const form = reactive({
|
|||
username: '',
|
||||
remoteIP: '',
|
||||
});
|
||||
|
||||
const confirmDialogRef = ref();
|
||||
const confirmAccessDialogRef = ref();
|
||||
const rules = reactive({
|
||||
password: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
});
|
||||
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
|
|
@ -177,6 +176,7 @@ const loadAccess = async () => {
|
|||
if (form.from === 'local') {
|
||||
const res = await loadRemoteAccess(form.type, form.database);
|
||||
form.privilege = res.data;
|
||||
form.oldPrivilege = res.data;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -204,68 +204,72 @@ const loadPassword = async () => {
|
|||
form.remoteIP = res.data.address;
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
let param = {
|
||||
id: 0,
|
||||
from: form.from,
|
||||
type: form.type,
|
||||
database: form.database,
|
||||
value: form.password,
|
||||
};
|
||||
loading.value = true;
|
||||
await updateMysqlPassword(param)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
dialogVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onSave = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
let params = {
|
||||
header: i18n.global.t('database.confChange'),
|
||||
operationInfo: i18n.global.t('database.restartNowHelper'),
|
||||
submitInputInfo: i18n.global.t('database.restartNow'),
|
||||
};
|
||||
confirmDialogRef.value!.acceptParams(params);
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('database.changeConnHelper', [i18n.global.t('commons.login.password')]),
|
||||
i18n.global.t('commons.msg.infoTitle'),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
},
|
||||
).then(async () => {
|
||||
let param = {
|
||||
id: 0,
|
||||
from: form.from,
|
||||
type: form.type,
|
||||
database: form.database,
|
||||
value: form.password,
|
||||
};
|
||||
loading.value = true;
|
||||
await updateMysqlPassword(param)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
dialogVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const onSubmitAccess = async () => {
|
||||
let param = {
|
||||
id: 0,
|
||||
from: form.from,
|
||||
type: form.type,
|
||||
database: form.database,
|
||||
value: form.privilege ? '%' : 'localhost',
|
||||
};
|
||||
loading.value = true;
|
||||
await updateMysqlAccess(param)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
dialogVisible.value = false;
|
||||
const onSaveAccess = async () => {
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('database.changeConnHelper', [i18n.global.t('database.remoteAccess')]),
|
||||
i18n.global.t('commons.msg.infoTitle'),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
},
|
||||
)
|
||||
.then(async () => {
|
||||
let param = {
|
||||
id: 0,
|
||||
from: form.from,
|
||||
type: form.type,
|
||||
database: form.database,
|
||||
value: form.privilege ? '%' : 'localhost',
|
||||
};
|
||||
loading.value = true;
|
||||
await updateMysqlAccess(param)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
dialogVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
form.privilege = form.oldPrivilege;
|
||||
});
|
||||
};
|
||||
|
||||
const onSaveAccess = () => {
|
||||
let params = {
|
||||
header: i18n.global.t('database.confChange'),
|
||||
operationInfo: i18n.global.t('database.restartNowHelper'),
|
||||
submitInputInfo: i18n.global.t('database.restartNow'),
|
||||
};
|
||||
confirmAccessDialogRef.value!.acceptParams(params);
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,13 +22,21 @@
|
|||
<el-button @click="random">{{ $t('commons.button.random') }}</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<span class="input-help">{{ $t('commons.rule.illegalChar') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('database.permission')" prop="permission">
|
||||
<el-select v-model="form.permission">
|
||||
<el-option value="%" :label="$t('database.permissionAll')" />
|
||||
<el-option v-if="form.from !== 'local'" value="localhost" :label="$t('terminal.localhost')" />
|
||||
<el-option
|
||||
v-if="form.from !== 'local'"
|
||||
value="localhost"
|
||||
:label="$t('terminal.localhost') + '(localhost)'"
|
||||
/>
|
||||
<el-option value="ip" :label="$t('database.permissionForIP')" />
|
||||
</el-select>
|
||||
<span v-if="form.from !== 'local'" class="input-help">
|
||||
{{ $t('database.localhostHelper') }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.permission === 'ip'" prop="permissionIPs">
|
||||
<el-input clearable :rows="3" type="textarea" v-model="form.permissionIPs" />
|
||||
|
|
@ -61,7 +69,7 @@ import i18n from '@/lang';
|
|||
import { ElForm } from 'element-plus';
|
||||
import { addMysqlDB } from '@/api/modules/database';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { checkIp, getRandomStr } from '@/utils/util';
|
||||
import { getRandomStr } from '@/utils/util';
|
||||
|
||||
const loading = ref();
|
||||
const createVisible = ref(false);
|
||||
|
|
@ -80,19 +88,10 @@ const form = reactive({
|
|||
const rules = reactive({
|
||||
name: [Rules.requiredInput, Rules.dbName],
|
||||
username: [Rules.requiredInput, Rules.name],
|
||||
password: [Rules.paramComplexity],
|
||||
password: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
permission: [Rules.requiredSelect],
|
||||
permissionIPs: [{ validator: checkIPs, trigger: 'blur', required: true }],
|
||||
permissionIPs: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
});
|
||||
function checkIPs(rule: any, value: any, callback: any) {
|
||||
let ips = form.permissionIPs.split(',');
|
||||
for (const item of ips) {
|
||||
if (checkIp(item)) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.ip')));
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@
|
|||
<el-input disabled v-model="changeForm.userName"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.login.password')" prop="password">
|
||||
<el-input type="password" clearable show-password v-model="changeForm.password"></el-input>
|
||||
<el-input type="password" clearable show-password v-model="changeForm.password" />
|
||||
</el-form-item>
|
||||
<span class="input-help">{{ $t('commons.rule.illegalChar') }}</span>
|
||||
</div>
|
||||
<div v-if="changeForm.operation === 'privilege'">
|
||||
<el-form-item :label="$t('database.permission')" prop="privilege">
|
||||
|
|
@ -23,10 +24,13 @@
|
|||
<el-option
|
||||
v-if="changeForm.from !== 'local'"
|
||||
value="localhost"
|
||||
:label="$t('terminal.localhost')"
|
||||
:label="$t('terminal.localhost') + '(localhost)'"
|
||||
/>
|
||||
<el-option value="ip" :label="$t('database.permissionForIP')" />
|
||||
</el-select>
|
||||
<span v-if="changeForm.from !== 'local'" class="input-help">
|
||||
{{ $t('database.localhostHelper') }}
|
||||
</span>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="changeForm.privilege === 'ip'" prop="privilegeIPs">
|
||||
<el-input clearable :rows="3" type="textarea" v-model="changeForm.privilegeIPs" />
|
||||
|
|
@ -56,13 +60,14 @@ import { ElForm } from 'element-plus';
|
|||
import { deleteCheckMysqlDB, updateMysqlAccess, updateMysqlPassword } from '@/api/modules/database';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { checkIp } from '@/utils/util';
|
||||
|
||||
const loading = ref();
|
||||
const changeVisible = ref(false);
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const changeFormRef = ref<FormInstance>();
|
||||
const title = ref();
|
||||
const oldPrivilege = ref();
|
||||
const oldPrivilegeIPs = ref();
|
||||
const changeForm = reactive({
|
||||
id: 0,
|
||||
from: '',
|
||||
|
|
@ -79,20 +84,10 @@ const changeForm = reactive({
|
|||
const confirmDialogRef = ref();
|
||||
|
||||
const rules = reactive({
|
||||
password: [Rules.paramComplexity],
|
||||
privilegeIPs: [{ validator: checkIPs, trigger: 'blur', required: true }],
|
||||
password: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
privilegeIPs: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
});
|
||||
|
||||
function checkIPs(rule: any, value: any, callback: any) {
|
||||
let ips = changeForm.privilegeIPs.split(',');
|
||||
for (const item of ips) {
|
||||
if (checkIp(item)) {
|
||||
return callback(new Error(i18n.global.t('commons.rule.ip')));
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
interface DialogProps {
|
||||
id: number;
|
||||
from: string;
|
||||
|
|
@ -123,6 +118,8 @@ const acceptParams = (params: DialogProps): void => {
|
|||
changeForm.privilegeIPs = params.privilegeIPs;
|
||||
changeForm.value = params.value;
|
||||
changeVisible.value = true;
|
||||
oldPrivilege.value = params.privilege;
|
||||
oldPrivilegeIPs.value = params.privilegeIPs;
|
||||
};
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
|
|
@ -166,6 +163,10 @@ const submitChangeInfo = async (formEl: FormInstance | undefined) => {
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (changeForm.privilege === oldPrivilege.value && changeForm.privilegeIPs === oldPrivilegeIPs.value) {
|
||||
changeVisible.value = false;
|
||||
return;
|
||||
}
|
||||
if (changeForm.privilege !== 'ip') {
|
||||
param.value = changeForm.privilege;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.login.password')" prop="password">
|
||||
<el-input type="password" clearable show-password v-model="form.password" />
|
||||
<span class="input-help">{{ $t('commons.rule.illegalChar') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('database.permission')" prop="superUser">
|
||||
<el-checkbox v-model="form.superUser">{{ $t('database.pgSuperUser') }}</el-checkbox>
|
||||
|
|
@ -57,7 +58,7 @@ const confirmDialogRef = ref();
|
|||
|
||||
const rules = reactive({
|
||||
username: [Rules.requiredInput, Rules.name],
|
||||
password: [Rules.paramComplexity],
|
||||
password: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
});
|
||||
|
||||
interface DialogProps {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<DrawerPro v-model="dialogVisible" :header="$t('database.databaseConnInfo')" @close="handleClose" size="small">
|
||||
<el-form @submit.prevent v-loading="loading" ref="formRef" :model="form" label-position="top">
|
||||
<el-form @submit.prevent v-loading="loading" ref="formRef" :rules="rules" :model="form" label-position="top">
|
||||
<el-form-item :label="$t('database.containerConn')" v-if="form.from === 'local'">
|
||||
<el-card class="mini-border-card">
|
||||
<el-descriptions :column="1">
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
<el-divider border-style="dashed" />
|
||||
<div v-if="form.from === 'local'">
|
||||
<el-form-item :label="$t('commons.login.username')" prop="username">
|
||||
<el-input readonly disabled v-model="form.username">
|
||||
<el-input type="text" style="width: calc(100% - 60px)" readonly disabled v-model="form.username">
|
||||
<template #append>
|
||||
<el-button-group>
|
||||
<CopyButton :content="form.username" />
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.login.password')" :rules="Rules.paramComplexity" prop="password">
|
||||
<el-form-item :label="$t('commons.login.password')" prop="password">
|
||||
<el-input
|
||||
style="width: calc(100% - 205px)"
|
||||
type="password"
|
||||
|
|
@ -75,6 +75,7 @@
|
|||
{{ $t('commons.button.random') }}
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
<span class="input-help">{{ $t('commons.rule.illegalChar') }}</span>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-if="form.from !== 'local'">
|
||||
|
|
@ -89,8 +90,6 @@
|
|||
</div>
|
||||
</el-form>
|
||||
|
||||
<ConfirmDialog ref="confirmDialogRef" @confirm="onSubmit" @cancel="loadPassword"></ConfirmDialog>
|
||||
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button :disabled="loading" @click="dialogVisible = false">
|
||||
|
|
@ -110,7 +109,6 @@ import { Rules } from '@/global/form-rules';
|
|||
import i18n from '@/lang';
|
||||
import { ElForm } from 'element-plus';
|
||||
import { getDatabase, updatePostgresqlPassword } from '@/api/modules/database';
|
||||
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
||||
import { getAppConnInfo } from '@/api/modules/app';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { getRandomStr } from '@/utils/util';
|
||||
|
|
@ -136,8 +134,9 @@ const form = reactive({
|
|||
username: '',
|
||||
remoteIP: '',
|
||||
});
|
||||
|
||||
const confirmDialogRef = ref();
|
||||
const rules = reactive({
|
||||
password: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
});
|
||||
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const formRef = ref<FormInstance>();
|
||||
|
|
@ -205,36 +204,36 @@ const loadPassword = async () => {
|
|||
form.remoteIP = res.data.address;
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
let param = {
|
||||
id: 0,
|
||||
from: form.from,
|
||||
type: form.type,
|
||||
database: form.database,
|
||||
value: form.password,
|
||||
};
|
||||
loading.value = true;
|
||||
await updatePostgresqlPassword(param)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
dialogVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const onSave = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
let params = {
|
||||
header: i18n.global.t('database.confChange'),
|
||||
operationInfo: i18n.global.t('database.restartNowHelper'),
|
||||
submitInputInfo: i18n.global.t('database.restartNow'),
|
||||
};
|
||||
confirmDialogRef.value!.acceptParams(params);
|
||||
ElMessageBox.confirm(
|
||||
i18n.global.t('database.changeConnHelper', [i18n.global.t('commons.login.password')]),
|
||||
i18n.global.t('commons.msg.infoTitle'),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
},
|
||||
).then(async () => {
|
||||
let param = {
|
||||
id: 0,
|
||||
from: form.from,
|
||||
type: form.type,
|
||||
database: form.database,
|
||||
value: form.password,
|
||||
};
|
||||
loading.value = true;
|
||||
await updatePostgresqlPassword(param)
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
dialogVisible.value = false;
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
<el-button @click="random">{{ $t('commons.button.random') }}</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<span class="input-help">{{ $t('commons.rule.illegalChar') }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('database.permission')" prop="superUser">
|
||||
<el-checkbox v-model="form.superUser">{{ $t('database.pgSuperUser') }}</el-checkbox>
|
||||
|
|
@ -66,7 +67,7 @@ const form = reactive({
|
|||
const rules = reactive({
|
||||
name: [Rules.requiredInput, Rules.dbName],
|
||||
username: [Rules.requiredInput, Rules.name],
|
||||
password: [Rules.paramComplexity],
|
||||
password: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
});
|
||||
|
||||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
</el-form-item>
|
||||
<el-form-item :label="$t('commons.login.password')" prop="password">
|
||||
<el-input type="password" clearable show-password v-model="changeForm.password"></el-input>
|
||||
<span class="input-help">{{ $t('commons.rule.illegalChar') }}</span>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
|
|
@ -58,7 +59,7 @@ const changeForm = reactive({
|
|||
});
|
||||
const confirmDialogRef = ref();
|
||||
const rules = reactive({
|
||||
password: [Rules.paramComplexity],
|
||||
password: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
});
|
||||
|
||||
interface DialogProps {
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@
|
|||
{{ $t('commons.button.random') }}
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
<span class="input-help">{{ $t('commons.rule.illegalChar') }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<div v-if="form.from !== 'local'">
|
||||
|
|
@ -104,6 +105,7 @@ import { getAppConnInfo } from '@/api/modules/app';
|
|||
import { MsgSuccess } from '@/utils/message';
|
||||
import { getRandomStr } from '@/utils/util';
|
||||
import { getAgentSettingInfo } from '@/api/modules/setting';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { GlobalStore } from '@/store';
|
||||
const globalStore = GlobalStore();
|
||||
|
||||
|
|
@ -123,21 +125,9 @@ const form = reactive({
|
|||
remoteIP: '',
|
||||
});
|
||||
const rules = reactive({
|
||||
password: [{ validator: checkPassword, trigger: 'blur' }],
|
||||
password: [Rules.requiredInput, Rules.noSpace, Rules.illegal],
|
||||
});
|
||||
|
||||
function checkPassword(rule: any, value: any, callback: any) {
|
||||
if (form.password !== '') {
|
||||
const reg = /^[a-zA-Z0-9]{1}[a-zA-Z0-9.%@!~_-]{4,126}[a-zA-Z0-9]{1}$/;
|
||||
if (!reg.test(value) && value !== '') {
|
||||
callback(new Error(i18n.global.t('commons.rule.paramComplexity', ['.%@!~_-'])));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
callback();
|
||||
}
|
||||
|
||||
const confirmDialogRef = ref();
|
||||
|
||||
const emit = defineEmits(['checkExist', 'closeTerminal']);
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ const acceptParams = async (props: MoveProps) => {
|
|||
type.value = props.type;
|
||||
if (props.name && props.name != '') {
|
||||
oldName.value = props.name;
|
||||
const res = await checkFile(props.path + '/' + props.name);
|
||||
const res = await checkFile(props.path + '/' + props.name, false);
|
||||
if (res.data) {
|
||||
changeName.value = true;
|
||||
addForm.cover = false;
|
||||
|
|
|
|||
|
|
@ -59,12 +59,8 @@ let isComplexity = ref(false);
|
|||
type FormInstance = InstanceType<typeof ElForm>;
|
||||
const passFormRef = ref<FormInstance>();
|
||||
const passRules = reactive({
|
||||
oldPass: [Rules.noSpace, Rules.requiredInput],
|
||||
newPass: [
|
||||
Rules.requiredInput,
|
||||
Rules.noSpace,
|
||||
{ min: 6, message: i18n.global.t('commons.rule.commonPassword'), trigger: 'blur' },
|
||||
],
|
||||
oldPass: [Rules.requiredInput, Rules.noSpace],
|
||||
newPass: [Rules.requiredInput, Rules.noSpace],
|
||||
newPassComplexity: [Rules.requiredInput, Rules.noSpace, Rules.password],
|
||||
rePass: [Rules.requiredInput, Rules.noSpace, { validator: checkPasswordSame, trigger: 'blur' }],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -47,12 +47,8 @@ import { logOutApi } from '@/api/modules/auth';
|
|||
const globalStore = GlobalStore();
|
||||
const passFormRef = ref<FormInstance>();
|
||||
const passRules = reactive({
|
||||
oldPassword: [Rules.noSpace, Rules.requiredInput],
|
||||
newPassword: [
|
||||
Rules.requiredInput,
|
||||
Rules.noSpace,
|
||||
{ min: 6, message: i18n.global.t('commons.rule.commonPassword'), trigger: 'blur' },
|
||||
],
|
||||
oldPassword: [Rules.requiredInput, Rules.noSpace],
|
||||
newPassword: [Rules.requiredInput, Rules.noSpace],
|
||||
newPasswordComplexity: [Rules.requiredInput, Rules.noSpace, Rules.password],
|
||||
retryPassword: [Rules.requiredInput, Rules.noSpace, { validator: checkPassword, trigger: 'blur' }],
|
||||
});
|
||||
|
|
|
|||
|
|
@ -43,8 +43,9 @@ import i18n from '@/lang';
|
|||
import { snapshotImport } from '@/api/modules/setting';
|
||||
import { listBackupOptions, getFilesFromBackup } from '@/api/modules/backup';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
import router from '@/routers';
|
||||
import { checkFile } from '@/api/modules/files';
|
||||
|
||||
const drawerVisible = ref(false);
|
||||
const loading = ref();
|
||||
|
|
@ -92,7 +93,12 @@ const checkDisable = (val: string) => {
|
|||
return false;
|
||||
};
|
||||
const toFolder = async () => {
|
||||
router.push({ path: '/hosts/files', query: { path: backupPath.value } });
|
||||
const res = await checkFile(backupPath.value, true);
|
||||
if (res.data) {
|
||||
router.push({ path: '/hosts/files', query: { path: backupPath.value } });
|
||||
} else {
|
||||
MsgError(i18n.global.t('file.noSuchFile'));
|
||||
}
|
||||
};
|
||||
|
||||
const submitImport = async (formEl: FormInstance | undefined) => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue