from uuid import uuid4 from flask import ( Blueprint, render_template, redirect, url_for, request, flash, ) from flask_login import login_required, current_user from app import db from .models import Plant, PlantCommonName, PlantScientificName from .forms import PlantForm from plugins.media.models import Media from plugins.media.utils import save_media_file, delete_media_file, rotate_media_file, generate_image_url bp = Blueprint( 'plant', __name__, url_prefix='/plants', template_folder='templates' ) # ----------------------------------------------------------------------------- # Make generate_image_url available in all templates # ----------------------------------------------------------------------------- @bp.app_context_processor def inject_image_helper(): return dict(generate_image_url=generate_image_url) # ─── LIST ───────────────────────────────────────────────────────────────────── @bp.route('/', methods=['GET']) @login_required def index(): plants = ( Plant.query .filter_by(owner_id=current_user.id) .order_by(Plant.created_at.desc()) .all() ) stats = { 'user_plants': Plant.query.filter_by(owner_id=current_user.id).count(), 'user_images': Media.query.filter_by(uploader_id=current_user.id).count(), 'total_plants': Plant.query.count(), 'total_images': Media.query.count(), } return render_template('plant/index.html', plants=plants, stats=stats) # ─── CREATE ─────────────────────────────────────────────────────────────────── @bp.route('/create', methods=['GET', 'POST']) @login_required def create(): form = PlantForm() # ─── dropdown choices ─────────────────────────────────────────────────────── form.plant_type.choices = [ ('plant', 'Plant'), ('cutting', 'Cutting'), ('seed', 'Seed'), ('tissue_culture', 'Tissue Culture'), ('division', 'Division'), ] form.common_name.choices = [ (c.id, c.name) for c in PlantCommonName.query.order_by(PlantCommonName.name) ] form.scientific_name.choices = [ (s.id, s.name) for s in PlantScientificName.query.order_by(PlantScientificName.name) ] 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( uuid=str(uuid4()), owner_id=current_user.id, 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 ), custom_slug=form.custom_slug.data, notes=form.notes.data, data_verified=form.data_verified.data, is_active=form.is_active.data, ) db.session.add(new_plant) db.session.commit() flash('New plant created successfully.', 'success') return redirect(url_for('plant.edit', uuid_val=new_plant.uuid)) return render_template('plant/create.html', form=form) # ─── DETAIL ─────────────────────────────────────────────────────────────────── @bp.route('/', methods=['GET']) @login_required def detail(uuid_val): plant = Plant.query.filter_by(uuid=str(uuid_val)).first_or_404() return render_template('plant/detail.html', plant=plant) # ─── EDIT ───────────────────────────────────────────────────────────────────── @bp.route('//edit', methods=['GET', 'POST']) @login_required def edit(uuid_val): plant = Plant.query.filter_by(uuid=str(uuid_val)).first_or_404() form = PlantForm() form.plant_type.choices = [ ('plant', 'Plant'), ('cutting', 'Cutting'), ('seed', 'Seed'), ('tissue_culture', 'Tissue Culture'), ('division', 'Division'), ] form.common_name.choices = [ (c.id, c.name) for c in PlantCommonName.query.order_by(PlantCommonName.name) ] form.scientific_name.choices = [ (s.id, s.name) for s in PlantScientificName.query.order_by(PlantScientificName.name) ] 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.filter(Plant.uuid != plant.uuid).all() ] if request.method == 'GET': form.plant_type.data = plant.plant_type form.common_name.data = plant.common_id form.scientific_name.data = plant.scientific_id form.mother_uuid.data = plant.mother_uuid or 'N/A' form.custom_slug.data = plant.custom_slug form.notes.data = plant.notes form.data_verified.data = plant.data_verified form.is_active.data = getattr(plant, 'is_active', True) if form.validate_on_submit(): 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.custom_slug = form.custom_slug.data plant.notes = form.notes.data plant.data_verified = form.data_verified.data plant.is_active = form.is_active.data db.session.commit() flash('Plant updated successfully.', 'success') return redirect(url_for('plant.detail', uuid_val=plant.uuid)) return render_template('plant/edit.html', form=form, plant=plant) # ─── IMAGE ROUTES ──────────────────────────────────────────────────────────── @bp.route('//upload', methods=['POST']) @login_required def upload_image(uuid_val): plant = Plant.query.filter_by(uuid=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') return redirect(url_for('plant.edit', uuid_val=plant.uuid)) @bp.route('//feature/', methods=['POST']) @login_required def set_featured_image(uuid_val, media_id): plant = Plant.query.filter_by(uuid=uuid_val).first_or_404() media = Media.query.get_or_404(media_id) plant.featured_media_id = media.id db.session.commit() flash('Featured image set.', 'success') return redirect(url_for('plant.edit', uuid_val=plant.uuid)) @bp.route('//delete/', methods=['POST']) @login_required def delete_image(uuid_val, media_id): plant = Plant.query.filter_by(uuid=uuid_val).first_or_404() media = Media.query.get_or_404(media_id) delete_media_file(media) flash('Image deleted.', 'success') return redirect(url_for('plant.edit', uuid_val=plant.uuid)) @bp.route('//rotate/', methods=['POST']) @login_required def rotate_image(uuid_val, media_id): plant = Plant.query.filter_by(uuid=uuid_val).first_or_404() media = Media.query.get_or_404(media_id) rotate_media_file(media) flash('Image rotated.', 'success') return redirect(url_for('plant.edit', uuid_val=plant.uuid))