feat(workspace): live synchronisation, verbindungsindikator, leere ordner persistenz und sperrkonfliktschutz
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m0s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m0s
This commit is contained in:
1 parent
35fd682fcd
commit
2f92e1f49a
4 files changed
+234
-14
No files matched your search
@@ -362,6 +362,10 @@ func (s *Store) migrate() error {
|
||||
|
||||
"CREATE TABLE IF NOT EXISTS doc_user_folders (user_id TEXT NOT NULL, doc_id TEXT NOT NULL, folder_path TEXT NOT NULL DEFAULT '', created_at TEXT NOT NULL, updated_at TEXT NOT NULL, PRIMARY KEY(user_id, doc_id));",
|
||||
"CREATE INDEX IF NOT EXISTS idx_doc_user_folders_user ON doc_user_folders(user_id);",
|
||||
|
||||
"CREATE TABLE IF NOT EXISTS workspace_folders (id TEXT PRIMARY KEY, user_id TEXT NOT NULL, shared_folder_id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL, sub_path TEXT NOT NULL DEFAULT '', created_at TEXT NOT NULL);",
|
||||
"CREATE INDEX IF NOT EXISTS idx_workspace_folders_user ON workspace_folders(user_id);",
|
||||
"CREATE INDEX IF NOT EXISTS idx_workspace_folders_sf ON workspace_folders(shared_folder_id);",
|
||||
}
|
||||
for _, q := range columnMigrations {
|
||||
_, _ = s.db.Exec(q)
|
||||
@@ -2101,14 +2105,39 @@ func (s *Store) GetFolders(userID string) ([]string, error) {
|
||||
// 2. Add mounted shared folders (so even empty shared folders appear in the tree)
|
||||
mounts, _, err := s.getUserFolderMounts(userID)
|
||||
if err == nil {
|
||||
for _, mPath := range mounts {
|
||||
for sfID, mPath := range mounts {
|
||||
if mPath != "" {
|
||||
addFolderSegments(mPath, folderSet)
|
||||
|
||||
// 2b. Add all subfolders created in this shared folder
|
||||
sRows, err := s.db.Query(`SELECT sub_path FROM workspace_folders WHERE shared_folder_id = ?`, sfID)
|
||||
if err == nil {
|
||||
for sRows.Next() {
|
||||
var sp string
|
||||
if err := sRows.Scan(&sp); err == nil && sp != "" {
|
||||
fullP := mPath + "/" + sp
|
||||
addFolderSegments(fullP, folderSet)
|
||||
}
|
||||
}
|
||||
_ = sRows.Close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Scan physical directories on disk in docDir/userID
|
||||
// 3. Add personal empty folders created by this user
|
||||
pRows, err := s.db.Query(`SELECT path FROM workspace_folders WHERE user_id = ? AND (shared_folder_id = '' OR shared_folder_id IS NULL)`, userID)
|
||||
if err == nil {
|
||||
for pRows.Next() {
|
||||
var p string
|
||||
if err := pRows.Scan(&p); err == nil && p != "" {
|
||||
addFolderSegments(p, folderSet)
|
||||
}
|
||||
}
|
||||
_ = pRows.Close()
|
||||
}
|
||||
|
||||
// 4. Scan physical directories on disk in docDir/userID
|
||||
if s.docDir != "" {
|
||||
userDir := filepath.Join(s.docDir, userID)
|
||||
if fi, err := os.Stat(userDir); err == nil && fi.IsDir() {
|
||||
@@ -2158,6 +2187,31 @@ func (s *Store) CreateFolder(userID, folderPath string) (string, error) {
|
||||
return "", fmt.Errorf("ungültiger Ordnerpfad")
|
||||
}
|
||||
|
||||
mounts, _, err := s.getUserFolderMounts(userID)
|
||||
var sfID, subPath string
|
||||
if err == nil {
|
||||
sfID, subPath, _ = matchMountPath(clean, mounts)
|
||||
}
|
||||
|
||||
now := time.Now().UTC().Format(time.RFC3339)
|
||||
id := domain.NewID("wfld")
|
||||
|
||||
if sfID != "" {
|
||||
var existsID string
|
||||
err := s.db.QueryRow(`SELECT id FROM workspace_folders WHERE shared_folder_id = ? AND sub_path = ?`, sfID, subPath).Scan(&existsID)
|
||||
if err == sql.ErrNoRows {
|
||||
_, _ = s.db.Exec(`INSERT INTO workspace_folders (id, user_id, shared_folder_id, path, sub_path, created_at) VALUES (?, ?, ?, ?, ?, ?)`,
|
||||
id, userID, sfID, clean, subPath, now)
|
||||
}
|
||||
} else {
|
||||
var existsID string
|
||||
err := s.db.QueryRow(`SELECT id FROM workspace_folders WHERE user_id = ? AND path = ? AND (shared_folder_id = '' OR shared_folder_id IS NULL)`, userID, clean).Scan(&existsID)
|
||||
if err == sql.ErrNoRows {
|
||||
_, _ = s.db.Exec(`INSERT INTO workspace_folders (id, user_id, shared_folder_id, path, sub_path, created_at) VALUES (?, ?, '', ?, '', ?)`,
|
||||
id, userID, clean, now)
|
||||
}
|
||||
}
|
||||
|
||||
if s.docDir != "" {
|
||||
targetDir := filepath.Join(s.docDir, userID, clean)
|
||||
if err := os.MkdirAll(targetDir, 0755); err != nil {
|
||||
@@ -2201,6 +2255,21 @@ func (s *Store) DeleteFolder(userID, folderPath string) ([]string, error) {
|
||||
_, _ = s.db.Exec(`DELETE FROM documents WHERE id = ? AND user_id = ?`, id, userID)
|
||||
}
|
||||
|
||||
// Clean up from workspace_folders
|
||||
mounts, _, err := s.getUserFolderMounts(userID)
|
||||
if err == nil {
|
||||
sfID, subPath, isMatch := matchMountPath(clean, mounts)
|
||||
if isMatch && sfID != "" {
|
||||
if subPath == "" {
|
||||
_, _ = s.db.Exec(`DELETE FROM workspace_folders WHERE shared_folder_id = ?`, sfID)
|
||||
} else {
|
||||
_, _ = s.db.Exec(`DELETE FROM workspace_folders WHERE shared_folder_id = ? AND (sub_path = ? OR sub_path LIKE ?)`,
|
||||
sfID, subPath, subPath+"/%")
|
||||
}
|
||||
}
|
||||
}
|
||||
_, _ = s.db.Exec(`DELETE FROM workspace_folders WHERE user_id = ? AND (path = ? OR path LIKE ?)`, userID, clean, clean+"/%")
|
||||
|
||||
// Remove physical folder and subdirectories from disk
|
||||
if s.docDir != "" {
|
||||
targetDir := filepath.Join(s.docDir, userID, clean)
|
||||
@@ -2367,6 +2436,28 @@ func (s *Store) CreateSharedFolder(userID, folderName, initialMountPath string)
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate any existing workspace_folders created by this user in cleanMount
|
||||
fRows, err := s.db.Query(`SELECT id, path FROM workspace_folders WHERE user_id = ? AND (path = ? OR path LIKE ?)`, userID, cleanMount, cleanMount+"/%")
|
||||
if err == nil {
|
||||
type wfEntry struct{ id, path string }
|
||||
var wfEntries []wfEntry
|
||||
for fRows.Next() {
|
||||
var wfe wfEntry
|
||||
if err := fRows.Scan(&wfe.id, &wfe.path); err == nil {
|
||||
wfEntries = append(wfEntries, wfe)
|
||||
}
|
||||
}
|
||||
_ = fRows.Close()
|
||||
|
||||
for _, wfe := range wfEntries {
|
||||
subP := ""
|
||||
if strings.HasPrefix(wfe.path, cleanMount+"/") {
|
||||
subP = strings.TrimPrefix(wfe.path, cleanMount+"/")
|
||||
}
|
||||
_, _ = s.db.Exec(`UPDATE workspace_folders SET shared_folder_id = ?, sub_path = ? WHERE id = ?`, folderID, subP, wfe.id)
|
||||
}
|
||||
}
|
||||
|
||||
var ownerName string
|
||||
_ = s.db.QueryRow(`SELECT display_name FROM users WHERE id = ?`, userID).Scan(&ownerName)
|
||||
|
||||
@@ -2646,6 +2737,7 @@ func (s *Store) DeleteSharedFolder(currentUserID, folderID string) error {
|
||||
_, _ = s.db.Exec(`UPDATE documents SET shared_folder_id = '', sub_folder_path = '' WHERE shared_folder_id = ?`, folderID)
|
||||
_, _ = s.db.Exec(`DELETE FROM workspace_folder_mounts WHERE folder_id = ?`, folderID)
|
||||
_, _ = s.db.Exec(`DELETE FROM workspace_folder_shares WHERE folder_id = ?`, folderID)
|
||||
_, _ = s.db.Exec(`DELETE FROM workspace_folders WHERE shared_folder_id = ?`, folderID)
|
||||
_, err = s.db.Exec(`DELETE FROM workspace_shared_folders WHERE id = ?`, folderID)
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user