mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2024-11-22 07:10:09 +01:00
Backup and restore function is done
Completed with SQLDump and .conf backup
This commit is contained in:
parent
e2e821881c
commit
413377fbb9
@ -516,6 +516,13 @@ class WireguardConfiguration:
|
||||
|
||||
self.Status = self.getStatus()
|
||||
|
||||
def __dropDatabase(self):
|
||||
existingTables = sqlSelect(f"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '{self.Name}%'").fetchall()
|
||||
for t in existingTables:
|
||||
sqlUpdate(f"DROP TABLE {t['name']}")
|
||||
|
||||
existingTables = sqlSelect(f"SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '{self.Name}%'").fetchall()
|
||||
|
||||
def __createDatabase(self):
|
||||
existingTables = sqlSelect("SELECT name FROM sqlite_master WHERE type='table'").fetchall()
|
||||
existingTables = [t['name'] for t in existingTables]
|
||||
@ -573,6 +580,15 @@ class WireguardConfiguration:
|
||||
""" % self.Name
|
||||
)
|
||||
|
||||
def __dumpDatabase(self):
|
||||
for line in sqldb.iterdump():
|
||||
if (line.startswith(f"INSERT INTO \"{self.Name}\"")
|
||||
or line.startswith(f'INSERT INTO "{self.Name}_restrict_access"')
|
||||
or line.startswith(f'INSERT INTO "{self.Name}_transfer"')
|
||||
or line.startswith(f'INSERT INTO "{self.Name}_deleted"')
|
||||
):
|
||||
yield line
|
||||
|
||||
def __getPublicKey(self) -> str:
|
||||
return _generatePublicKey(self.PrivateKey)[1]
|
||||
|
||||
@ -925,10 +941,14 @@ class WireguardConfiguration:
|
||||
def backupConfigurationFile(self):
|
||||
if not os.path.exists(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup')):
|
||||
os.mkdir(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup'))
|
||||
time = datetime.now().strftime("%Y%m%d%H%M%S")
|
||||
shutil.copy(
|
||||
os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], f'{self.Name}.conf'),
|
||||
os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', f'{self.Name}_{datetime.now().strftime("%Y%m%d%H%M%S")}.conf')
|
||||
os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', f'{self.Name}_{time}.conf')
|
||||
)
|
||||
with open(os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', f'{self.Name}_{time}.sql'), 'w+') as f:
|
||||
for l in self.__dumpDatabase():
|
||||
f.write(l + "\n")
|
||||
|
||||
|
||||
def getBackups(self) -> list[dict[str: str, str: str, str: str]]:
|
||||
@ -959,6 +979,7 @@ class WireguardConfiguration:
|
||||
if self.Status:
|
||||
self.toggleConfiguration()
|
||||
target = os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', backupFileName)
|
||||
targetSQL = os.path.join(DashboardConfig.GetConfig("Server", "wg_conf_path")[1], 'WGDashboard_Backup', backupFileName.replace(".conf", ".sql"))
|
||||
if not os.path.exists(target):
|
||||
return False
|
||||
targetContent = open(target, 'r').read()
|
||||
@ -968,6 +989,15 @@ class WireguardConfiguration:
|
||||
except Exception as e:
|
||||
return False
|
||||
self.__parseConfigurationFile()
|
||||
self.__dropDatabase()
|
||||
self.__createDatabase()
|
||||
if (os.path.exists(targetSQL)):
|
||||
with open(targetSQL, 'r') as sqlFile:
|
||||
for l in sqlFile.readlines():
|
||||
l = l.rstrip('\n')
|
||||
if len(l) > 0:
|
||||
sqlUpdate(l)
|
||||
|
||||
self.__initPeersList()
|
||||
return True
|
||||
|
||||
@ -1518,7 +1548,7 @@ def sqlUpdate(statement: str, paramters: tuple = ()) -> sqlite3.Cursor:
|
||||
cursor.execute(statement, paramters)
|
||||
sqldb.commit()
|
||||
except sqlite3.OperationalError as error:
|
||||
print("[WGDashboard] SQLite Error:" + str(error))
|
||||
print("[WGDashboard] SQLite Error:" + str(error) + " | Statement: " + statement)
|
||||
|
||||
DashboardConfig = DashboardConfig()
|
||||
_, APP_PREFIX = DashboardConfig.GetConfig("Server", "app_prefix")
|
||||
|
@ -34,9 +34,10 @@ const restoreBackup = () => {
|
||||
backupFileName: props.b.filename
|
||||
}, (res) => {
|
||||
loading.value = false;
|
||||
restoreConfirmation.value = false;
|
||||
if (res.status){
|
||||
emit("refresh")
|
||||
store.newMessage("Server", "Backup restored", "success")
|
||||
store.newMessage("Server", "Backup restored with " + props.b.filename, "success")
|
||||
}else{
|
||||
store.newMessage("Server", "Backup failed to restore", "danger")
|
||||
}
|
||||
@ -83,7 +84,7 @@ const delaySeconds = computed(() => {
|
||||
<button
|
||||
:disabled="loading"
|
||||
@click="restoreBackup()"
|
||||
class="btn btn-danger rounded-3">
|
||||
class="btn btn-success rounded-3">
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
|
@ -154,7 +154,7 @@ export default {
|
||||
modalOpen: false
|
||||
},
|
||||
backupRestore: {
|
||||
modalOpen: true
|
||||
modalOpen: false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -45,16 +45,17 @@ export default {
|
||||
<LocaleText t="Configuration"></LocaleText>
|
||||
</RouterLink>
|
||||
</div>
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div v-if="this.configurationLoaded">
|
||||
<p class="text-muted" v-if="this.wireguardConfigurationsStore.Configurations.length === 0">
|
||||
<LocaleText t="You don't have any WireGuard configurations yet. Please check the configuration folder or change it in Settings. By default the folder is /etc/wireguard."></LocaleText>
|
||||
</p>
|
||||
<div class="d-flex gap-3 flex-column mb-3" v-else>
|
||||
<ConfigurationCard v-for="c in this.wireguardConfigurationsStore.Configurations" :key="c.Name" :c="c"></ConfigurationCard>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
<TransitionGroup name="fade" tag="div" class="d-flex flex-column gap-3 mb-4">
|
||||
<p class="text-muted"
|
||||
key="noConfiguration"
|
||||
v-if="this.configurationLoaded && this.wireguardConfigurationsStore.Configurations.length === 0">
|
||||
<LocaleText t="You don't have any WireGuard configurations yet. Please check the configuration folder or change it in Settings. By default the folder is /etc/wireguard."></LocaleText>
|
||||
</p>
|
||||
<ConfigurationCard v-for="(c, index) in this.wireguardConfigurationsStore.Configurations"
|
||||
:delay="index*0.05 + 's'"
|
||||
v-else-if="this.configurationLoaded"
|
||||
:key="c.Name" :c="c"></ConfigurationCard>
|
||||
</TransitionGroup>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
@ -12,7 +12,8 @@ export default {
|
||||
Status: Boolean,
|
||||
PublicKey: String,
|
||||
PrivateKey: String
|
||||
}
|
||||
},
|
||||
delay: String
|
||||
},
|
||||
data(){
|
||||
return{
|
||||
@ -105,5 +106,7 @@ export default {
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
.fade-enter-active{
|
||||
transition-delay: v-bind(delay) !important;
|
||||
}
|
||||
</style>
|
@ -70,6 +70,7 @@ export const WireguardConfigurationsStore = defineStore('WireguardConfigurations
|
||||
async getConfigurations(){
|
||||
await fetchGet("/api/getWireguardConfigurations", {}, (res) => {
|
||||
if (res.status) this.Configurations = res.data
|
||||
// this.Configurations = []
|
||||
});
|
||||
},
|
||||
regexCheckIP(ip){
|
||||
|
@ -1038,14 +1038,12 @@ pre.index-alert {
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: all 0.3s ease-in-out;
|
||||
/*position: absolute;*/
|
||||
/*padding-top: 50px*/
|
||||
transition: all 0.5s cubic-bezier(0.42, 0, 0.22, 1.0);
|
||||
}
|
||||
|
||||
.fade-enter-from,
|
||||
.fade-leave-to {
|
||||
transform: translateY(30px);
|
||||
transform: translateY(40px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user