mirror of
https://github.com/xpltdco/media-rip.git
synced 2026-04-03 02:53:58 -06:00
Privacy Mode feature: - Toggle in Admin > Settings enables automatic purge of download history, session logs, and files after configurable retention period - Default retention: 24 hours when privacy mode is on - Configurable 1-8760 hours via number input - When enabled, starts purge scheduler (every 30 min) if not running - When disabled, data persists indefinitely Admin panel consolidation: - Removed separate 'Purge' tab — manual purge moved to Settings - Settings tab order: Privacy Mode > Manual Purge > Welcome Message > Output Formats > Change Password - Toggle switch UI with accent color and smooth animation - Retention input with left accent border and unit label Backend: - PurgeConfig: added privacy_mode (bool) and privacy_retention_hours - Purge service: uses privacy_retention_hours when privacy mode active - PUT /admin/settings: accepts privacy_mode + privacy_retention_hours - GET /config/public: exposes privacy settings to frontend - Runtime overrides passed to purge service via config._runtime_overrides
146 lines
3.5 KiB
TypeScript
146 lines
3.5 KiB
TypeScript
/**
|
|
* Admin Pinia store — manages admin authentication and API calls.
|
|
*/
|
|
|
|
import { ref, computed } from 'vue'
|
|
import { defineStore } from 'pinia'
|
|
import type { PublicConfig } from '@/api/types'
|
|
|
|
interface AdminSession {
|
|
id: string
|
|
created_at: string
|
|
last_seen: string
|
|
job_count: number
|
|
}
|
|
|
|
interface StorageInfo {
|
|
disk: { total: number; used: number; free: number }
|
|
jobs_by_status: Record<string, number>
|
|
}
|
|
|
|
interface PurgeResult {
|
|
rows_deleted: number
|
|
files_deleted: number
|
|
files_missing: number
|
|
active_skipped: number
|
|
}
|
|
|
|
export const useAdminStore = defineStore('admin', () => {
|
|
const username = ref('')
|
|
const password = ref('')
|
|
const isAuthenticated = ref(false)
|
|
const authError = ref<string | null>(null)
|
|
const sessions = ref<AdminSession[]>([])
|
|
const storage = ref<StorageInfo | null>(null)
|
|
const purgeResult = ref<PurgeResult | null>(null)
|
|
const isLoading = ref(false)
|
|
|
|
function _authHeaders(): Record<string, string> {
|
|
const encoded = btoa(`${username.value}:${password.value}`)
|
|
return { Authorization: `Basic ${encoded}` }
|
|
}
|
|
|
|
async function login(user: string, pass: string): Promise<boolean> {
|
|
username.value = user
|
|
password.value = pass
|
|
authError.value = null
|
|
|
|
try {
|
|
const res = await fetch('/api/admin/sessions', {
|
|
headers: _authHeaders(),
|
|
})
|
|
if (res.ok) {
|
|
isAuthenticated.value = true
|
|
const data = await res.json()
|
|
sessions.value = data.sessions
|
|
return true
|
|
} else if (res.status === 401) {
|
|
authError.value = 'Invalid credentials'
|
|
isAuthenticated.value = false
|
|
return false
|
|
} else if (res.status === 404) {
|
|
authError.value = 'Admin panel is not enabled'
|
|
isAuthenticated.value = false
|
|
return false
|
|
}
|
|
authError.value = `Unexpected error: ${res.status}`
|
|
return false
|
|
} catch (err: any) {
|
|
authError.value = err.message || 'Network error'
|
|
return false
|
|
}
|
|
}
|
|
|
|
function logout(): void {
|
|
username.value = ''
|
|
password.value = ''
|
|
isAuthenticated.value = false
|
|
sessions.value = []
|
|
storage.value = null
|
|
purgeResult.value = null
|
|
}
|
|
|
|
async function loadSessions(): Promise<void> {
|
|
const res = await fetch('/api/admin/sessions', { headers: _authHeaders() })
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
sessions.value = data.sessions
|
|
}
|
|
}
|
|
|
|
async function loadStorage(): Promise<void> {
|
|
const res = await fetch('/api/admin/storage', { headers: _authHeaders() })
|
|
if (res.ok) {
|
|
storage.value = await res.json()
|
|
}
|
|
}
|
|
|
|
async function triggerPurge(): Promise<void> {
|
|
isLoading.value = true
|
|
try {
|
|
const res = await fetch('/api/admin/purge', {
|
|
method: 'POST',
|
|
headers: _authHeaders(),
|
|
})
|
|
if (res.ok) {
|
|
purgeResult.value = await res.json()
|
|
}
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
|
|
async function updateSettings(data: Record<string, string | boolean | number>): Promise<boolean> {
|
|
isLoading.value = true
|
|
try {
|
|
const res = await fetch('/api/admin/settings', {
|
|
method: 'PUT',
|
|
headers: {
|
|
..._authHeaders(),
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(data),
|
|
})
|
|
return res.ok
|
|
} finally {
|
|
isLoading.value = false
|
|
}
|
|
}
|
|
|
|
return {
|
|
username,
|
|
password,
|
|
isAuthenticated,
|
|
authError,
|
|
sessions,
|
|
storage,
|
|
purgeResult,
|
|
isLoading,
|
|
login,
|
|
logout,
|
|
loadSessions,
|
|
loadStorage,
|
|
triggerPurge,
|
|
updateSettings,
|
|
}
|
|
})
|