stuff is working again

This commit is contained in:
2025-06-26 05:21:21 -05:00
parent 7a8ec5face
commit 00fd49c79b
12 changed files with 639 additions and 272 deletions

View File

@ -1,5 +1,6 @@
from uuid import uuid4
import os
import string
from sqlalchemy.orm import joinedload
from flask import (
@ -14,7 +15,7 @@ from flask import (
from flask_login import login_required, current_user
from app import db
from .models import Plant, PlantCommonName, PlantScientificName
from .models import Plant, PlantScientificName, PlantCommonName
from .forms import PlantForm
from plugins.media.models import Media
from plugins.media.routes import (
@ -76,11 +77,10 @@ def index():
stats=stats,
)
@bp.route('/create', methods=['GET', 'POST'])
@bp.route('/', methods=['GET', 'POST'])
@login_required
def create():
form = PlantForm()
form.plant_type.choices = [
('plant', 'Plant'),
('cutting', 'Cutting'),
@ -96,13 +96,6 @@ def create():
(s.id, s.name)
for s in PlantScientificName.query.order_by(PlantScientificName.name).all()
]
form.mother_uuid.choices = [('N/A', 'None')] + [
(
p.uuid,
f"{p.common_name.name if p.common_name else 'Unnamed'} {p.uuid}"
)
for p in Plant.query.order_by(Plant.created_at.desc()).all()
]
if form.validate_on_submit():
new_plant = Plant(
@ -111,11 +104,7 @@ def create():
plant_type=form.plant_type.data,
common_id=form.common_name.data,
scientific_id=form.scientific_name.data,
mother_uuid=(
form.mother_uuid.data
if form.mother_uuid.data != 'N/A'
else None
),
mother_uuid=(form.mother_uuid.data if form.mother_uuid.data != 'N/A' else None),
custom_slug=(form.custom_slug.data.strip() or None),
vendor_name=(form.vendor_name.data.strip() or None),
price=(form.price.data or None),
@ -130,25 +119,97 @@ def create():
return render_template('plant/create.html', form=form)
@bp.route('/<uuid:uuid_val>', methods=['GET'])
@login_required
def detail(uuid_val):
plant = Plant.query.filter_by(
uuid=str(uuid_val),
owner_id=current_user.id,
).first_or_404()
return render_template('plant/detail.html', plant=plant)
# 1) load this plant (and its media) or 404
plant = (
Plant.query
.options(joinedload(Plant.media_items))
.filter_by(uuid=str(uuid_val), owner_id=current_user.id)
.first_or_404()
)
# 2) load any child plants (same owner, mother_uuid pointing here)
children = (
Plant.query
.options(joinedload(Plant.media_items))
.filter_by(owner_id=current_user.id, mother_uuid=plant.uuid)
.order_by(Plant.id)
.all()
)
# 3) build linear nav of this user's plants (by insertion order)
all_plants = (
Plant.query
.filter_by(owner_id=current_user.id)
.order_by(Plant.id)
.all()
)
uuids = [p.uuid for p in all_plants]
try:
idx = uuids.index(str(uuid_val))
except ValueError:
idx = None
prev_uuid = uuids[idx - 1] if idx not in (None, 0) else None
next_uuid = uuids[idx + 1] if idx is not None and idx < len(uuids) - 1 else None
return render_template(
'plant/detail.html',
plant=plant,
children=children,
prev_uuid=prev_uuid,
next_uuid=next_uuid
)
@bp.route('/<uuid:uuid_val>/generate_children', methods=['POST'])
@login_required
def generate_children(uuid_val):
parent = (
Plant.query
.filter_by(uuid=str(uuid_val), owner_id=current_user.id)
.first_or_404()
)
try:
count = int(request.form.get('count', 1))
except ValueError:
count = 1
created = 0
for _ in range(count):
child = Plant(
uuid=str(uuid4()),
owner_id=current_user.id,
plant_type='cutting',
common_id=parent.common_id,
scientific_id=parent.scientific_id,
mother_uuid=parent.uuid,
custom_slug=None,
vendor_name=None,
price=None,
notes=None,
data_verified=False,
is_active=True
)
db.session.add(child)
created += 1
db.session.commit()
flash(f"Generated {created} cuttings for {parent.common_name.name}.", 'success')
return redirect(url_for('plant.detail', uuid_val=parent.uuid))
@bp.route('/<uuid:uuid_val>/edit', methods=['GET', 'POST'])
@login_required
def edit(uuid_val):
plant = Plant.query.filter_by(
uuid=str(uuid_val),
owner_id=current_user.id,
owner_id=current_user.id
).first_or_404()
form = PlantForm()
form.plant_type.choices = [
('plant', 'Plant'),
('cutting', 'Cutting'),
@ -165,10 +226,7 @@ def edit(uuid_val):
for s in PlantScientificName.query.order_by(PlantScientificName.name).all()
]
form.mother_uuid.choices = [('N/A', 'None')] + [
(
p.uuid,
f"{p.common_name.name if p.common_name else 'Unnamed'} {p.uuid}"
)
(p.uuid, f"{p.common_name.name if p.common_name else 'Unnamed'} {p.uuid}")
for p in Plant.query.filter(Plant.uuid != plant.uuid).all()
]
@ -188,22 +246,15 @@ def edit(uuid_val):
plant.plant_type = form.plant_type.data
plant.common_id = form.common_name.data
plant.scientific_id = form.scientific_name.data
plant.mother_uuid = (
form.mother_uuid.data
if form.mother_uuid.data != 'N/A'
else None
)
plant.mother_uuid = (form.mother_uuid.data if form.mother_uuid.data != 'N/A' else None)
plant.custom_slug = (form.custom_slug.data.strip() or None)
plant.vendor_name = (form.vendor_name.data.strip() or None)
plant.price = (form.price.data or None)
plant.price = form.price.data or None
plant.notes = form.notes.data
plant.data_verified = form.data_verified.data
plant.is_active = form.is_active.data
# — patch to save whichever radio was checked —
featured_id = request.form.get("featured_media_id")
if featured_id and featured_id.isdigit():
plant.featured_media_id = int(featured_id)
# (No more inline "featured_media_id" patch here—handled in media plugin)
db.session.commit()
flash('Plant updated successfully.', 'success')
@ -211,32 +262,32 @@ def edit(uuid_val):
return render_template('plant/edit.html', form=form, plant=plant)
@bp.route('/<uuid:uuid_val>/upload', methods=['POST'])
@login_required
def upload_image(uuid_val):
plant = Plant.query.filter_by(uuid=str(uuid_val)).first_or_404()
file = request.files.get('file')
if file and file.filename:
save_media_file(
file,
current_user.id,
related_model='plant',
related_uuid=str(plant.uuid),
)
flash('Image uploaded successfully.', 'success')
plant = Plant.query.filter_by(
uuid=str(uuid_val),
owner_id=current_user.id
).first_or_404()
file = request.files.get('image')
if not file or file.filename == '':
flash('No file selected.', 'danger')
return redirect(url_for('plant.edit', uuid_val=plant.uuid))
try:
media = save_media_file(file, 'plants', plant.id)
media.uploader_id = current_user.id
db.session.add(media)
db.session.commit()
flash('Image uploaded.', 'success')
except Exception as e:
current_app.logger.error(f"Upload failed: {e}")
flash('Failed to upload image.', 'danger')
return redirect(url_for('plant.edit', uuid_val=plant.uuid))
@bp.route("/feature/<int:media_id>", methods=["POST"])
@login_required
def set_featured_image(media_id):
media = Media.query.get_or_404(media_id)
if current_user.id != media.uploader_id and current_user.role != "admin":
return jsonify({"error": "Not authorized"}), 403
plant = media.plant
plant.featured_media_id = media.id
db.session.commit()
return jsonify({"status": "success", "media_id": media.id})
@bp.route('/<uuid:uuid_val>/delete/<int:media_id>', methods=['POST'])
@login_required
@ -247,6 +298,7 @@ def delete_image(uuid_val, media_id):
flash('Image deleted.', 'success')
return redirect(url_for('plant.edit', uuid_val=plant.uuid))
@bp.route('/<uuid:uuid_val>/rotate/<int:media_id>', methods=['POST'])
@login_required
def rotate_image(uuid_val, media_id):
@ -255,3 +307,17 @@ def rotate_image(uuid_val, media_id):
rotate_media_file(media)
flash('Image rotated.', 'success')
return redirect(url_for('plant.edit', uuid_val=plant.uuid))
@bp.route('/f/<string:short_id>')
@bp.route('/<string:short_id>')
def view_card(short_id):
p = Plant.query.filter_by(short_id=short_id).first_or_404()
# 2) owner → straight to the normal detail page
if current_user.is_authenticated and p.owner_id == current_user.id:
return redirect(url_for('plant.detail', uuid_val=p.uuid))
# 3) everyone else → public card
featured = next((m for m in p.media_items if getattr(m, 'featured', False)), None)
return render_template('plant/card.html', plant=p, featured=featured)