Files
natureinpots_community/plugins/plant/routes.py
2025-06-23 04:08:45 -05:00

258 lines
8.1 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.

from uuid import uuid4
import os
from sqlalchemy.orm import joinedload
from flask import (
Blueprint,
render_template,
redirect,
url_for,
request,
flash,
current_app,
)
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.routes import (
save_media_file,
delete_media_file,
rotate_media_file,
generate_image_url,
)
bp = Blueprint(
'plant',
__name__,
url_prefix='/plants',
template_folder='templates',
)
@bp.app_context_processor
def inject_image_helper():
return dict(generate_image_url=generate_image_url)
@bp.route('/', methods=['GET'])
@login_required
def index():
plants = (
Plant.query
.options(joinedload(Plant.media_items))
.filter_by(owner_id=current_user.id)
.order_by(Plant.id.desc())
.all()
)
user_plants_count = Plant.query.filter_by(owner_id=current_user.id).count()
user_images_count = Media.query.filter_by(uploader_id=current_user.id).count()
total_plants_count = Plant.query.count()
total_images_count = Media.query.count()
plant_types = [
pt[0]
for pt in (
db.session.query(Plant.plant_type)
.filter_by(owner_id=current_user.id)
.distinct()
.all()
)
]
stats = {
'user_plants': user_plants_count,
'user_images': user_images_count,
'total_plants': total_plants_count,
'total_images': total_images_count,
}
return render_template(
'plant/index.html',
plants=plants,
plant_types=plant_types,
stats=stats,
)
@bp.route('/create', methods=['GET', 'POST'])
@login_required
def create():
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).all()
]
form.scientific_name.choices = [
(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(
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.strip() or None),
vendor_name=(form.vendor_name.data.strip() or None),
price=(form.price.data 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)
@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)
@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,
).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).all()
]
form.scientific_name.choices = [
(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.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.vendor_name.data = plant.vendor_name or ''
form.price.data = plant.price or None
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.strip() or None)
plant.vendor_name = (form.vendor_name.data.strip() 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)
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)
@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')
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
def delete_image(uuid_val, media_id):
plant = Plant.query.filter_by(uuid=str(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=str(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))