feat: 同步数据库时标记已删除数据库 (#4185)

Refs #4165
This commit is contained in:
ssongliu 2024-03-14 18:22:07 +08:00 committed by GitHub
parent be36103475
commit 0f9b0d5d82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 108 additions and 20 deletions

View File

@ -41,7 +41,7 @@ type MysqlDBInfo struct {
Username string `json:"username"` Username string `json:"username"`
Password string `json:"password"` Password string `json:"password"`
Permission string `json:"permission"` Permission string `json:"permission"`
BackupCount int `json:"backupCount"` IsDelete bool `json:"isDelete"`
Description string `json:"description"` Description string `json:"description"`
} }

View File

@ -20,7 +20,7 @@ type PostgresqlDBInfo struct {
Username string `json:"username"` Username string `json:"username"`
Password string `json:"password"` Password string `json:"password"`
SuperUser bool `json:"superUser"` SuperUser bool `json:"superUser"`
BackupCount int `json:"backupCount"` IsDelete bool `json:"isDelete"`
Description string `json:"description"` Description string `json:"description"`
} }

View File

@ -9,5 +9,6 @@ type DatabaseMysql struct {
Username string `json:"username" gorm:"type:varchar(256);not null"` Username string `json:"username" gorm:"type:varchar(256);not null"`
Password string `json:"password" gorm:"type:varchar(256);not null"` Password string `json:"password" gorm:"type:varchar(256);not null"`
Permission string `json:"permission" gorm:"type:varchar(256);not null"` Permission string `json:"permission" gorm:"type:varchar(256);not null"`
IsDelete bool `json:"isDelete" gorm:"type:varchar(64)"`
Description string `json:"description" gorm:"type:varchar(256);"` Description string `json:"description" gorm:"type:varchar(256);"`
} }

View File

@ -8,6 +8,7 @@ type DatabasePostgresql struct {
Format string `json:"format" gorm:"type:varchar(64);not null"` Format string `json:"format" gorm:"type:varchar(64);not null"`
Username string `json:"username" gorm:"type:varchar(256);not null"` Username string `json:"username" gorm:"type:varchar(256);not null"`
Password string `json:"password" gorm:"type:varchar(256);not null"` Password string `json:"password" gorm:"type:varchar(256);not null"`
SuperUser bool `json:"superUser" gorm:"type:varchar(64)" ` SuperUser bool `json:"superUser" gorm:"type:varchar(64)"`
IsDelete bool `json:"isDelete" gorm:"type:varchar(64)"`
Description string `json:"description" gorm:"type:varchar(256);"` Description string `json:"description" gorm:"type:varchar(256);"`
} }

View File

@ -190,11 +190,13 @@ func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error {
if err != nil { if err != nil {
return err return err
} }
deleteList := databases
for _, data := range datas { for _, data := range datas {
hasOld := false hasOld := false
for _, oldData := range databases { for i := 0; i < len(databases); i++ {
if strings.EqualFold(oldData.Name, data.Name) && strings.EqualFold(oldData.MysqlName, data.MysqlName) { if strings.EqualFold(databases[i].Name, data.Name) && strings.EqualFold(databases[i].MysqlName, data.MysqlName) {
hasOld = true hasOld = true
deleteList = append(deleteList[:i], deleteList[i+1:]...)
break break
} }
} }
@ -208,6 +210,9 @@ func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error {
} }
} }
} }
for _, delItem := range deleteList {
_ = mysqlRepo.Update(delItem.ID, map[string]interface{}{"is_delete": true})
}
return nil return nil
} }

View File

@ -216,11 +216,13 @@ func (u *PostgresqlService) LoadFromRemote(database string) error {
if err != nil { if err != nil {
return err return err
} }
deleteList := databases
for _, data := range datas { for _, data := range datas {
hasOld := false hasOld := false
for _, oldData := range databases { for i := 0; i < len(databases); i++ {
if strings.EqualFold(oldData.Name, data.Name) && strings.EqualFold(oldData.PostgresqlName, data.PostgresqlName) { if strings.EqualFold(databases[i].Name, data.Name) && strings.EqualFold(databases[i].PostgresqlName, data.PostgresqlName) {
hasOld = true hasOld = true
deleteList = append(deleteList[:i], deleteList[i+1:]...)
break break
} }
} }
@ -234,6 +236,9 @@ func (u *PostgresqlService) LoadFromRemote(database string) error {
} }
} }
} }
for _, delItem := range deleteList {
_ = postgresqlRepo.Update(delItem.ID, map[string]interface{}{"is_delete": true})
}
return nil return nil
} }

