Add job deletion functionality

- Add delete_queue_item function to database.py with ownership validation
- Add delete_job method to QueueManager class
- Add /job/<id>/delete endpoint in web.py with user authentication
- Update history.html template to show delete button for queued jobs
- Only allow users to delete their own jobs or admins to delete any job
- Add confirmation dialog for job deletion
parent 0c0d80df
......@@ -8,7 +8,7 @@
.history-table { background: white; border-radius: 12px; box-shadow: 0 2px 10px rgba(0,0,0,0.05); overflow: hidden; }
.table-header { padding: 2rem; border-bottom: 1px solid #e5e7eb; }
.table-header h2 { margin: 0; color: #1e293b; }
.job-row { display: grid; grid-template-columns: 1fr 2fr 1fr 100px 100px; gap: 1rem; padding: 1rem 2rem; border-bottom: 1px solid #f1f5f9; align-items: center; }
.job-row { display: grid; grid-template-columns: 1fr 2fr 1fr 100px 100px 120px; gap: 1rem; padding: 1rem 2rem; border-bottom: 1px solid #f1f5f9; align-items: center; }
.job-row:last-child { border-bottom: none; }
.job-type { font-weight: 600; color: #1e293b; }
.job-data { color: #64748b; font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
......@@ -159,12 +159,18 @@
{{ job.status.title() }}
</span>
<div class="job-tokens">{{ job.used_tokens or 0 }}</div>
<div class="job-actions">
{% if job.status == 'completed' %}
<a href="/job_result/{{ job.id }}" class="view-result-link">View Result</a>
{% elif job.status == 'processing' and job.result %}
<div class="job-progress">{{ job.result.get('status', 'Processing...') }}</div>
{% elif job.status == 'queued' %}
<form method="post" action="/job/{{ job.id }}/delete" style="display: inline;" onsubmit="return confirm('Are you sure you want to delete this queued job?')">
<button type="submit" class="delete-btn" style="background: #dc2626; color: white; border: none; padding: 0.25rem 0.5rem; border-radius: 4px; font-size: 0.8rem; cursor: pointer;">Delete</button>
</form>
{% endif %}
</div>
</div>
{% endfor %}
{% if not queue_items %}
<div class="no-jobs">No jobs found. Start by analyzing some media!</div>
......
......@@ -1201,6 +1201,35 @@ def get_queue_position(queue_id: int) -> int:
return row['position'] + 1 if row else 0
def delete_queue_item(queue_id: int, user_id: int = None) -> bool:
"""Delete a queue item. If user_id is provided, only allow deletion by the owner or admin."""
conn = get_db_connection()
cursor = conn.cursor()
if user_id is not None:
# Check ownership or admin role
cursor.execute('SELECT user_id FROM processing_queue WHERE id = ?', (queue_id,))
row = cursor.fetchone()
if not row:
conn.close()
return False
if row['user_id'] != user_id:
# Check if user is admin
cursor.execute('SELECT role FROM users WHERE id = ?', (user_id,))
user_row = cursor.fetchone()
if not user_row or user_row['role'] != 'admin':
conn.close()
return False
# Delete the queue item
cursor.execute('DELETE FROM processing_queue WHERE id = ?', (queue_id,))
conn.commit()
success = cursor.rowcount > 0
conn.close()
return success
# User management functions
def get_all_users() -> List[Dict[str, Any]]:
"""Get all users for admin panel."""
......
......@@ -60,6 +60,11 @@ class QueueManager:
"""Get all jobs for a user."""
return get_user_queue_items(user_id)
def delete_job(self, queue_id: int, user_id: int = None) -> bool:
"""Delete a job from the queue."""
from .database import delete_queue_item
return delete_queue_item(queue_id, user_id)
def _process_queue(self) -> None:
"""Background thread to process queued jobs."""
while self.running:
......
......@@ -321,6 +321,21 @@ def history():
active_page='history')
@app.route('/job/<int:job_id>/delete', methods=['POST'])
@login_required
def delete_job(job_id):
"""Delete a job from the queue."""
user = get_current_user_session()
from .queue import queue_manager
if queue_manager.delete_job(job_id, user['id']):
flash('Job deleted successfully!', 'success')
else:
flash('Failed to delete job or access denied.', 'error')
return redirect(url_for('history'))
@app.route('/job_result/<int:job_id>')
@login_required
def job_result(job_id):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment