This commit is contained in:
2025-05-22 21:22:15 +02:00
parent 3d57f842f9
commit 97cb9c8703
156 changed files with 1205 additions and 6603 deletions

240
app.py
View File

@@ -5,14 +5,10 @@ from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash
from werkzeug.utils import secure_filename
import os
from config import Config
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
# Use DATABASE_URL from environment if available, else default to SQLite
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'sqlite:///site.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['UPLOAD_FOLDER'] = 'static/uploads'
app.config['MAX_CONTENT_LENGTH'] = 2 * 1024 * 1024 # 2MB max file size
app.config.from_object(Config)
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
@@ -23,7 +19,7 @@ migrate = Migrate(app, db)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
password_hash = db.Column(db.String(128), nullable=False)
password_hash = db.Column(db.String(256), nullable=False)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
@@ -270,6 +266,14 @@ def manage_environments():
description = request.form['description']
icon_file = request.files.get('icon')
icon_filename = None
if not name:
flash('Name is required!', 'danger')
print('No name provided')
return redirect(url_for('manage_environments'))
if Environment.query.filter_by(name=name).first():
flash('Environment with this name already exists!', 'danger')
print('Duplicate environment name')
return redirect(url_for('manage_environments'))
if icon_file and icon_file.filename:
icon_filename = secure_filename(icon_file.filename)
icon_path = os.path.join('static/icons', icon_filename)
@@ -278,11 +282,18 @@ def manage_environments():
icon_file.save(icon_path)
except Exception as e:
print('Error saving icon:', e)
flash(f'Error saving icon: {e}', 'danger')
try:
environment = Environment(name=name, description=description, icon=icon_filename)
db.session.add(environment)
db.session.commit()
flash('Environment added successfully!', 'success')
return redirect(url_for('manage_environments'))
print('Environment added:', name)
except Exception as e:
db.session.rollback()
print('Error adding environment:', e)
flash(f'Error adding environment: {e}', 'danger')
return redirect(url_for('manage_environments'))
environments = Environment.query.all()
return render_template('manage_environments.html',
environments=environments,
@@ -339,6 +350,14 @@ def manage_climates():
description = request.form['description']
icon_file = request.files.get('icon')
icon_filename = None
if not name:
flash('Name is required!', 'danger')
print('No name provided')
return redirect(url_for('manage_climates'))
if Climate.query.filter_by(name=name).first():
flash('Climate with this name already exists!', 'danger')
print('Duplicate climate name')
return redirect(url_for('manage_climates'))
if icon_file and icon_file.filename:
icon_filename = secure_filename(icon_file.filename)
icon_path = os.path.join('static/icons', icon_filename)
@@ -347,11 +366,18 @@ def manage_climates():
icon_file.save(icon_path)
except Exception as e:
print('Error saving icon:', e)
flash(f'Error saving icon: {e}', 'danger')
try:
climate = Climate(name=name, description=description, icon=icon_filename)
db.session.add(climate)
db.session.commit()
flash('Climate added successfully!', 'success')
return redirect(url_for('manage_climates'))
print('Climate added:', name)
except Exception as e:
db.session.rollback()
print('Error adding climate:', e)
flash(f'Error adding climate: {e}', 'danger')
return redirect(url_for('manage_climates'))
climates = Climate.query.all()
return render_template('manage_climates.html',
climates=climates,
@@ -470,30 +496,59 @@ def new_plant():
picture_file = request.files.get('picture')
picture_filename = None
# Required field checks
if not name:
flash('Name is required!', 'danger')
print('No name provided')
return redirect(url_for('new_plant'))
if not climate_id:
flash('Climate is required!', 'danger')
print('No climate provided')
return redirect(url_for('new_plant'))
if not environment_id:
flash('Environment is required!', 'danger')
print('No environment provided')
return redirect(url_for('new_plant'))
if Plant.query.filter_by(name=name).first():
flash('A plant with this name already exists!', 'danger')
print('Duplicate plant name')
return redirect(url_for('new_plant'))
if picture_file and picture_file.filename:
filename = secure_filename(picture_file.filename)
picture_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
picture_file.save(picture_path)
picture_filename = filename
try:
picture_file.save(picture_path)
picture_filename = filename
except Exception as e:
print('Error saving plant picture:', e)
flash(f'Error saving plant picture: {e}', 'danger')
plant = Plant(
name=name,
picture=picture_filename,
climate_id=climate_id,
environment_id=environment_id,
light_id=light_id,
toxicity_id=toxicity_id,
size_id=size_id,
care_difficulty_id=care_difficulty_id,
growth_rate_id=growth_rate_id,
products=','.join(product_ids),
description=description,
care_guide=care_guide
)
db.session.add(plant)
db.session.commit()
flash('Your plant has been added!', 'success')
return redirect(url_for('home'))
try:
plant = Plant(
name=name,
picture=picture_filename,
climate_id=climate_id,
environment_id=environment_id,
light_id=light_id,
toxicity_id=toxicity_id,
size_id=size_id,
care_difficulty_id=care_difficulty_id,
growth_rate_id=growth_rate_id,
products=','.join(product_ids),
description=description,
care_guide=care_guide
)
db.session.add(plant)
db.session.commit()
flash('Your plant has been added!', 'success')
print('Plant added:', name)
return redirect(url_for('manage_plants', add=1))
except Exception as e:
db.session.rollback()
print('Error adding plant:', e)
flash(f'Error adding plant: {e}', 'danger')
return redirect(url_for('new_plant'))
climates = Climate.query.all()
environments = Environment.query.all()
@@ -591,20 +646,37 @@ def manage_plants():
climates = Climate.query.all()
environments = Environment.query.all()
products = Product.query.all()
lights = Light.query.order_by(Light.name).all()
toxicities = Toxicity.query.order_by(Toxicity.name).all()
sizes = Size.query.order_by(Size.name).all()
difficulties = CareDifficulty.query.order_by(CareDifficulty.name).all()
growth_rates = GrowthRate.query.order_by(GrowthRate.name).all()
# Create dictionaries for easy lookup
climates_dict = {climate.id: climate.name for climate in climates}
environments_dict = {env.id: env.name for env in environments}
return render_template('manage_plants.html',
plants=plants,
climates=climates,
environments=environments,
climates=climates, # list for form
environments=environments, # list for form
climates_dict=climates_dict, # dict for table
environments_dict=environments_dict, # dict for table
products=products,
lights=lights,
toxicities=toxicities,
sizes=sizes,
difficulties=difficulties,
growth_rates=growth_rates,
plant_count=len(plants),
climate_count=len(climates),
environment_count=len(environments),
product_count=len(products),
light_count=len(Light.query.all()),
toxicity_count=len(Toxicity.query.all()),
size_count=len(Size.query.all()),
difficulty_count=len(CareDifficulty.query.all()),
rate_count=len(GrowthRate.query.all()))
light_count=len(lights),
toxicity_count=len(toxicities),
size_count=len(sizes),
difficulty_count=len(difficulties),
rate_count=len(growth_rates))
@app.route('/admin/attributes')
def manage_attributes():
@@ -634,6 +706,14 @@ def manage_lights():
description = request.form['description']
icon_file = request.files.get('icon')
icon_filename = None
if not name:
flash('Name is required!', 'danger')
print('No name provided')
return redirect(url_for('manage_lights'))
if Light.query.filter_by(name=name).first():
flash('Light requirement with this name already exists!', 'danger')
print('Duplicate light name')
return redirect(url_for('manage_lights'))
if icon_file and icon_file.filename:
icon_filename = secure_filename(icon_file.filename)
icon_path = os.path.join('static/icons', icon_filename)
@@ -642,11 +722,18 @@ def manage_lights():
icon_file.save(icon_path)
except Exception as e:
print('Error saving icon:', e)
flash(f'Error saving icon: {e}', 'danger')
try:
light = Light(name=name, description=description, icon=icon_filename)
db.session.add(light)
db.session.commit()
flash('Light requirement added successfully!', 'success')
return redirect(url_for('manage_lights'))
print('Light added:', name)
except Exception as e:
db.session.rollback()
print('Error adding light:', e)
flash(f'Error adding light: {e}', 'danger')
return redirect(url_for('manage_lights'))
lights = Light.query.all()
return render_template('manage_lights.html',
lights=lights,
@@ -703,6 +790,14 @@ def manage_toxicities():
description = request.form['description']
icon_file = request.files.get('icon')
icon_filename = None
if not name:
flash('Name is required!', 'danger')
print('No name provided')
return redirect(url_for('manage_toxicities'))
if Toxicity.query.filter_by(name=name).first():
flash('Toxicity with this name already exists!', 'danger')
print('Duplicate toxicity name')
return redirect(url_for('manage_toxicities'))
if icon_file and icon_file.filename:
icon_filename = secure_filename(icon_file.filename)
icon_path = os.path.join('static/icons', icon_filename)
@@ -711,11 +806,18 @@ def manage_toxicities():
icon_file.save(icon_path)
except Exception as e:
print('Error saving icon:', e)
flash(f'Error saving icon: {e}', 'danger')
try:
toxicity = Toxicity(name=name, description=description, icon=icon_filename)
db.session.add(toxicity)
db.session.commit()
flash('Toxicity level added successfully!', 'success')
return redirect(url_for('manage_toxicities'))
print('Toxicity added:', name)
except Exception as e:
db.session.rollback()
print('Error adding toxicity:', e)
flash(f'Error adding toxicity: {e}', 'danger')
return redirect(url_for('manage_toxicities'))
toxicities = Toxicity.query.all()
return render_template('manage_toxicities.html',
toxicities=toxicities,
@@ -772,6 +874,14 @@ def manage_sizes():
description = request.form['description']
icon_file = request.files.get('icon')
icon_filename = None
if not name:
flash('Name is required!', 'danger')
print('No name provided')
return redirect(url_for('manage_sizes'))
if Size.query.filter_by(name=name).first():
flash('Size with this name already exists!', 'danger')
print('Duplicate size name')
return redirect(url_for('manage_sizes'))
if icon_file and icon_file.filename:
icon_filename = secure_filename(icon_file.filename)
icon_path = os.path.join('static/icons', icon_filename)
@@ -780,11 +890,18 @@ def manage_sizes():
icon_file.save(icon_path)
except Exception as e:
print('Error saving icon:', e)
flash(f'Error saving icon: {e}', 'danger')
try:
size = Size(name=name, description=description, icon=icon_filename)
db.session.add(size)
db.session.commit()
flash('Size category added successfully!', 'success')
return redirect(url_for('manage_sizes'))
print('Size added:', name)
except Exception as e:
db.session.rollback()
print('Error adding size:', e)
flash(f'Error adding size: {e}', 'danger')
return redirect(url_for('manage_sizes'))
sizes = Size.query.all()
return render_template('manage_sizes.html',
sizes=sizes,
@@ -841,6 +958,14 @@ def manage_care_difficulties():
description = request.form['description']
icon_file = request.files.get('icon')
icon_filename = None
if not name:
flash('Name is required!', 'danger')
print('No name provided')
return redirect(url_for('manage_care_difficulties'))
if CareDifficulty.query.filter_by(name=name).first():
flash('Care difficulty with this name already exists!', 'danger')
print('Duplicate care difficulty name')
return redirect(url_for('manage_care_difficulties'))
if icon_file and icon_file.filename:
icon_filename = secure_filename(icon_file.filename)
icon_path = os.path.join('static/icons', icon_filename)
@@ -849,11 +974,18 @@ def manage_care_difficulties():
icon_file.save(icon_path)
except Exception as e:
print('Error saving icon:', e)
flash(f'Error saving icon: {e}', 'danger')
try:
difficulty = CareDifficulty(name=name, description=description, icon=icon_filename)
db.session.add(difficulty)
db.session.commit()
flash('Care difficulty level added successfully!', 'success')
return redirect(url_for('manage_care_difficulties'))
print('Care difficulty added:', name)
except Exception as e:
db.session.rollback()
print('Error adding care difficulty:', e)
flash(f'Error adding care difficulty: {e}', 'danger')
return redirect(url_for('manage_care_difficulties'))
difficulties = CareDifficulty.query.all()
return render_template('manage_care_difficulties.html',
difficulties=difficulties,
@@ -910,6 +1042,14 @@ def manage_growth_rates():
description = request.form['description']
icon_file = request.files.get('icon')
icon_filename = None
if not name:
flash('Name is required!', 'danger')
print('No name provided')
return redirect(url_for('manage_growth_rates'))
if GrowthRate.query.filter_by(name=name).first():
flash('Growth rate with this name already exists!', 'danger')
print('Duplicate growth rate name')
return redirect(url_for('manage_growth_rates'))
if icon_file and icon_file.filename:
icon_filename = secure_filename(icon_file.filename)
icon_path = os.path.join('static/icons', icon_filename)
@@ -918,11 +1058,18 @@ def manage_growth_rates():
icon_file.save(icon_path)
except Exception as e:
print('Error saving icon:', e)
flash(f'Error saving icon: {e}', 'danger')
try:
rate = GrowthRate(name=name, description=description, icon=icon_filename)
db.session.add(rate)
db.session.commit()
flash('Growth rate category added successfully!', 'success')
return redirect(url_for('manage_growth_rates'))
print('Growth rate added:', name)
except Exception as e:
db.session.rollback()
print('Error adding growth rate:', e)
flash(f'Error adding growth rate: {e}', 'danger')
return redirect(url_for('manage_growth_rates'))
rates = GrowthRate.query.all()
return render_template('manage_growth_rates.html',
rates=rates,
@@ -1147,4 +1294,15 @@ def seed_db():
db.session.commit()
if __name__ == "__main__":
with app.app_context():
db.create_all() # Create all tables
# Create admin user if it doesn't exist
admin = User.query.filter_by(username='admin').first()
if not admin:
admin = User(username='admin')
admin.set_password('admin123') # Set a default password
db.session.add(admin)
db.session.commit()
print("Admin user created with username: admin and password: admin123")
seed_db() # Seed initial data
app.run(debug=True)