From 83ce1b236a515a7f75463381d3def2c91f137384 Mon Sep 17 00:00:00 2001 From: amanfromspace Date: Thu, 27 Nov 2025 09:50:55 -0500 Subject: [PATCH] Testing app --- .env.example | 17 ++ .flake8 | 4 + .gitignore | 14 ++ README.md | 11 +- app.py | 552 +++++++++++++++++++++++++++++++++++++++++++++ config.py | 33 +++ requirements.txt | 14 ++ run.py | 21 ++ scripts/install.sh | 7 + wsgi.py | 4 + 10 files changed, 676 insertions(+), 1 deletion(-) create mode 100644 .env.example create mode 100644 .flake8 create mode 100644 .gitignore create mode 100644 app.py create mode 100644 config.py create mode 100644 requirements.txt create mode 100644 run.py create mode 100755 scripts/install.sh create mode 100644 wsgi.py diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b44912e --- /dev/null +++ b/.env.example @@ -0,0 +1,17 @@ +# Copy this file to .env and update with your values + +# Security +SECRET_KEY=change-this-to-a-random-secret-key +FLASK_ENV=development +FLASK_DEBUG=True + +# Database +DB_HOST=localhost +DB_USER=wearwell_user +DB_PASSWORD=your_password_here +DB_NAME=wearwell_db +DB_PORT=3306 + +# Application +FLASK_PORT=5001 +FLASK_HOST=0.0.0.0 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..a45b148 --- /dev/null +++ b/.flake8 @@ -0,0 +1,4 @@ +[flake8] +max-line-length = 88 +extend-ignore = E203, W503 +exclude = .git,__pycache__,venv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3a7a60e --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Environment variables +.env + +# Virtual environment +venv/ +env/ + +# Python cache +__pycache__/ +*.pyc + +# IDE +.vscode/ +.idea/ diff --git a/README.md b/README.md index 9aee135..d3cb19b 100644 --- a/README.md +++ b/README.md @@ -1 +1,10 @@ -Shop Project \ No newline at end of file +# WearWell Flask Application + +## Setup +1. Copy `.env.example` to `.env` +2. Update `.env` with your configuration +3. Install dependencies: `pip install -r requirements.txt` +4. Run: `python run.py` + +## Development +- Use `requirements-dev.txt` for development tools diff --git a/app.py b/app.py new file mode 100644 index 0000000..dedd34d --- /dev/null +++ b/app.py @@ -0,0 +1,552 @@ +# app.py - COMPLETE VERSION +import os +from dotenv import load_dotenv +from flask import Flask, jsonify, request +import pymysql +import pymysql.cursors +from config import config + +# Load environment variables at the start +load_dotenv() + +app = Flask(__name__) + +# Configure the app +env = os.getenv('FLASK_ENV', 'development') +app.config.from_object(config[env]) + +print(f"🔧 App configured for: {env}") +print(f"📡 Will run on port: {app.config['FLASK_PORT']}") + +# Database configuration +def get_db_connection(): + db_config = { + 'host': app.config['DB_HOST'], + 'user': app.config['DB_USER'], + 'password': app.config['DB_PASSWORD'], + 'database': app.config['DB_NAME'], + 'port': app.config['DB_PORT'], + 'charset': 'utf8mb4', + 'cursorclass': pymysql.cursors.DictCursor + } + try: + return pymysql.connect(**db_config) + except pymysql.Error as e: + print(f"Database connection error: {e}") + return None + +def init_users_table(): + """Create users table if it doesn't exist""" + conn = get_db_connection() + if conn: + try: + with conn.cursor() as cursor: + cursor.execute(''' + CREATE TABLE IF NOT EXISTS users ( + id INT AUTO_INCREMENT PRIMARY KEY, + username VARCHAR(80) UNIQUE NOT NULL, + email VARCHAR(120) UNIQUE NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + ''') + conn.commit() + print("✅ Users table is ready") + except Exception as e: + print(f"Error creating users table: {e}") + finally: + conn.close() + +# Initialize the users table when app starts +init_users_table() + +# Routes +@app.route('/') +def hello(): + return jsonify({ + "message": "WearWell API is running!", + "port": app.config['FLASK_PORT'], + "endpoints": { + "health_check": "/health", + "all_users": "/users", + "get_user": "/users/", + "add_user": "/users/add (POST)", + "delete_user": "/users/delete/ (DELETE)", + "web_interface": "/users/manage" + } + }) + +@app.route('/health') +def health_check(): + conn = get_db_connection() + if conn: + conn.close() + return jsonify({"status": "healthy", "database": "connected"}) + else: + return jsonify({"status": "unhealthy", "database": "disconnected"}), 500 + +# User Management Routes +@app.route('/users') +def get_all_users(): + """Get all users""" + conn = get_db_connection() + if not conn: + return jsonify({"error": "Database connection failed"}), 500 + + try: + with conn.cursor() as cursor: + cursor.execute("SELECT * FROM users ORDER BY created_at DESC") + users = cursor.fetchall() + return jsonify({"users": users, "count": len(users)}) + except Exception as e: + return jsonify({"error": str(e)}), 500 + finally: + conn.close() + +@app.route('/users/') +def get_user(user_id): + """Get a specific user by ID""" + conn = get_db_connection() + if not conn: + return jsonify({"error": "Database connection failed"}), 500 + + try: + with conn.cursor() as cursor: + cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) + user = cursor.fetchone() + + if user: + return jsonify({"user": user}) + else: + return jsonify({"error": "User not found"}), 404 + except Exception as e: + return jsonify({"error": str(e)}), 500 + finally: + conn.close() + +@app.route('/users/add', methods=['POST']) +def add_user(): + """Add a new user""" + conn = get_db_connection() + if not conn: + return jsonify({"error": "Database connection failed"}), 500 + + try: + # Check if request is JSON + if not request.is_json: + return jsonify({"error": "Content-Type must be application/json"}), 400 + + data = request.get_json() + + if not data or not data.get('username') or not data.get('email'): + return jsonify({"error": "Username and email are required"}), 400 + + username = data['username'].strip() + email = data['email'].strip() + + # Basic validation + if len(username) < 3: + return jsonify({"error": "Username must be at least 3 characters"}), 400 + + if '@' not in email: + return jsonify({"error": "Invalid email format"}), 400 + + with conn.cursor() as cursor: + cursor.execute( + "INSERT INTO users (username, email) VALUES (%s, %s)", + (username, email) + ) + conn.commit() + user_id = cursor.lastrowid + + return jsonify({ + "message": "User added successfully", + "user_id": user_id, + "username": username, + "email": email + }), 201 + + except pymysql.IntegrityError as e: + if "username" in str(e): + return jsonify({"error": "Username already exists"}), 400 + elif "email" in str(e): + return jsonify({"error": "Email already exists"}), 400 + else: + return jsonify({"error": "Database integrity error"}), 400 + except Exception as e: + return jsonify({"error": str(e)}), 500 + finally: + conn.close() + +@app.route('/users/delete/', methods=['DELETE']) +def delete_user(user_id): + """Delete a user by ID""" + conn = get_db_connection() + if not conn: + return jsonify({"error": "Database connection failed"}), 500 + + try: + with conn.cursor() as cursor: + # First check if user exists + cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,)) + user = cursor.fetchone() + + if not user: + return jsonify({"error": "User not found"}), 404 + + # Delete the user + cursor.execute("DELETE FROM users WHERE id = %s", (user_id,)) + conn.commit() + + return jsonify({ + "message": "User deleted successfully", + "deleted_user": { + "id": user_id, + "username": user['username'], + "email": user['email'] + } + }) + + except Exception as e: + return jsonify({"error": str(e)}), 500 + finally: + conn.close() + +@app.route('/users/update/', methods=['PUT']) +def update_user(user_id): + """Update a user's information""" + conn = get_db_connection() + if not conn: + return jsonify({"error": "Database connection failed"}), 500 + + try: + if not request.is_json: + return jsonify({"error": "Content-Type must be application/json"}), 400 + + data = request.get_json() + + if not data or (not data.get('username') and not data.get('email')): + return jsonify({"error": "At least username or email is required to update"}), 400 + + # Build update query dynamically based on provided fields + update_fields = [] + values = [] + + if 'username' in data and data['username']: + update_fields.append("username = %s") + values.append(data['username'].strip()) + + if 'email' in data and data['email']: + update_fields.append("email = %s") + values.append(data['email'].strip()) + + values.append(user_id) + + with conn.cursor() as cursor: + cursor.execute( + f"UPDATE users SET {', '.join(update_fields)} WHERE id = %s", + values + ) + conn.commit() + + if cursor.rowcount == 0: + return jsonify({"error": "User not found"}), 404 + + return jsonify({"message": "User updated successfully"}) + + except pymysql.IntegrityError as e: + if "username" in str(e): + return jsonify({"error": "Username already exists"}), 400 + elif "email" in str(e): + return jsonify({"error": "Email already exists"}), 400 + else: + return jsonify({"error": "Database integrity error"}), 400 + except Exception as e: + return jsonify({"error": str(e)}), 500 + finally: + conn.close() + +# Web Interface +@app.route('/users/manage') +def manage_users(): + """Simple web interface to manage users""" + return ''' + + + + User Management - WearWell + + + +
+

