Files
natureinpots_community/plugins/plant/routes.py
2025-06-11 02:47:01 -05:00

214 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# plugins/plant/routes.py
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 plant 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
),
# ← HERE: convert blank slug to NULL
custom_slug=(form.custom_slug.data.strip() or None),
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('/<uuid:uuid_val>', methods=['GET'])
@login_required
def detail(uuid_val):
plant = Plant.query.filter_by(uuid=uuid_val).first_or_404()
return render_template('plant/detail.html', plant=plant)
# ─── EDIT ─────────────────────────────────────────────────────────────────────
@bp.route('/<uuid:uuid_val>/edit', methods=['GET', 'POST'])
@login_required
def edit(uuid_val):
plant = Plant.query.filter_by(uuid=uuid_val).first_or_404()
form = PlantForm()
# Populate dropdowns (same as in create)
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 or ''
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
)
# ← HERE as well
plant.custom_slug = (form.custom_slug.data.strip() or None)
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('/<uuid:uuid_val>/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('/<uuid:uuid_val>/feature/<int:media_id>', 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('/<uuid:uuid_val>/delete/<int:media_id>', 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('/<uuid:uuid_val>/rotate/<int:media_id>', 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))