feat: Mini-Cloud Plattform - komplette Implementierung Phase 0-8
Selbstgehostete Web-Cloud mit Dateiverwaltung, Kalender, Kontakte, Email-Webclient, Office-Viewer und Passwort-Manager. Backend (Flask/Python): - JWT-Auth mit Access/Refresh Tokens, Benutzerverwaltung - Dateien: Upload/Download, Ordner, Berechtigungen, Share-Links - Kalender: CRUD, Teilen, iCal-Export, CalDAV well-known URLs - Kontakte: Adressbuecher, vCard-Export, Teilen - Email: IMAP/SMTP-Proxy, Multi-Account - Office-Viewer: DOCX/XLSX/PPTX/PDF Vorschau - Passwort-Manager: AES-256-GCM clientseitig, KeePass-Import - Sync-API fuer Desktop/Mobile-Clients - SQLite mit WAL-Modus Frontend (Vue 3 + PrimeVue): - Datei-Explorer mit Breadcrumbs und Share-Dialogen - Monatskalender mit Event-Verwaltung - Kontaktliste mit Adressbuch-Sidebar - Email-Client mit 3-Spalten-Layout - Passwort-Manager mit TOTP und Passwort-Generator - Admin-Panel, Settings, oeffentliche Share-Seite Docker: Multi-Stage Build, Bind Mounts (keine Volumes) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import apiClient from '../api/client'
|
||||
|
||||
export const useFilesStore = defineStore('files', () => {
|
||||
const files = ref([])
|
||||
const breadcrumb = ref([])
|
||||
const currentParentId = ref(null)
|
||||
const loading = ref(false)
|
||||
|
||||
async function loadFiles(parentId = null) {
|
||||
loading.value = true
|
||||
try {
|
||||
currentParentId.value = parentId
|
||||
const params = parentId ? { parent_id: parentId } : {}
|
||||
const response = await apiClient.get('/files', { params })
|
||||
files.value = response.data.files
|
||||
breadcrumb.value = response.data.breadcrumb
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function createFolder(name, parentId = null) {
|
||||
const response = await apiClient.post('/files/folder', {
|
||||
name,
|
||||
parent_id: parentId,
|
||||
})
|
||||
await loadFiles(parentId)
|
||||
return response.data
|
||||
}
|
||||
|
||||
async function uploadFile(file, parentId = null) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
if (parentId) formData.append('parent_id', parentId)
|
||||
|
||||
const response = await apiClient.post('/files/upload', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
})
|
||||
await loadFiles(parentId)
|
||||
return response.data
|
||||
}
|
||||
|
||||
async function deleteFile(fileId) {
|
||||
await apiClient.delete(`/files/${fileId}`)
|
||||
await loadFiles(currentParentId.value)
|
||||
}
|
||||
|
||||
async function renameFile(fileId, newName) {
|
||||
await apiClient.put(`/files/${fileId}`, { name: newName })
|
||||
await loadFiles(currentParentId.value)
|
||||
}
|
||||
|
||||
async function moveFile(fileId, newParentId) {
|
||||
await apiClient.put(`/files/${fileId}`, { parent_id: newParentId })
|
||||
await loadFiles(currentParentId.value)
|
||||
}
|
||||
|
||||
async function createShareLink(fileId, options = {}) {
|
||||
const response = await apiClient.post(`/files/${fileId}/share`, options)
|
||||
return response.data
|
||||
}
|
||||
|
||||
async function getShareLinks(fileId) {
|
||||
const response = await apiClient.get(`/files/${fileId}/shares`)
|
||||
return response.data
|
||||
}
|
||||
|
||||
async function deleteShareLink(token) {
|
||||
await apiClient.delete(`/share/${token}`)
|
||||
}
|
||||
|
||||
function downloadUrl(fileId) {
|
||||
return `/api/files/${fileId}/download`
|
||||
}
|
||||
|
||||
return {
|
||||
files, breadcrumb, currentParentId, loading,
|
||||
loadFiles, createFolder, uploadFile, deleteFile,
|
||||
renameFile, moveFile, createShareLink, getShareLinks,
|
||||
deleteShareLink, downloadUrl,
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user