Support for doing both auto backup on backend creation and force export

This commit is contained in:
arabcoders
2025-04-03 00:31:17 +03:00
parent 7b61660290
commit abd60715c2
5 changed files with 147 additions and 67 deletions

View File

@@ -269,34 +269,30 @@
</p>
</div>
</div>
<div class="field" v-if="backends.length > 0">
<div class="field">
<hr>
<label class="label has-text-danger" for="force_export">
Export current local database state to this backend?
<label class="label has-text-danger" for="backup_data">
Create backup for this backend data?
</label>
<div class="control">
<input id="force_export" type="checkbox" class="switch is-success"
v-model="forceExport">
<label for="force_export">Yes</label>
<input id="backup_data" type="checkbox" class="switch is-success" v-model="backup_data">
<label for="backup_data">Yes</label>
<p class="help">
<span class="icon has-text-danger"><i class="fas fa-exclamation-triangle"></i></span>
If this is a new backend, you need to get it in sync with your current database,
enabling this option will initiate a one time force export the current local database state to the
backend. This will override the backend state to be inline with the local database state.
This will run a one time backup for the backend data.
</p>
</div>
</div>
<div class="field" v-else>
<div class="field" v-if="backends.length > 0">
<hr>
<label class="label has-text-danger" for="run_import">
Export current local database state to this backend?
<label class="label has-text-danger" for="force_export">
Force Export local data to this backend?
</label>
<div class="control">
<input id="run_import" type="checkbox" class="switch is-success" v-model="runImport">
<label for="run_import">Yes</label>
<p class="help">
<span class="icon has-text-danger"><i class="fas fa-info-circle"></i></span>
Do you want to run a one time import for this backend after adding this backend?
<input id="force_export" type="checkbox" class="switch is-success" v-model="force_export">
<label for="force_export">Yes</label>
<p class="help has-text-danger">
<span class="icon"><i class="fas fa-info-circle"></i></span>
THIS OPTION WILL OVERRIDE THE BACKEND DATA with locally stored data.
</p>
</div>
</div>
@@ -335,7 +331,7 @@ import request from '~/utils/request'
import {awaitElement, explode, notification, ucFirst} from '~/utils/index'
import {useStorage} from "@vueuse/core";
const emit = defineEmits(['addBackend', 'forceExport', 'runImport'])
const emit = defineEmits(['addBackend', 'backupData', 'forceExport'])
const props = defineProps({
backends: {
@@ -377,8 +373,8 @@ const uuidLoading = ref(false)
const serversLoading = ref(false)
const exposeToken = ref(false)
const error = ref()
const forceExport = ref(false)
const runImport = ref(false)
const backup_data = ref(true)
const force_export = ref(false)
const isLimited = ref(false)
const accessTokenResponse = ref({})
@@ -674,16 +670,15 @@ const addBackend = async () => {
notification('success', 'Information', `Backend ${backend.value.name} added successfully.`)
let event
if (true === Boolean(forceExport?.value ?? false)) {
event = 'forceExport'
} else if (true === Boolean(runImport?.value ?? false)) {
event = 'runImport'
} else {
event = 'addBackend'
if (true === Boolean(backup_data?.value ?? false)) {
emit('backupData', backend)
}
emit(event, backend)
if (true === Boolean(force_export?.value ?? false)) {
emit('forceExport', backend)
}
emit('addBackend')
return true
}

View File

@@ -35,8 +35,9 @@
</div>
<div class="column is-12" v-if="toggleForm">
<BackendAdd @forceExport="e => handleEvents('forceExport', e)" :backends="backends"
@runImport="e => handleEvents('runImport', e)" @addBackend="e => handleEvents('addBackend', e)"/>
<BackendAdd @backupData="e => handleEvents('backupData', e)" :backends="backends"
@forceExport="e => handleEvents('forceExport', e)"
@addBackend="e => handleEvents('addBackend', e)"/>
</div>
<template v-else>
<div class="column is-12" v-if="backends.length<1">
@@ -188,7 +189,7 @@ import 'assets/css/bulma-switch.css'
import moment from 'moment'
import request from '~/utils/request'
import BackendAdd from '~/components/BackendAdd'
import {ag, copyText, makeConsoleCommand, notification, r, TOOLTIP_DATE_FORMAT} from '~/utils/index'
import {ag, copyText, makeConsoleCommand, notification, queue_event, r, TOOLTIP_DATE_FORMAT} from '~/utils/index'
import {useStorage} from '@vueuse/core'
import Message from '~/components/Message'
@@ -206,31 +207,31 @@ const usefulCommands = {
export_now: {
id: 1,
title: "Run normal export.",
command: 'state:export -v -s {name}',
command: 'state:export -v -u {user} -s {name}',
state_key: 'export.enabled',
},
import_now: {
id: 2,
title: "Run normal import.",
command: 'state:import -v -s {name}',
command: 'state:import -v -u {user} -s {name}',
state_key: 'import.enabled'
},
force_export: {
id: 3,
title: "Force export local play state to this backend.",
command: 'state:export -fi -v -s {name}',
command: 'state:export -fi -v -u {user} -s {name}',
state_key: 'export.enabled',
},
backup_now: {
id: 4,
title: "Backup this backend play state.",
command: "state:backup -v -s {name} --file '{date}.manual_{name}.json'",
command: "state:backup -v -u {user} -s {name} --file '{date}.manual_{name}.json'",
state_key: 'import.enabled',
},
metadata_only: {
id: 5,
title: "Import this backend metadata.",
command: "state:import -v --metadata-only -s {name}",
command: "state:import -v --metadata-only -u {user} -s {name}",
state_key: 'import.enabled',
},
}
@@ -247,7 +248,7 @@ const forwardCommand = async backend => {
date: moment().format('YYYYMMDD'),
}
await navigateTo(makeConsoleCommand(r(usefulCommands[index].command, {...backend, ...util})));
await navigateTo(makeConsoleCommand(r(usefulCommands[index].command, {...backend, ...util, user: api_user.value})));
}
const loadContent = async () => {
@@ -285,13 +286,48 @@ const updateValue = async (backend, key, newValue) => {
const handleEvents = async (event, backend) => {
switch (event) {
case 'forceExport':
notification('warning', 'Warning', `We are going to sync '${backend.value.name}' play state to match the current local database.`, 10000)
await navigateTo(makeConsoleCommand(`state:export -fi -v -s ${backend.value.name}`, true))
case 'backupData':
try {
const backup_status = await queue_event('run_console', {
command: 'state:backup',
args: [
'-v',
'--user',
api_user.value,
'--select-backend',
backend.value.name,
'--file',
'{user}.{backend}.{date}.initial_backup.json',
]
})
console.log(backup_status);
notification('info', 'Info', `We are going to initiate a backup for '${backend.value.name}' in little bit.`, 5000)
} catch (e) {
notification('error', 'Error', `Failed to queue backup request. ${e.message}`)
}
break
case 'runImport':
notification('info', 'Info', `We are going to import '${backend.value.name}' play state to the local database.`, 10000)
await navigateTo(makeConsoleCommand(`state:import -v -s ${backend.value.name}`, true))
case 'forceExport':
try {
const export_status = await queue_event('run_console', {
command: 'state:export',
args: [
'-fi',
'-v',
'--user',
api_user.value,
'--dry-run',
'--select-backend',
backend.value.name,
]
}, 180)
console.log(export_status);
notification('info', 'Info', `Soon we are going to force export the local data to '${backend.value.name}'.`, 5000)
} catch (e) {
notification('error', 'Error', `Failed to queue force export request. ${e.message}`)
}
break
case 'addBackend':
toggleForm.value = false
@@ -299,4 +335,5 @@ const handleEvents = async (event, backend) => {
break
}
}
</script>

View File

@@ -253,7 +253,7 @@ const makeGUIDLink = (type, source, guid, data) => {
const link = ag(guid_links, `${type}.${source}`, null)
return null == link ? '' : r(link, { _guid: guid, ...toRaw(data) })
return null == link ? '' : r(link, {_guid: guid, ...toRaw(data)})
}
/**
@@ -339,7 +339,7 @@ const makeSearchLink = (type, query) => {
* @param detail
* @returns {boolean}
*/
const dEvent = (eventName, detail = {}) => window.dispatchEvent(new CustomEvent(eventName, { detail }))
const dEvent = (eventName, detail = {}) => window.dispatchEvent(new CustomEvent(eventName, {detail}))
/**
* Make name
@@ -358,7 +358,7 @@ const makeName = (item, asMovie = false) => {
const type = ag(item, 'type', 'movie');
if (['show', 'movie'].includes(type) || asMovie) {
return r('{title} ({year})', { title, year })
return r('{title} ({year})', {title, year})
}
return r('{title} ({year}) - {season}x{episode}', {
@@ -470,7 +470,7 @@ const parse_api_response = async r => {
try {
return await r.json()
} catch (e) {
return { error: { code: r.status, message: r.statusText } }
return {error: {code: r.status, message: r.statusText}}
}
}
@@ -493,6 +493,39 @@ const goto_history_item = async item => {
await navigateTo(`/history/${item.item_id}`)
}
/**
* Queue event.
*
* @param {string} event The event name.
* @param {object} event_data The event data.
* @param {int} delay delay running the event in XXX seconds.
* @param {object} opts additional options.
*
* @returns {Promise<number>} The status code of the response.
*/
const queue_event = async (event, event_data = {}, delay = 0, opts = {}) => {
let reqData = {event}
if (event_data) {
reqData.event_data = event_data
}
delay = parseInt(delay)
if (0 !== delay) {
reqData.DELAY_BY = delay
}
if (opts) {
reqData = {...reqData, ...opts}
}
const resp = await request(`/system/events`, {
method: 'POST', body: JSON.stringify(reqData)
})
return resp.status
}
export {
r,
ag_set,
@@ -515,5 +548,6 @@ export {
explode,
basename,
parse_api_response,
goto_history_item
goto_history_item,
queue_event
}