Files
workout_buddy/backend/app.py

146 lines
5.8 KiB
Python
Executable File

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)