👥 User Management - WearWell

+ +
+

➕ Add New User

+ + + +
+
+ +
+

📋 Users List

+ +
Loading user count...
+
+
+ +
+

🔧 API Testing

+

Test the API endpoints directly:

+ + + +
+
+ + + + + ''' diff --git a/config.py b/config.py new file mode 100644 index 0000000..5f716f1 --- /dev/null +++ b/config.py @@ -0,0 +1,33 @@ +import os +from dotenv import load_dotenv + +load_dotenv() + +class Config: + SECRET_KEY = os.getenv('SECRET_KEY', 'dev-fallback-key') + FLASK_ENV = os.getenv('FLASK_ENV', 'development') + DEBUG = os.getenv('FLASK_DEBUG', 'False').lower() == 'true' + + # Database + DB_HOST = os.getenv('DB_HOST', 'localhost') + DB_USER = os.getenv('DB_USER', 'wearwell_user') + DB_PASSWORD = os.getenv('DB_PASSWORD', '') + DB_NAME = os.getenv('DB_NAME', 'wearwell_db') + DB_PORT = int(os.getenv('DB_PORT', 3306)) + + # Application + FLASK_PORT = int(os.getenv('FLASK_PORT', 5001)) + FLASK_HOST = os.getenv('FLASK_HOST', '0.0.0.0') + +class DevelopmentConfig(Config): + DEBUG = True + +class ProductionConfig(Config): + DEBUG = False + FLASK_ENV = 'production' + +config = { + 'development': DevelopmentConfig, + 'production': ProductionConfig, + 'default': DevelopmentConfig +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e6d74ab --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +blinker==1.9.0 +cffi==2.0.0 +click==8.3.1 +cryptography==46.0.3 +Flask==3.1.2 +Flask-MySQLdb==2.0.0 +itsdangerous==2.2.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +mysqlclient==2.2.7 +pycparser==2.23 +PyMySQL==1.1.2 +python-dotenv==1.2.1 +Werkzeug==3.1.3 diff --git a/run.py b/run.py new file mode 100644 index 0000000..dcd087a --- /dev/null +++ b/run.py @@ -0,0 +1,21 @@ +# run.py - FIXED VERSION +import os +from dotenv import load_dotenv + +# Load environment variables FIRST +load_dotenv() + +from app import app + +if __name__ == '__main__': + env = os.getenv('FLASK_ENV', 'development') + print(f"🚀 Starting WearWell in {env} mode...") + print(f"📡 Host: {app.config.get('FLASK_HOST', '0.0.0.0')}") + print(f"🔌 Port: {app.config.get('FLASK_PORT', 5000)}") + print(f"🐛 Debug: {app.config.get('DEBUG', False)}") + + app.run( + host=app.config.get('FLASK_HOST', '0.0.0.0'), + port=app.config.get('FLASK_PORT', 5001), + debug=app.config.get('DEBUG', False) + ) diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..85dc36a --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,7 @@ +#!/bin/bash +echo "Setting up WearWell..." +python -m venv venv +source venv/bin/activate +pip install -r requirements.txt +cp .env.example .env +echo "Please edit .env with your configuration" diff --git a/wsgi.py b/wsgi.py new file mode 100644 index 0000000..6026b0f --- /dev/null +++ b/wsgi.py @@ -0,0 +1,4 @@ +from app import app + +if __name__ == "__main__": + app.run()