View File

@ -74,6 +74,7 @@ func Init() {
migrations.UpdateWebDavConf, migrations.UpdateWebDavConf,
migrations.AddSnapshotIgnore, migrations.AddSnapshotIgnore,
migrations.AddDatabaseIsDelete,
}) })
if err := m.Migrate(); err != nil { if err := m.Migrate(); err != nil {
global.LOG.Error(err) global.LOG.Error(err)

View File

@ -15,3 +15,13 @@ var AddSnapshotIgnore = &gormigrate.Migration{
return nil return nil
}, },
} }
var AddDatabaseIsDelete = &gormigrate.Migration{
ID: "20240314-add-database-is-delete",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.DatabaseMysql{}, &model.DatabasePostgresql{}); err != nil {
return err
}
return nil
},
}

View File

@ -17818,6 +17818,9 @@ const docTemplate = `{
"sessionTimeout": { "sessionTimeout": {
"type": "string" "type": "string"
}, },
"snapshotIgnore": {
"type": "string"
},
"ssl": { "ssl": {
"type": "string" "type": "string"
}, },

View File

@ -17811,6 +17811,9 @@
"sessionTimeout": { "sessionTimeout": {
"type": "string" "type": "string"
}, },
"snapshotIgnore": {
"type": "string"
},
"ssl": { "ssl": {
"type": "string" "type": "string"
}, },

View File

@ -2538,6 +2538,8 @@ definitions:
type: string type: string
sessionTimeout: sessionTimeout:
type: string type: string
snapshotIgnore:
type: string
ssl: ssl:
type: string type: string
sslType: sslType:

View File

@ -23,6 +23,7 @@ export namespace Database {
username: string; username: string;
password: string; password: string;
permission: string; permission: string;
isDelete: string;
description: string; description: string;
} }
export interface BaseInfo { export interface BaseInfo {
@ -207,6 +208,7 @@ export namespace Database {
username: string; username: string;
password: string; password: string;
superUser: boolean; superUser: boolean;
isDelete: string;
description: string; description: string;
} }
export interface ChangeInfo { export interface ChangeInfo {

View File

@ -364,6 +364,7 @@ const message = {
goUpgrade: 'Go for upgrade', goUpgrade: 'Go for upgrade',
goInstall: 'Go for install', goInstall: 'Go for install',
source: 'Source', source: 'Source',
isDelete: 'Deleted',
permission: 'Permission', permission: 'Permission',
permissionForIP: 'IP', permissionForIP: 'IP',
permissionAll: 'All of them(%)', permissionAll: 'All of them(%)',
@ -388,7 +389,7 @@ const message = {
portHelper: portHelper:
'This port is the exposed port of the container. You need to save the modification separately and restart the container!', 'This port is the exposed port of the container. You need to save the modification separately and restart the container!',
loadFromRemote: 'Load from server', loadFromRemote: 'Sync from Server',
userBind: 'Bind User', userBind: 'Bind User',
pgBindHelper: pgBindHelper:
'This operation is used to create a new user and bind it to the target database. Currently, selecting users already existing in the database is not supported.', 'This operation is used to create a new user and bind it to the target database. Currently, selecting users already existing in the database is not supported.',

View File

@ -360,6 +360,7 @@ const message = {
goUpgrade: '去應用商店升級', goUpgrade: '去應用商店升級',
goInstall: '去應用商店安裝', goInstall: '去應用商店安裝',
source: '來源', source: '來源',
isDelete: '已刪除',
permission: '權限', permission: '權限',
permissionForIP: '指定 IP', permissionForIP: '指定 IP',
permissionAll: '所有人(%)', permissionAll: '所有人(%)',
@ -380,7 +381,7 @@ const message = {
confChange: '配置修改', confChange: '配置修改',
confNotFound: '未能找到該應用配置文件請在應用商店升級該應用至最新版本後重試', confNotFound: '未能找到該應用配置文件請在應用商店升級該應用至最新版本後重試',
loadFromRemote: '服務器獲取', loadFromRemote: '伺服器同步',
userBind: '綁定使用者', userBind: '綁定使用者',
pgBindHelper: '此操作用於創建新使用者並將其綁定到目標資料庫暫不支援選擇已存在於資料庫中的使用者', pgBindHelper: '此操作用於創建新使用者並將其綁定到目標資料庫暫不支援選擇已存在於資料庫中的使用者',
pgSuperUser: '超級使用者', pgSuperUser: '超級使用者',

View File

@ -360,6 +360,7 @@ const message = {
goUpgrade: '去应用列表升级', goUpgrade: '去应用列表升级',
goInstall: '去应用商店安装', goInstall: '去应用商店安装',
source: '来源', source: '来源',
isDelete: '已删除',
permission: '权限', permission: '权限',
permissionForIP: '指定 IP', permissionForIP: '指定 IP',
permissionAll: '所有人(%)', permissionAll: '所有人(%)',
@ -380,7 +381,7 @@ const message = {
confChange: '配置修改', confChange: '配置修改',
confNotFound: '未能找到该应用配置文件请在应用商店升级该应用至最新版本后重试', confNotFound: '未能找到该应用配置文件请在应用商店升级该应用至最新版本后重试',
loadFromRemote: '从服务器获取', loadFromRemote: '从服务器同步',
userBind: '绑定用户', userBind: '绑定用户',
pgBindHelper: '该操作用于创建新用户并将其绑定到目标数据库暂不支持选择已存在于数据库中的用户', pgBindHelper: '该操作用于创建新用户并将其绑定到目标数据库暂不支持选择已存在于数据库中的用户',
pgSuperUser: '超级用户', pgSuperUser: '超级用户',

View File

@ -113,8 +113,19 @@
</template> </template>
<template #main v-if="currentDB"> <template #main v-if="currentDB">
<ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data"> <ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
<el-table-column :label="$t('commons.table.name')" prop="name" sortable /> <el-table-column :label="$t('commons.table.name')" prop="name" sortable min-width="90">
<el-table-column :label="$t('commons.login.username')" prop="username"> <template #default="{ row }">
<Tooltip v-if="!row.isDelete" :islink="false" :text="row.name" />
<div v-else>
<span v-if="row.name.length < 15">{{ row.name }}</span>
<el-tooltip v-else :content="row.name">{{ row.name.substring(0, 10) }}...</el-tooltip>
<el-tag round type="info" class="ml-1" size="small">
{{ $t('database.isDelete') }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('commons.login.username')" show-overflow-tooltip prop="username">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center" v-if="row.username"> <div class="flex items-center" v-if="row.username">
<span> <span>
@ -122,7 +133,13 @@
</span> </span>
</div> </div>
<div v-else> <div v-else>
<el-button style="margin-left: -3px" type="primary" link @click="onBind(row)"> <el-button
:disabled="row.isDelete"
style="margin-left: -3px"
type="primary"
link
@click="onBind(row)"
>
{{ $t('database.userBind') }} {{ $t('database.userBind') }}
</el-button> </el-button>
</div> </div>
@ -159,7 +176,13 @@
</div> </div>
</div> </div>
<div v-if="row.password === '' && row.username"> <div v-if="row.password === '' && row.username">
<el-button style="margin-left: -3px" link type="primary" @click="onChangePassword(row)"> <el-button
:disabled="row.isDelete"
style="margin-left: -3px"
link
type="primary"
@click="onChangePassword(row)"
>
{{ $t('database.passwordHelper') }} {{ $t('database.passwordHelper') }}
</el-button> </el-button>
</div> </div>
@ -542,7 +565,7 @@ const buttons = [
{ {
label: i18n.global.t('database.changePassword'), label: i18n.global.t('database.changePassword'),
disabled: (row: Database.MysqlDBInfo) => { disabled: (row: Database.MysqlDBInfo) => {
return !row.username; return !row.username || row.isDelete;
}, },
click: (row: Database.MysqlDBInfo) => { click: (row: Database.MysqlDBInfo) => {
onChangePassword(row); onChangePassword(row);
@ -551,7 +574,7 @@ const buttons = [
{ {
label: i18n.global.t('database.permission'), label: i18n.global.t('database.permission'),
disabled: (row: Database.MysqlDBInfo) => { disabled: (row: Database.MysqlDBInfo) => {
return !row.password; return !row.password || row.isDelete;
}, },
click: (row: Database.MysqlDBInfo) => { click: (row: Database.MysqlDBInfo) => {
let param = { let param = {
@ -576,6 +599,9 @@ const buttons = [
}, },
{ {
label: i18n.global.t('database.backupList'), label: i18n.global.t('database.backupList'),
disabled: (row: Database.MysqlDBInfo) => {
return row.isDelete;
},
click: (row: Database.MysqlDBInfo) => { click: (row: Database.MysqlDBInfo) => {
let params = { let params = {
type: currentDB.value.type, type: currentDB.value.type,
@ -587,6 +613,9 @@ const buttons = [
}, },
{ {
label: i18n.global.t('database.loadBackup'), label: i18n.global.t('database.loadBackup'),
disabled: (row: Database.MysqlDBInfo) => {
return row.isDelete;
},
click: (row: Database.MysqlDBInfo) => { click: (row: Database.MysqlDBInfo) => {
let params = { let params = {
type: currentDB.value.type, type: currentDB.value.type,

View File

@ -90,7 +90,18 @@
</template> </template>
<template #main v-if="currentDB"> <template #main v-if="currentDB">
<ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data"> <ComplexTable :pagination-config="paginationConfig" @sort-change="search" @search="search" :data="data">
<el-table-column :label="$t('commons.table.name')" prop="name" sortable /> <el-table-column :label="$t('commons.table.name')" prop="name" sortable>
<template #default="{ row }">
<Tooltip v-if="!row.isDelete" :islink="false" :text="row.name" />
<div v-else>
<span v-if="row.name.length < 15">{{ row.name }}</span>
<el-tooltip v-else :content="row.name">{{ row.name.substring(0, 10) }}...</el-tooltip>
<el-tag round type="info" class="ml-1" size="small">
{{ $t('database.isDelete') }}
</el-tag>
</div>
</template>
</el-table-column>
<el-table-column :label="$t('commons.login.username')" prop="username"> <el-table-column :label="$t('commons.login.username')" prop="username">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center" v-if="row.username"> <div class="flex items-center" v-if="row.username">
@ -99,7 +110,13 @@
</span> </span>
</div> </div>
<div v-else> <div v-else>
<el-button style="margin-left: -3px" type="primary" link @click="onBind(row)"> <el-button
:disabled="row.isDelete"
style="margin-left: -3px"
type="primary"
link
@click="onBind(row)"
>
{{ $t('database.userBind') }} {{ $t('database.userBind') }}
</el-button> </el-button>
</div> </div>
@ -498,7 +515,7 @@ const buttons = [
{ {
label: i18n.global.t('database.changePassword'), label: i18n.global.t('database.changePassword'),
disabled: (row: Database.PostgresqlDBInfo) => { disabled: (row: Database.PostgresqlDBInfo) => {
return !row.username; return !row.username || row.isDelete;
}, },
click: (row: Database.PostgresqlDBInfo) => { click: (row: Database.PostgresqlDBInfo) => {
onChangePassword(row); onChangePassword(row);
@ -507,7 +524,7 @@ const buttons = [
{ {
label: i18n.global.t('database.permission'), label: i18n.global.t('database.permission'),
disabled: (row: Database.PostgresqlDBInfo) => { disabled: (row: Database.PostgresqlDBInfo) => {
return !row.username; return !row.username || row.isDelete;
}, },
click: (row: Database.PostgresqlDBInfo) => { click: (row: Database.PostgresqlDBInfo) => {
let param = { let param = {
@ -521,6 +538,9 @@ const buttons = [
}, },
{ {
label: i18n.global.t('database.backupList'), label: i18n.global.t('database.backupList'),
disabled: (row: Database.PostgresqlDBInfo) => {
return row.isDelete;
},
click: (row: Database.PostgresqlDBInfo) => { click: (row: Database.PostgresqlDBInfo) => {
let params = { let params = {
type: currentDB.value.type, type: currentDB.value.type,
@ -532,6 +552,9 @@ const buttons = [
}, },
{ {
label: i18n.global.t('database.loadBackup'), label: i18n.global.t('database.loadBackup'),
disabled: (row: Database.PostgresqlDBInfo) => {
return row.isDelete;
},
click: (row: Database.PostgresqlDBInfo) => { click: (row: Database.PostgresqlDBInfo) => {
let params = { let params = {
type: currentDB.value.type, type: currentDB.value.type,