Initial commit
Dieser Commit ist enthalten in:
209
project_manager.py
Normale Datei
209
project_manager.py
Normale Datei
@ -0,0 +1,209 @@
|
||||
"""
|
||||
Project Manager Module
|
||||
Handles project storage, loading, and management
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
from typing import List, Dict, Optional
|
||||
import uuid
|
||||
from utils.logger import logger
|
||||
|
||||
class Project:
|
||||
def __init__(self, name: str, path: str, project_id: str = None):
|
||||
self.id = project_id or str(uuid.uuid4())
|
||||
self.name = name
|
||||
self.path = path
|
||||
self.created_at = datetime.now().isoformat()
|
||||
self.last_accessed = datetime.now().isoformat()
|
||||
self.readme_path = os.path.join(path, "CLAUDE_PROJECT_README.md")
|
||||
self.description = ""
|
||||
self.tags = []
|
||||
self.gitea_repo = None # Format: "owner/repo_name" or None if not linked
|
||||
|
||||
def to_dict(self) -> Dict:
|
||||
"""Convert project to dictionary for JSON storage"""
|
||||
return {
|
||||
'id': self.id,
|
||||
'name': self.name,
|
||||
'path': self.path,
|
||||
'created_at': self.created_at,
|
||||
'last_accessed': self.last_accessed,
|
||||
'readme_path': self.readme_path,
|
||||
'description': self.description,
|
||||
'tags': self.tags,
|
||||
'gitea_repo': self.gitea_repo
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Dict) -> 'Project':
|
||||
"""Create project from dictionary"""
|
||||
project = cls(data['name'], data['path'], data['id'])
|
||||
project.created_at = data.get('created_at', datetime.now().isoformat())
|
||||
project.last_accessed = data.get('last_accessed', datetime.now().isoformat())
|
||||
project.readme_path = data.get('readme_path', os.path.join(data['path'], "CLAUDE_PROJECT_README.md"))
|
||||
project.description = data.get('description', '')
|
||||
project.tags = data.get('tags', [])
|
||||
project.gitea_repo = data.get('gitea_repo', None)
|
||||
return project
|
||||
|
||||
def update_last_accessed(self):
|
||||
"""Update last accessed timestamp"""
|
||||
self.last_accessed = datetime.now().isoformat()
|
||||
|
||||
class ProjectManager:
|
||||
def __init__(self, data_file: str = "data/projects.json"):
|
||||
self.data_file = data_file
|
||||
self.projects: Dict[str, Project] = {}
|
||||
self.vps_project = None
|
||||
self.admin_panel_project = None
|
||||
self._ensure_data_dir()
|
||||
self.load_projects()
|
||||
self._initialize_vps_project()
|
||||
self._initialize_admin_panel_project()
|
||||
|
||||
def _ensure_data_dir(self):
|
||||
"""Ensure data directory exists"""
|
||||
data_dir = os.path.dirname(self.data_file)
|
||||
if data_dir and not os.path.exists(data_dir):
|
||||
os.makedirs(data_dir)
|
||||
|
||||
def _initialize_vps_project(self):
|
||||
"""Initialize the permanent VPS project"""
|
||||
vps_id = "vps-permanent"
|
||||
if vps_id not in self.projects:
|
||||
self.vps_project = Project(
|
||||
name="VPS Server",
|
||||
path="claude-dev@91.99.192.14",
|
||||
project_id=vps_id
|
||||
)
|
||||
self.vps_project.description = "Remote VPS Server with Claude"
|
||||
self.vps_project.tags = ["vps", "remote", "server"]
|
||||
self.projects[vps_id] = self.vps_project
|
||||
self.save_projects()
|
||||
else:
|
||||
self.vps_project = self.projects[vps_id]
|
||||
|
||||
def _initialize_admin_panel_project(self):
|
||||
"""Initialize the permanent Admin Panel project"""
|
||||
admin_id = "admin-panel-permanent"
|
||||
if admin_id not in self.projects:
|
||||
self.admin_panel_project = Project(
|
||||
name="Admin Panel",
|
||||
path="/opt/v2-Docker",
|
||||
project_id=admin_id
|
||||
)
|
||||
self.admin_panel_project.description = "V2 Docker Admin Panel"
|
||||
self.admin_panel_project.tags = ["admin", "docker", "v2"]
|
||||
self.projects[admin_id] = self.admin_panel_project
|
||||
self.save_projects()
|
||||
else:
|
||||
self.admin_panel_project = self.projects[admin_id]
|
||||
|
||||
def load_projects(self):
|
||||
"""Load projects from JSON file"""
|
||||
logger.info("Loading projects from file")
|
||||
if os.path.exists(self.data_file):
|
||||
try:
|
||||
with open(self.data_file, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
for proj_data in data.get('projects', []):
|
||||
project = Project.from_dict(proj_data)
|
||||
self.projects[project.id] = project
|
||||
except Exception as e:
|
||||
print(f"Error loading projects: {e}")
|
||||
self.projects = {}
|
||||
|
||||
def save_projects(self):
|
||||
"""Save projects to JSON file"""
|
||||
logger.debug("Saving projects to file")
|
||||
try:
|
||||
data = {
|
||||
'projects': [proj.to_dict() for proj in self.projects.values()],
|
||||
'last_updated': datetime.now().isoformat()
|
||||
}
|
||||
with open(self.data_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
except Exception as e:
|
||||
print(f"Error saving projects: {e}")
|
||||
|
||||
def add_project(self, name: str, path: str) -> Project:
|
||||
"""Add new project"""
|
||||
logger.info(f"Adding project: {name} at {path}")
|
||||
# Check if project with same path already exists
|
||||
for project in self.projects.values():
|
||||
if project.path == path and project.id != "vps-permanent":
|
||||
# Update existing project
|
||||
project.name = name
|
||||
project.update_last_accessed()
|
||||
self.save_projects()
|
||||
return project
|
||||
|
||||
# Create new project
|
||||
project = Project(name, path)
|
||||
self.projects[project.id] = project
|
||||
self.save_projects()
|
||||
return project
|
||||
|
||||
def remove_project(self, project_id: str) -> bool:
|
||||
"""Remove project by ID"""
|
||||
logger.info(f"Removing project with ID: {project_id}")
|
||||
if project_id in self.projects and project_id not in ["vps-permanent", "admin-panel-permanent"]:
|
||||
del self.projects[project_id]
|
||||
self.save_projects()
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_project(self, project_id: str) -> Optional[Project]:
|
||||
"""Get project by ID"""
|
||||
return self.projects.get(project_id)
|
||||
|
||||
def get_all_projects(self) -> List[Project]:
|
||||
"""Get all projects sorted alphabetically by name"""
|
||||
projects = list(self.projects.values())
|
||||
# Sort alphabetically, but keep VPS and Admin Panel first
|
||||
vps = [p for p in projects if p.id == "vps-permanent"]
|
||||
admin = [p for p in projects if p.id == "admin-panel-permanent"]
|
||||
others = [p for p in projects if p.id not in ["vps-permanent", "admin-panel-permanent"]]
|
||||
others.sort(key=lambda p: p.name.lower()) # Sort alphabetically by name (case-insensitive)
|
||||
return vps + admin + others
|
||||
|
||||
def update_project(self, project_id: str, **kwargs):
|
||||
"""Update project properties"""
|
||||
project = self.get_project(project_id)
|
||||
if project:
|
||||
for key, value in kwargs.items():
|
||||
if hasattr(project, key):
|
||||
setattr(project, key, value)
|
||||
self.save_projects()
|
||||
|
||||
def search_projects(self, query: str) -> List[Project]:
|
||||
"""Search projects by name, path, or tags"""
|
||||
query = query.lower()
|
||||
results = []
|
||||
for project in self.projects.values():
|
||||
if (query in project.name.lower() or
|
||||
query in project.path.lower() or
|
||||
any(query in tag.lower() for tag in project.tags)):
|
||||
results.append(project)
|
||||
return results
|
||||
|
||||
# Test the module
|
||||
if __name__ == "__main__":
|
||||
# Create manager
|
||||
manager = ProjectManager("test_projects.json")
|
||||
|
||||
# Add test projects
|
||||
proj1 = manager.add_project("Test Project 1", "C:\\Users\\test\\project1")
|
||||
proj2 = manager.add_project("Test Project 2", "C:\\Users\\test\\project2")
|
||||
|
||||
# List all projects
|
||||
print("All projects:")
|
||||
for project in manager.get_all_projects():
|
||||
print(f"- {project.name} ({project.path})")
|
||||
|
||||
# Clean up test file
|
||||
import os
|
||||
if os.path.exists("test_projects.json"):
|
||||
os.remove("test_projects.json")
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren