Standardize tenant DB directory to db with legacy migration
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
import sqlite3
|
|
||||||
import os
|
import os
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
db_path = r'workspace/workspace_user_33Gz1FPI86VDXhRY8QN4ragRFGN/db/alwrity_user_33Gz1FPI86VDXhRY8QN4ragRFGN.db'
|
from services.database import get_user_db_path
|
||||||
|
|
||||||
|
USER_ID = "user_33Gz1FPI86VDXhRY8QN4ragRFGN"
|
||||||
|
db_path = get_user_db_path(USER_ID)
|
||||||
|
|
||||||
if os.path.exists(db_path):
|
if os.path.exists(db_path):
|
||||||
conn = sqlite3.connect(db_path)
|
conn = sqlite3.connect(db_path)
|
||||||
|
|||||||
@@ -19,18 +19,8 @@ from services.subscription import UsageTrackingService, PricingService
|
|||||||
USER_ID = "user_33Gz1FPI86VDXhRY8QN4ragRFGN"
|
USER_ID = "user_33Gz1FPI86VDXhRY8QN4ragRFGN"
|
||||||
|
|
||||||
def get_db_path(user_id):
|
def get_db_path(user_id):
|
||||||
# Logic from database.py to resolve path
|
from services.database import get_user_db_path
|
||||||
base_path = os.getcwd()
|
return get_user_db_path(user_id)
|
||||||
# Sanitize user_id
|
|
||||||
safe_user_id = "".join(c for c in user_id if c.isalnum() or c in ('-', '_'))
|
|
||||||
user_workspace = os.path.join(base_path, "workspace", f"workspace_{safe_user_id}")
|
|
||||||
# Try both naming conventions
|
|
||||||
db_path_v1 = os.path.join(user_workspace, "db", "alwrity.db")
|
|
||||||
db_path_v2 = os.path.join(user_workspace, "db", f"alwrity_{safe_user_id}.db")
|
|
||||||
|
|
||||||
if os.path.exists(db_path_v2):
|
|
||||||
return db_path_v2
|
|
||||||
return db_path_v1
|
|
||||||
|
|
||||||
def check_user_data():
|
def check_user_data():
|
||||||
db_path = get_db_path(USER_ID)
|
db_path = get_db_path(USER_ID)
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
|
# Add backend to path
|
||||||
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
|
from services.database import get_user_db_path
|
||||||
|
|
||||||
user_id = "user_33Gz1FPI86VDXhRY8QN4ragRFGN"
|
user_id = "user_33Gz1FPI86VDXhRY8QN4ragRFGN"
|
||||||
base_path = os.getcwd()
|
db_path = get_user_db_path(user_id)
|
||||||
safe_user_id = "".join(c for c in user_id if c.isalnum() or c in ('-', '_'))
|
|
||||||
user_workspace = os.path.join(base_path, "workspace", f"workspace_{safe_user_id}")
|
|
||||||
db_path = os.path.join(user_workspace, "db", f"alwrity_{safe_user_id}.db")
|
|
||||||
|
|
||||||
print(f"Reading from: {db_path}")
|
print(f"Reading from: {db_path}")
|
||||||
|
|
||||||
|
|||||||
@@ -9,16 +9,10 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|||||||
from services.database import get_user_db_path
|
from services.database import get_user_db_path
|
||||||
|
|
||||||
user_id = "user_33Gz1FPI86VDXhRY8QN4ragRFGN"
|
user_id = "user_33Gz1FPI86VDXhRY8QN4ragRFGN"
|
||||||
base_path = os.getcwd()
|
resolved = get_user_db_path(user_id)
|
||||||
safe_user_id = "".join(c for c in user_id if c.isalnum() or c in ('-', '_'))
|
legacy_filename = "alwrity.db"
|
||||||
user_workspace = os.path.join(base_path, "workspace", f"workspace_{safe_user_id}")
|
print(f"Resolved active DB path for user {user_id}: {resolved}")
|
||||||
|
print(f"Legacy filename still supported in db/: {legacy_filename}")
|
||||||
path1 = os.path.join(user_workspace, "db", "alwrity.db")
|
|
||||||
path2 = os.path.join(user_workspace, "db", f"alwrity_{safe_user_id}.db")
|
|
||||||
|
|
||||||
print(f"Checking paths for user {user_id}:")
|
|
||||||
print(f"Legacy: {path1}")
|
|
||||||
print(f"Specific: {path2}")
|
|
||||||
|
|
||||||
def check_db(path):
|
def check_db(path):
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
@@ -35,9 +29,7 @@ def check_db(path):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" [EXISTS] {path} - Error reading: {e}")
|
print(f" [EXISTS] {path} - Error reading: {e}")
|
||||||
|
|
||||||
check_db(path1)
|
check_db(resolved)
|
||||||
check_db(path2)
|
|
||||||
|
|
||||||
print("-" * 30)
|
print("-" * 30)
|
||||||
resolved = get_user_db_path(user_id)
|
|
||||||
print(f"Application resolves to: {resolved}")
|
print(f"Application resolves to: {resolved}")
|
||||||
|
|||||||
@@ -53,16 +53,57 @@ WORKSPACE_DIR = os.path.join(ROOT_DIR, 'workspace')
|
|||||||
# Engine cache for multi-tenant support
|
# Engine cache for multi-tenant support
|
||||||
_user_engines = {}
|
_user_engines = {}
|
||||||
|
|
||||||
|
|
||||||
|
def _sanitize_user_id(user_id: str) -> str:
|
||||||
|
"""Sanitize user_id to be safe for filesystem."""
|
||||||
|
return "".join(c for c in user_id if c.isalnum() or c in ('-', '_'))
|
||||||
|
|
||||||
|
|
||||||
|
def ensure_user_workspace_db_directory(user_id: str) -> str:
|
||||||
|
"""Ensure modern `db/` directory exists, migrating legacy `database/` when safe."""
|
||||||
|
safe_user_id = _sanitize_user_id(user_id)
|
||||||
|
user_workspace = os.path.join(WORKSPACE_DIR, f"workspace_{safe_user_id}")
|
||||||
|
db_dir = os.path.join(user_workspace, 'db')
|
||||||
|
legacy_db_dir = os.path.join(user_workspace, 'database')
|
||||||
|
|
||||||
|
if os.path.isdir(legacy_db_dir) and not os.path.exists(db_dir):
|
||||||
|
try:
|
||||||
|
os.rename(legacy_db_dir, db_dir)
|
||||||
|
logger.info(f"Migrated legacy database directory to db/: {user_workspace}")
|
||||||
|
except OSError as rename_error:
|
||||||
|
logger.warning(
|
||||||
|
f"Could not rename legacy database directory for {user_workspace}: {rename_error}"
|
||||||
|
)
|
||||||
|
os.makedirs(db_dir, exist_ok=True)
|
||||||
|
for filename in os.listdir(legacy_db_dir):
|
||||||
|
src = os.path.join(legacy_db_dir, filename)
|
||||||
|
dst = os.path.join(db_dir, filename)
|
||||||
|
if os.path.isfile(src) and not os.path.exists(dst):
|
||||||
|
try:
|
||||||
|
os.link(src, dst)
|
||||||
|
except OSError:
|
||||||
|
# Fall back to copy when hard-linking is not possible.
|
||||||
|
import shutil
|
||||||
|
shutil.copy2(src, dst)
|
||||||
|
else:
|
||||||
|
os.makedirs(db_dir, exist_ok=True)
|
||||||
|
|
||||||
|
return db_dir
|
||||||
|
|
||||||
def get_user_db_path(user_id: str) -> str:
|
def get_user_db_path(user_id: str) -> str:
|
||||||
"""Get the database path for a specific user."""
|
"""Get the database path for a specific user."""
|
||||||
# Sanitize user_id to be safe for filesystem
|
safe_user_id = _sanitize_user_id(user_id)
|
||||||
safe_user_id = "".join(c for c in user_id if c.isalnum() or c in ('-', '_'))
|
|
||||||
user_workspace = os.path.join(WORKSPACE_DIR, f"workspace_{safe_user_id}")
|
user_workspace = os.path.join(WORKSPACE_DIR, f"workspace_{safe_user_id}")
|
||||||
|
db_dir = ensure_user_workspace_db_directory(user_id)
|
||||||
|
|
||||||
# Check for legacy naming convention first (to support existing data)
|
# Check for legacy naming convention first (to support existing data)
|
||||||
# Some older workspaces might have 'alwrity.db' instead of 'alwrity_{user_id}.db'
|
# Some older workspaces might have 'alwrity.db' instead of 'alwrity_{user_id}.db'
|
||||||
legacy_db_path = os.path.join(user_workspace, 'db', 'alwrity.db')
|
legacy_db_path = os.path.join(db_dir, 'alwrity.db')
|
||||||
specific_db_path = os.path.join(user_workspace, 'db', f'alwrity_{safe_user_id}.db')
|
specific_db_path = os.path.join(db_dir, f'alwrity_{safe_user_id}.db')
|
||||||
|
|
||||||
|
# Backward compatibility when filesystem migration couldn't run yet.
|
||||||
|
legacy_dir_path = os.path.join(user_workspace, 'database', f'alwrity_{safe_user_id}.db')
|
||||||
|
legacy_dir_default = os.path.join(user_workspace, 'database', 'alwrity.db')
|
||||||
|
|
||||||
# If the specific one exists, use it (preferred)
|
# If the specific one exists, use it (preferred)
|
||||||
if os.path.exists(specific_db_path):
|
if os.path.exists(specific_db_path):
|
||||||
@@ -72,6 +113,12 @@ def get_user_db_path(user_id: str) -> str:
|
|||||||
if os.path.exists(legacy_db_path):
|
if os.path.exists(legacy_db_path):
|
||||||
return legacy_db_path
|
return legacy_db_path
|
||||||
|
|
||||||
|
if os.path.exists(legacy_dir_path):
|
||||||
|
return legacy_dir_path
|
||||||
|
|
||||||
|
if os.path.exists(legacy_dir_default):
|
||||||
|
return legacy_dir_default
|
||||||
|
|
||||||
# Default to specific for new databases
|
# Default to specific for new databases
|
||||||
return specific_db_path
|
return specific_db_path
|
||||||
|
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ class DeepCrawlService:
|
|||||||
# Note: Path logic should be consistent with project structure
|
# Note: Path logic should be consistent with project structure
|
||||||
# Assuming workspace path is available via env or config, or constructing it.
|
# Assuming workspace path is available via env or config, or constructing it.
|
||||||
# Using relative path for now, adjusted to project root.
|
# Using relative path for now, adjusted to project root.
|
||||||
# The memory says: workspace/workspace_{user_id}/db/alwrity.db
|
# Database files are stored under workspace/workspace_{user_id}/db/.
|
||||||
# So workspace root is workspace/workspace_{user_id}/
|
# So workspace root is workspace/workspace_{user_id}/
|
||||||
workspace_dir = f"workspace/workspace_{user_id}/crawled_content"
|
workspace_dir = f"workspace/workspace_{user_id}/crawled_content"
|
||||||
os.makedirs(workspace_dir, exist_ok=True)
|
os.makedirs(workspace_dir, exist_ok=True)
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from loguru import logger
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
|
|
||||||
from services.database import init_user_database
|
from services.database import init_user_database, ensure_user_workspace_db_directory
|
||||||
|
|
||||||
class UserWorkspaceManager:
|
class UserWorkspaceManager:
|
||||||
"""Manages user-specific workspaces and progressive setup."""
|
"""Manages user-specific workspaces and progressive setup."""
|
||||||
@@ -36,6 +36,11 @@ class UserWorkspaceManager:
|
|||||||
"""Sanitize user_id to be safe for filesystem (matches database.py logic)."""
|
"""Sanitize user_id to be safe for filesystem (matches database.py logic)."""
|
||||||
return "".join(c for c in user_id if c.isalnum() or c in ('-', '_'))
|
return "".join(c for c in user_id if c.isalnum() or c in ('-', '_'))
|
||||||
|
|
||||||
|
def _ensure_workspace_db_directory(self, user_id: str) -> None:
|
||||||
|
"""Ensure workspace uses canonical `db/` layout via database service authority."""
|
||||||
|
ensure_user_workspace_db_directory(user_id)
|
||||||
|
|
||||||
|
|
||||||
def create_user_workspace(self, user_id: str) -> Dict[str, Any]:
|
def create_user_workspace(self, user_id: str) -> Dict[str, Any]:
|
||||||
"""Create a complete user workspace with progressive setup."""
|
"""Create a complete user workspace with progressive setup."""
|
||||||
try:
|
try:
|
||||||
@@ -60,6 +65,9 @@ class UserWorkspaceManager:
|
|||||||
user_dir = self.user_workspaces_dir / f"workspace_{safe_user_id}"
|
user_dir = self.user_workspaces_dir / f"workspace_{safe_user_id}"
|
||||||
user_dir.mkdir(parents=True, exist_ok=True)
|
user_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Ensure canonical DB directory and migrate legacy layout if needed
|
||||||
|
self._ensure_workspace_db_directory(user_id)
|
||||||
|
|
||||||
# Create subdirectories
|
# Create subdirectories
|
||||||
subdirs = [
|
subdirs = [
|
||||||
"content",
|
"content",
|
||||||
@@ -74,8 +82,7 @@ class UserWorkspaceManager:
|
|||||||
"cache",
|
"cache",
|
||||||
"exports",
|
"exports",
|
||||||
"templates",
|
"templates",
|
||||||
"database",
|
"db", # Official database folder
|
||||||
"db", # Requested 'db' folder
|
|
||||||
"media", # Requested 'media' folder
|
"media", # Requested 'media' folder
|
||||||
"data" # User specific data folder
|
"data" # User specific data folder
|
||||||
]
|
]
|
||||||
@@ -359,7 +366,7 @@ class UserWorkspaceManager:
|
|||||||
shutil.rmtree(user_dir)
|
shutil.rmtree(user_dir)
|
||||||
|
|
||||||
# Note: We do not drop tables here because each user has their own DB file
|
# Note: We do not drop tables here because each user has their own DB file
|
||||||
# (alwrity.db) inside their workspace. Deleting the workspace folder
|
# inside workspace/workspace_{id}/db/. Deleting the workspace folder
|
||||||
# deletes the DB file as well.
|
# deletes the DB file as well.
|
||||||
|
|
||||||
logger.info(f"✅ User workspace cleaned up for user {user_id}")
|
logger.info(f"✅ User workspace cleaned up for user {user_id}")
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
db_path = r'c:\Users\diksha rawat\Desktop\ALwrity\workspace\workspace_alwrity\db\alwrity_alwrity.db'
|
from services.database import get_user_db_path
|
||||||
|
|
||||||
|
USER_ID = "alwrity"
|
||||||
|
db_path = get_user_db_path(USER_ID)
|
||||||
|
|
||||||
conn = sqlite3.connect(db_path)
|
conn = sqlite3.connect(db_path)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|||||||
Reference in New Issue
Block a user