# plugins/plant/growlog/routes.py from uuid import UUID as _UUID from flask import ( Blueprint, render_template, abort, redirect, url_for, request, flash ) from flask_login import login_required, current_user from app import db from .models import GrowLog from .forms import GrowLogForm from plugins.plant.models import Plant, PlantCommonName bp = Blueprint( 'growlog', __name__, url_prefix='/growlogs', template_folder='templates', ) def _get_plant_by_uuid(uuid_val): """ Normalize & validate a UUID (may be a uuid.UUID or a string), then return the Plant owned by current_user or 404. """ # 1) If Flask gave us a real UUID, stringify it if isinstance(uuid_val, _UUID): val = str(uuid_val) else: # 2) Otherwise try to parse it try: val = str(_UUID(uuid_val)) except (ValueError, TypeError): abort(404) # 3) Only return plants owned by this user return ( Plant.query .filter_by(uuid=val, owner_id=current_user.id) .first_or_404() ) def _user_plant_choices(): """ Return [(uuid, "Common Name – uuid"), ...] for all plants owned by current_user, sorted by common name. """ plants = ( Plant.query .filter_by(owner_id=current_user.id) .join(PlantCommonName, Plant.common_id == PlantCommonName.id) .order_by(PlantCommonName.name) .all() ) return [ (p.uuid, f"{p.common_name.name} – {p.uuid}") for p in plants ] @bp.route('/add', methods=['GET','POST']) @bp.route('//add', methods=['GET','POST']) @login_required def add_log(plant_uuid=None): form = GrowLogForm() # always populate the select behind the scenes form.plant_uuid.choices = _user_plant_choices() plant = None hide_select = False # if URL gave us a plant_uuid, lock to that one if plant_uuid: plant = _get_plant_by_uuid(plant_uuid) form.plant_uuid.data = str(plant_uuid) hide_select = True if form.validate_on_submit(): plant = _get_plant_by_uuid(form.plant_uuid.data) log = GrowLog( plant_id = plant.id, event_type = form.event_type.data, title = form.title.data, notes = form.notes.data, is_public = form.is_public.data, ) db.session.add(log) db.session.commit() flash('Grow log added.', 'success') return redirect( url_for('growlog.list_logs', plant_uuid=plant.uuid) ) return render_template( 'growlog/log_form.html', form = form, plant = plant, hide_plant_select = hide_select, ) @bp.route('/', defaults={'plant_uuid': None}) @bp.route('/') @login_required def list_logs(plant_uuid): from plugins.utility.celery import celery_app celery_app.send_task('plugins.utility.tasks.ping') limit = request.args.get('limit', default=10, type=int) if plant_uuid: # logs for one plant plant = _get_plant_by_uuid(plant_uuid) query = GrowLog.query.filter_by(plant_id=plant.id) else: # logs across all of this user’s plants plant = None query = ( GrowLog.query .join(Plant, GrowLog.plant_id == Plant.id) .filter(Plant.owner_id == current_user.id) ) logs = ( query .order_by(GrowLog.created_at.desc()) .limit(limit) .all() ) return render_template( 'growlog/log_list.html', plant = plant, logs = logs, limit = limit, ) @bp.route('//edit/', methods=['GET','POST']) @login_required def edit_log(plant_uuid, log_id): plant = _get_plant_by_uuid(plant_uuid) log = GrowLog.query.filter_by(id=log_id, plant_id=plant.id).first_or_404() form = GrowLogForm(obj=log) # lock the dropdown to this plant form.plant_uuid.choices = [(plant.uuid, plant.common_name.name)] form.plant_uuid.data = plant.uuid if form.validate_on_submit(): log.event_type = form.event_type.data log.title = form.title.data log.notes = form.notes.data log.is_public = form.is_public.data db.session.commit() flash('Grow log updated.', 'success') return redirect(url_for('growlog.list_logs', plant_uuid=plant_uuid)) return render_template( 'growlog/log_form.html', form = form, plant_uuid = plant_uuid, plant = plant, log = log, ) @bp.route('//delete/', methods=['POST']) @login_required def delete_log(plant_uuid, log_id): plant = _get_plant_by_uuid(plant_uuid) log = GrowLog.query.filter_by(id=log_id, plant_id=plant.id).first_or_404() db.session.delete(log) db.session.commit() flash('Grow log deleted.', 'warning') return redirect(url_for('growlog.list_logs', plant_uuid=plant_uuid))