Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
Phinetwork committed Dec 14, 2024
1 parent 7e28614 commit 04e2b35
Show file tree
Hide file tree
Showing 7 changed files with 377 additions and 496 deletions.
Binary file modified backend/.DS_Store
Binary file not shown.
109 changes: 97 additions & 12 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@

from flask import Flask, request, jsonify, g
from flask_cors import CORS
from flask import Flask, send_from_directory
from database import SessionLocal, Base, User # Import after loading .env
from database import SessionLocal, Base, User, Profile, Badge
from sqlalchemy.exc import IntegrityError
from werkzeug.security import generate_password_hash, check_password_hash
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
Expand Down Expand Up @@ -38,7 +37,11 @@
app.logger.info(f"CORS enabled for frontend URLs: {ALLOWED_ORIGINS}")

# Initialize Redis client
REDIS_URL = os.getenv("REDIS_URL", "redis://localhost:6379/0") # Default to local Redis
REDIS_URL = os.getenv(
"REDIS_URL",
"redis://:2xctaLdMYomYsJJ2drVp9Ylj5GDnJdZQ@redis-19847.c256.us-east-1-2.ec2.redns.redis-cloud.com:19847/0"
) # Default to your Redis public URL with credentials

try:
redis_client = redis.Redis.from_url(REDIS_URL)
redis_client.ping()
Expand All @@ -49,9 +52,6 @@

# Helper Functions for Caching
def get_cached_matches(skills):
"""
Retrieve cached matches from Redis based on the provided skills.
"""
if not redis_client:
return None
try:
Expand All @@ -68,9 +68,6 @@ def get_cached_matches(skills):
return None

def set_cached_matches(skills, matches):
"""
Cache the matches in Redis for future requests.
"""
if not redis_client:
return
try:
Expand All @@ -92,11 +89,84 @@ def shutdown_session(exception=None):
db.close()

# Existing Routes

from matching_engine import get_side_hustles
from skill_engine import recommend_skills
from habit_engine import get_habit_recommendations

# Profile Management Routes
@app.route("/api/profile", methods=["GET", "PUT"])
@jwt_required()
def manage_profile():
user_id = get_jwt_identity()
try:
user = g.db.query(User).filter_by(id=user_id).first()
if not user:
return jsonify({"error": "User not found"}), 404

if request.method == "GET":
if not user.profile:
return jsonify({"error": "Profile not found"}), 404
return jsonify({
"bio": user.profile.bio,
"avatar_url": user.profile.avatar_url
}), 200

if request.method == "PUT":
data = request.get_json()
bio = data.get("bio")
avatar_url = data.get("avatar_url")

if not user.profile:
user.profile = Profile(bio=bio, avatar_url=avatar_url, user_id=user_id)
else:
user.profile.bio = bio
user.profile.avatar_url = avatar_url

g.db.commit()
return jsonify({"message": "Profile updated successfully"}), 200
except Exception as e:
app.logger.error(f"Error in /api/profile: {e}", exc_info=True)
return jsonify({"error": "An unexpected error occurred"}), 500

# Badge Management Routes
@app.route("/api/badges", methods=["GET", "POST", "DELETE"])
@jwt_required()
def manage_badges():
user_id = get_jwt_identity()
try:
user = g.db.query(User).filter_by(id=user_id).first()
if not user:
return jsonify({"error": "User not found"}), 404

if request.method == "GET":
badges = [{"id": badge.id, "name": badge.name, "description": badge.description} for badge in user.badges]
return jsonify(badges), 200

if request.method == "POST":
data = request.get_json()
name = data.get("name")
description = data.get("description")
if not name:
return jsonify({"error": "Badge name is required"}), 400

new_badge = Badge(name=name, description=description, user_id=user_id)
g.db.add(new_badge)
g.db.commit()
return jsonify({"message": "Badge added successfully"}), 201

if request.method == "DELETE":
badge_id = request.args.get("id")
badge = g.db.query(Badge).filter_by(id=badge_id, user_id=user_id).first()
if not badge:
return jsonify({"error": "Badge not found"}), 404

g.db.delete(badge)
g.db.commit()
return jsonify({"message": "Badge deleted successfully"}), 200
except Exception as e:
app.logger.error(f"Error in /api/badges: {e}", exc_info=True)
return jsonify({"error": "An unexpected error occurred"}), 500

@app.route("/api/matches", methods=["POST"])
def side_hustle_matches():
app.logger.info("Request received at /api/matches")
Expand Down Expand Up @@ -294,11 +364,13 @@ def login():
app.logger.error(f"Error in /api/login: {e}", exc_info=True)
return jsonify({"error": "An unexpected error occurred"}), 500

# Consolidated Dashboard Route
@app.route("/api/dashboard", methods=["GET"])
@jwt_required()
def dashboard():
app.logger.info("Request received at /api/dashboard")
try:
# Extract the user ID from the token
user_id = get_jwt_identity()
app.logger.info(f"Extracted user_id from token: {user_id}")

Expand All @@ -308,14 +380,27 @@ def dashboard():
app.logger.warning("User not found!")
return jsonify({"error": "User not found!"}), 404

# Example user-specific data; adjust as needed
# Handle user profile, ensuring it's safe to access even if not set
profile = {
"bio": user.profile.bio if user.profile else None,
"avatar_url": user.profile.avatar_url if user.profile else None
}

