import os from flask import Flask, request, jsonify from flask_sqlalchemy import SQLAlchemy from flask_restful import Api, Resource from flask_jwt_extended import JWTManager, jwt_required, create_access_token, get_jwt_identity from werkzeug.security import generate_password_hash, check_password_hash from marshmallow import Schema, fields, validate from flask_limiter import Limiter from flask_limiter.util import get_remote_address import logging from logging.handlers import RotatingFileHandler from flask_cors import CORS app = Flask(__name__) CORS(app) logging.basicConfig(level=logging.DEBUG) # PostgreSQL database configuration app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['JWT_SECRET_KEY'] = os.environ.get('JWT_SECRET_KEY', 'super-secret') # Change this in production! app.config['JWT_ACCESS_TOKEN_EXPIRES'] = 3600 # 1 hour app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL', 'postgresql://workout_user:workout_password@db/workout_buddy') db = SQLAlchemy(app) api = Api(app) jwt = JWTManager(app) limiter = Limiter(app, key_func=get_remote_address) # Set up logging if not app.debug: if not os.path.exists('logs'): os.mkdir('logs') file_handler = RotatingFileHandler('logs/workout_buddy.log', maxBytes=10240, backupCount=10) file_handler.setFormatter(logging.Formatter( '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]')) file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) app.logger.setLevel(logging.INFO) app.logger.info('Workout Buddy startup') class User(db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) age = db.Column(db.Integer, nullable=False) location = db.Column(db.String(100), nullable=False) gender = db.Column(db.String(10), nullable=False) password_hash = db.Column(db.String(128)) created_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) updated_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now(), onupdate=db.func.now()) def set_password(self, password): self.password_hash = generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password) class Message(db.Model): __tablename__ = 'messages' id = db.Column(db.Integer, primary_key=True) sender_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) receiver_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) content = db.Column(db.String(500), nullable=False) created_at = db.Column(db.DateTime(timezone=True), server_default=db.func.now()) sender = db.relationship('User', foreign_keys=[sender_id], backref=db.backref('sent_messages', lazy=True)) receiver = db.relationship('User', foreign_keys=[receiver_id], backref=db.backref('received_messages', lazy=True)) class UserSchema(Schema): name = fields.Str(required=True, validate=validate.Length(min=1, max=100)) email = fields.Email(required=True) age = fields.Int(required=True, validate=validate.Range(min=18, max=120)) location = fields.Str(required=True, validate=validate.Length(min=1, max=100)) password = fields.Str(required=True, validate=validate.Length(min=8)) class MessageSchema(Schema): content = fields.Str(required=True, validate=validate.Length(min=1, max=500)) user_schema = UserSchema() message_schema = MessageSchema() # Define the resource classes class UserResource(Resource): def post(self): try: data = request.get_json() errors = user_schema.validate(data) if errors: return {'message': 'Validation error', 'errors': errors}, 400 existing_user = User.query.filter_by(email=data['email']).first() if existing_user: return {'message': 'User with this email already exists'}, 409 user = User( name=data['name'], email=data['email'], age=data['age'], location=data['location'], gender=data['gender'] ) user.set_password(data['password']) db.session.add(user) db.session.commit() return user_schema.dump(user), 201 except Exception as e: app.logger.error(f'Error creating user: {str(e)}') app.logger.info(f'Attempting to create user: {data["email"]}') return {'message': 'An error occurred while creating the user'}, 500 class MessageResource(Resource): @jwt_required() def get(self): messages = Message.query.all() return message_schema.dump(messages, many=True), 200 @jwt_required() def post(self): data = request.get_json() message = Message( sender_id=get_jwt_identity(), # Assuming JWT identity is user ID receiver_id=data['receiver_id'], content=data['content'] ) db.session.add(message) db.session.commit() return message_schema.dump(message), 201 class AuthResource(Resource): def post(self): data = request.get_json() user = User.query.filter_by(email=data['email']).first() if user and user.check_password(data['password']): access_token = create_access_token(identity=user.id) return {'access_token': access_token}, 200 return {'message': 'Invalid credentials'}, 401 # Add resource endpoints api.add_resource(UserResource, '/users') api.add_resource(MessageResource, '/messages') api.add_resource(AuthResource, '/auth') if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)