feat: Add project deletion; untrack CLAUDE.md from git
- Add DELETE /project/<id>/delete route with ownership check, active-run guard, filesystem cleanup (shutil.rmtree), and StoryState cascade delete - Add delete button + confirmation modal to project page header - Add delete button + per-project confirmation modal to dashboard cards - Add CLAUDE.md to .gitignore and remove it from git tracking Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ import shutil
|
||||
from datetime import datetime
|
||||
from flask import Blueprint, render_template, request, redirect, url_for, flash
|
||||
from flask_login import login_required, current_user
|
||||
from web.db import db, Project, Run, Persona
|
||||
from web.db import db, Project, Run, Persona, StoryState
|
||||
from web.helpers import is_project_locked
|
||||
from core import config, utils
|
||||
from ai import models as ai_models
|
||||
@@ -392,6 +392,36 @@ def run_project(id):
|
||||
return redirect(url_for('project.view_project', id=id))
|
||||
|
||||
|
||||
@project_bp.route('/project/<int:id>/delete', methods=['POST'])
|
||||
@login_required
|
||||
def delete_project(id):
|
||||
proj = db.session.get(Project, id) or Project.query.get_or_404(id)
|
||||
if proj.user_id != current_user.id:
|
||||
return "Unauthorized", 403
|
||||
|
||||
active = Run.query.filter_by(project_id=id).filter(Run.status.in_(['running', 'queued'])).first()
|
||||
if active:
|
||||
flash("Cannot delete a project with an active run. Stop the run first.", "danger")
|
||||
return redirect(url_for('project.view_project', id=id))
|
||||
|
||||
# Delete filesystem folder
|
||||
if proj.folder_path and os.path.exists(proj.folder_path):
|
||||
try:
|
||||
shutil.rmtree(proj.folder_path)
|
||||
except Exception as e:
|
||||
flash(f"Warning: could not delete project files: {e}", "warning")
|
||||
|
||||
# Delete StoryState records (no cascade on Project yet)
|
||||
StoryState.query.filter_by(project_id=id).delete()
|
||||
|
||||
# Delete project (cascade handles Runs and LogEntries)
|
||||
db.session.delete(proj)
|
||||
db.session.commit()
|
||||
|
||||
flash("Project deleted.", "success")
|
||||
return redirect(url_for('project.index'))
|
||||
|
||||
|
||||
@project_bp.route('/project/<int:id>/review')
|
||||
@login_required
|
||||
def review_project(id):
|
||||
|
||||
Reference in New Issue
Block a user