Skip to content

Commit

Permalink
feat(backup): save Boorus and restore old backups
Browse files Browse the repository at this point in the history
  • Loading branch information
AlejandroAkbal committed Jan 13, 2024
1 parent bbe98fc commit 2b476ad
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 26 deletions.
133 changes: 115 additions & 18 deletions assets/js/BackupHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,62 @@ import { cloneDeep, toLower, union, unionWith } from 'lodash-es'
import type { Domain } from '~/assets/js/domain'
import { booruTypeList } from '~/assets/lib/rule-34-shared-resources/src/util/BooruUtils'
import type { IPost } from '~/assets/js/post'
import type { IOldBackupState } from '~/assets/js/oldBackup'

export interface IBackupState {
version: number

saved_posts: ISavedPost[]
boorus: Domain[]
tag_collections: ITagCollection[]
saved_posts: ISavedPost[]

settings: {
[key: string]: any
}
}

export async function createBackupState(): Promise<IBackupState> {
const savedPosts = await postsDb.posts.toArray()
const { booruList } = useBooruList()
const { tagCollections } = useTagCollections()
const savedPosts = await postsDb.posts.toArray()
const userSettings = useUserSettings()

// TODO: Only save data that is not defaulted

const backupState: IBackupState = {
version: 1,

saved_posts: savedPosts,
boorus: booruList.value,
tag_collections: tagCollections.value,
saved_posts: savedPosts,

settings: userSettings
}

return backupState
}