# Handle badges, ensuring the app works even if no badges are earned yet
badges = [{"id": badge.id, "name": badge.name, "description": badge.description} for badge in user.badges] if user.badges else []

# Consolidated data including user, profile, and badges
data = {
"username": user.username,
"email": user.email,
"created_at": user.created_at.isoformat()
"created_at": user.created_at.isoformat(),
"profile": profile,
"badges": badges
}
app.logger.info(f"Dashboard data for user_id {user_id}: {data}")

return jsonify(data), 200

except Exception as e:
app.logger.error(f"Error in /api/dashboard: {e}", exc_info=True)
return jsonify({"error": "An unexpected error occurred"}), 500
Expand Down
64 changes: 53 additions & 11 deletions backend/database.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import os
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, DateTime
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey, DateTime, Index
from sqlalchemy.orm import declarative_base, relationship, sessionmaker
from datetime import datetime
import logging
Expand All @@ -15,65 +15,107 @@
logger.error("DATABASE_URL environment variable is not set")
raise ValueError("DATABASE_URL environment variable is not set")

# Debugging: Log the database connection string (hide sensitive info in production)
logger.info(f"DATABASE_URL Loaded: {DATABASE_URL}")
# Debugging: Avoid logging sensitive info in production
logger.info("DATABASE_URL Loaded successfully.")

# Create SQLAlchemy engine and session
engine = create_engine(DATABASE_URL, echo=False)
Base = declarative_base()
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# Models

# User model
class User(Base):
__tablename__ = "users"

id = Column(Integer, primary_key=True, index=True)
username = Column(String, unique=True, nullable=False, index=True)
email = Column(String, unique=True, nullable=False, index=True)
username = Column(String(150), unique=True, nullable=False, index=True)
email = Column(String(255), unique=True, nullable=False, index=True)
hashed_password = Column(String, nullable=False)
created_at = Column(DateTime, default=datetime.utcnow)

# Relationships
skills = relationship("Skill", back_populates="user", cascade="all, delete-orphan")
habits = relationship("Habit", back_populates="user", cascade="all, delete-orphan")
profile = relationship("Profile", back_populates="user", uselist=False, cascade="all, delete-orphan")
badges = relationship("Badge", back_populates="user", cascade="all, delete-orphan")

def __repr__(self):
return f"<User(id={self.id}, username='{self.username}', email='{self.email}')>"

# Profile model
class Profile(Base):
__tablename__ = "profiles"

id = Column(Integer, primary_key=True, index=True)
bio = Column(String(500), nullable=True) # Max length of 500 characters for bio
avatar_url = Column(String(2083), nullable=True) # Max length for URLs
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)

user = relationship("User", back_populates="profile")

def __repr__(self):
return f"<Profile(id={self.id}, user_id={self.user_id}, bio='{self.bio}')>"

# Add an index for user_id
Index("ix_profiles_user_id", Profile.user_id)

# Badge model
class Badge(Base):
__tablename__ = "badges"

id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), nullable=False) # Max length for badge name
description = Column(String(255), nullable=True) # Max length for description
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)

user = relationship("User", back_populates="badges")

def __repr__(self):
return f"<Badge(id={self.id}, name='{self.name}', user_id={self.user_id}')>"

# Add an index for user_id
Index("ix_badges_user_id", Badge.user_id)

# Skill model
class Skill(Base):
__tablename__ = "skills"

id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
name = Column(String(100), nullable=False) # Max length for skill name
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)

user = relationship("User", back_populates="skills")

def __repr__(self):
return f"<Skill(id={self.id}, name='{self.name}', user_id={self.user_id})>"
return f"<Skill(id={self.id}, name='{self.name}', user_id={self.user_id}')>"

# Habit model
class Habit(Base):
__tablename__ = "habits"

id = Column(Integer, primary_key=True, index=True)
description = Column(String, nullable=False)
description = Column(String(255), nullable=False) # Max length for description
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)

user = relationship("User", back_populates="habits")

def __repr__(self):
return f"<Habit(id={self.id}, description='{self.description}', user_id={self.user_id})>"
return f"<Habit(id={self.id}, description='{self.description}', user_id={self.user_id}')>"

# Create all tables
# Initialize Database
def initialize_database():
"""
Create all database tables.
"""
try:
logger.info("Creating database tables...")
Base.metadata.create_all(engine)
logger.info("Database tables created successfully.")
except Exception as e:
logger.error(f"Error creating database tables: {e}")

# Initialize database
# Main execution
if __name__ == "__main__":
initialize_database()
5 changes: 5 additions & 0 deletions frontend/src/components/Dashboard.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import AI_DecisionTreeVisualizer from "./DecisionTree";
import PredictiveForecastChart from "./PredictiveForecastChart";
import InteractiveGlobe from "./InteractiveGlobe";
import EconomicSectorBubbleMap from "./EconomicSectorBubbleMap";
import Game from "./Game";
import {
Chart as ChartJS,
CategoryScale,
Expand Down Expand Up @@ -677,6 +678,10 @@ const Dashboard = () => {
<Bar data={generatePlaceholderChartData()} options={chartOptions} />
)}
</div>

<div className="chart-container">
<Game />
</div>

<div className="chart-container">
<PredictiveForecastChart />
Expand Down
Loading

0 comments on commit 04e2b35

Please sign in to comment.