146 lines
5.8 KiB
Python
Executable File
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)
|