export async function restoreBackupState(backupState: IBackupState): Promise<void> {
if (backupState.version !== 1) {
throw new Error('Backup version not supported')
async function restoreV4Backup(backupState: IBackupState) {
if (backupState.boorus?.length) {
const { booruList } = useBooruList()

booruList.value = backupState.boorus
}

if (backupState.tag_collections?.length) {
const { tagCollections } = useTagCollections()

tagCollections.value = backupState.tag_collections
}

if (backupState.saved_posts) {
if (backupState.saved_posts?.length) {
const { posts } = postsDb

await posts.clear()

await posts.bulkAdd(backupState.saved_posts)
}

if (backupState.tag_collections) {
const { tagCollections } = useTagCollections()

tagCollections.value = backupState.tag_collections
}

if (backupState.settings) {
const userSettings = useUserSettings()

Expand All @@ -72,22 +78,112 @@ export async function restoreBackupState(backupState: IBackupState): Promise<voi
}
}

export function doesHaveOldVersionState(): boolean {
function restoreV3Backup(backupState: IOldBackupState) {
if (backupState.user.custom.boorus?.length) {
const { booruList } = useBooruList()

const migratedBooruList: Domain[] = backupState.user.custom.boorus.map((booru) => {
return {
domain: booru.domain,

type: booruTypeList.find((type) => type.type === booru.type) as Domain['type'],

config: booru.config,

// Doesnt matter if its Premium or not, API is protected
isPremium: false
}
})

booruList.value = migratedBooruList
}

if (backupState.user.custom.tagCollections?.length) {
const { tagCollections } = useTagCollections()

tagCollections.value = backupState.user.custom.tagCollections
}

if (backupState.user.custom.savedPosts?.length) {
const { posts } = postsDb

const oldSavedPostsAsNewSavedPosts = backupState.user.custom.savedPosts.map((oldSavedPost) => {
// Restore date too

const newSavedPost: ISavedPost = {
original_id: oldSavedPost.data.id,
original_domain: oldSavedPost.meta_data.booru_domain,

data: {
id: oldSavedPost.data.id,

score: oldSavedPost.data.score,

high_res_file: oldSavedPost.data.high_res_file,
low_res_file: oldSavedPost.data.low_res_file,
preview_file: oldSavedPost.data.preview_file,

tags: oldSavedPost.data.tags,

rating: oldSavedPost.data.rating,

media_type: oldSavedPost.data.media_type as IPost['media_type'],

sources: oldSavedPost.data.sources
}
}

return newSavedPost
})

posts.clear()

posts.bulkAdd(oldSavedPostsAsNewSavedPosts)
}

// TODO: Restore settings
}

/**
* Attempts to restore a backup, either from the old (<V3) or current (>V4) app version format
* Destroys the current data
*/
export async function tryToRestoreV3OrV4Backup(backup: any): Promise<void> {
// V3 Version check
if ('user' in backup && 'custom' in backup.user) {
restoreV3Backup(backup)
}

// V4 Version check
if (backup.version !== 1) {
throw new Error('Backup version not supported')
}

// TODO: Verify object with Zod

await restoreV4Backup(backup)
}

export function doesBrowserHaveOldVersionState(): boolean {
if (localStorage.getItem('vuex-user')) {
return true
}

return false
}

export function removeOldVersionState() {
export function removeBrowserOldVersionState() {
localStorage.removeItem('vuex-root')
localStorage.removeItem('vuex-user')
localStorage.removeItem('vuex-booru')
localStorage.removeItem('vuex-notifications')
}

export async function migrateOldVersionState(): Promise<void> {
/**
* Migrates the old (V3) browser state to the new one (V4)
* Merges the data
*/
export async function migrateBrowserOldVersionState(): Promise<void> {
const { tagCollections } = useTagCollections()
const userSettings = useUserSettings()
const { booruList } = useBooruList()
Expand Down Expand Up @@ -122,7 +218,8 @@ export async function migrateOldVersionState(): Promise<void> {

config: booru.config,

isPremium: true
// Doesnt matter if its Premium or not, API is protected
isPremium: false
}
}) as Domain[]

Expand Down Expand Up @@ -167,7 +264,7 @@ export async function migrateOldVersionState(): Promise<void> {
await posts.bulkAdd(oldSavedPostsAsNewSavedPosts)
}

removeOldVersionState()
removeBrowserOldVersionState()
}

function mergeTags(tags1: string[], tags2: string[]): string[] {
Expand Down
69 changes: 69 additions & 0 deletions assets/js/oldBackup.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
export interface IOldBackupState {
version: number
user: IOldBackupUser
}

export interface IOldBackupUser {
custom: IOldBackupCustom
}

export interface IOldBackupCustom {
boorus: any[]
tagCollections: IOldBackupTagCollection[]
savedPosts: IOldBackupSavedPost[]
}

export interface IOldBackupTagCollection {
name: string
tags: string[]
}

export interface IOldBackupSavedPost {
/** Booru + The ID of the post, e.g rule34.xxx-1234 */
id: string
data: IOldBackupData
meta_data: IOldBackupMetaData
}

export interface IOldBackupData {
id: number
score: number
high_res_file: IOldBackupHighResFile
low_res_file: IOldBackupLowResFile
preview_file: IOldBackupPreviewFile
tags: IOldBackupTags
sources: string[]
rating: string
media_type: string
}

export interface IOldBackupHighResFile {
url: string
width: number
height: number
}

export interface IOldBackupLowResFile {
url?: string
width: number
height: number
}

export interface IOldBackupPreviewFile {
url: string
width?: number
height?: number
}

export interface IOldBackupTags {
character: string[]
copyright: string[]
artist: string[]
general: string[]
meta: string[]
}

export interface IOldBackupMetaData {
booru_domain: string
created_at: string
}
6 changes: 3 additions & 3 deletions pages/premium/backup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { ArrowDownTrayIcon, ArrowUturnLeftIcon } from '@heroicons/vue/24/solid'
import PageHeader from '~/components/layout/PageHeader.vue'
import { toast } from 'vue-sonner'
import { createBackupState, type IBackupState, restoreBackupState } from '~/assets/js/BackupHelper'
import { createBackupState, type IBackupState, tryToRestoreV3OrV4Backup } from '~/assets/js/BackupHelper'
const fileInputElement = ref<HTMLInputElement | null>(null)
Expand Down Expand Up @@ -66,7 +66,7 @@
const backupState: IBackupState = JSON.parse(await file.text())
try {
await restoreBackupState(backupState)
await tryToRestoreV3OrV4Backup(backupState)
} catch (error) {
toast.error(`Failed to restore backup: ${error}`)
return
Expand All @@ -79,7 +79,7 @@
title: 'Backup'
})
definePageMeta({ middleware: 'auth' })
// definePageMeta({ middleware: 'auth' })
</script>

<template>
Expand Down
4 changes: 2 additions & 2 deletions pages/premium/dashboard.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts" setup>
import { ArrowLeftOnRectangleIcon } from '@heroicons/vue/24/solid'
import { doesHaveOldVersionState } from '~/assets/js/BackupHelper'
import { doesBrowserHaveOldVersionState } from '~/assets/js/BackupHelper'
const { data, signOut: _signOut } = useAuth()
Expand All @@ -27,7 +27,7 @@
}
]
const doesHaveOldVersionStateData = doesHaveOldVersionState()
const doesHaveOldVersionStateData = doesBrowserHaveOldVersionState()
if (doesHaveOldVersionStateData) {
links.unshift({
Expand Down
6 changes: 3 additions & 3 deletions pages/premium/migrate-old-data.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script lang="ts" setup>
import PageHeader from '~/components/layout/PageHeader.vue'
import { migrateOldVersionState, removeOldVersionState } from '~/assets/js/BackupHelper'
import { migrateBrowserOldVersionState, removeBrowserOldVersionState } from '~/assets/js/BackupHelper'
import { toast } from 'vue-sonner'
async function migrateOldData() {
try {
await migrateOldVersionState()
await migrateBrowserOldVersionState()
} catch (error) {
// TODO: Sentry
console.error(error)
Expand All @@ -21,7 +21,7 @@
}
function removeOldData() {
removeOldVersionState()
removeBrowserOldVersionState()
toast.success('Old data removed successfully!')
Expand Down

0 comments on commit 2b476ad

Please sign in to comment.