forked from programmable-web-project-unioulu/PWP
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapp.py
184 lines (144 loc) · 5.83 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# app.py
from datetime import timedelta
from flask import Flask, jsonify, request
from flask_jwt_extended import (
JWTManager,
create_access_token,
get_jwt_identity,
jwt_required,
)
from werkzeug.security import check_password_hash
from extentions.extensions import cache # Import from extensions
from models import User, init_db
from routes.project_routes import project_bp
from routes.task_routes import task_bp
from routes.team_routes import team_bp
from routes.user_routes import user_bp
def create_app():
"""
Create and configure the Flask application.
This function sets up the application, including JWT authentication, caching,
database initialization, and routing for various modules such as tasks, teams,
projects, and users.
Returns:
Flask app instance
"""
app = Flask(__name__)
# Application configuration
app.config["JWT_SECRET_KEY"] = (
"super-secret" # Secret key for JWT token encoding (change for production)
)
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(
hours=1
) # Token expiration time set to 1 hour
app.config["CACHE_DEFAULT_TIMEOUT"] = 300 # Cache expiry time set to 5 minutes (300 seconds)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres@localhost:5432/taskmanagement'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Initialize JWT and Cache
JWTManager(app) # Initialize JWT without storing the instance
cache.init_app(app) # Initialize caching with the Flask app
# Initialize the database
init_db(app)
# Register Blueprints for modular routes
app.register_blueprint(task_bp)
app.register_blueprint(team_bp)
app.register_blueprint(project_bp)
app.register_blueprint(user_bp)
# ---------------- AUTHENTICATION ROUTES ----------------
@app.route("/login", methods=["POST"])
def login():
"""
User login route. This route accepts email and password, and returns a JWT
token if credentials are valid.
Request body:
{
"email": "user_email",
"password": "user_password"
}
Returns:
JSON response containing the access token or an error message.
"""
try:
data = request.get_json()
# Check if email and password are provided in the request
if not data:
return jsonify({"error": "Missing request body"}), 400
if "email" not in data:
return jsonify({"error": "Email is required"}), 400
if "password" not in data:
return jsonify({"error": "Password is required"}), 400
# Find user by email
user = User.query.filter_by(email=data["email"]).first()
# Validate user and password
if not user:
return jsonify({"error": "User not found"}), 401
if not check_password_hash(user.password_hash, data["password"]):
return jsonify({"error": "Invalid password"}), 401
# Generate JWT token upon successful login
access_token = create_access_token(identity=str(user.user_id))
return jsonify({"access_token": access_token}), 200
except Exception as e:
return jsonify({"error": "Internal server error", "message": str(e)}), 500
# ---------------- ERROR HANDLERS ----------------
@app.errorhandler(400)
def bad_request(error):
"""
Handle 400 Bad Request error. Returns a JSON response with the error details.
Returns:
JSON response with error message and status code 400.
"""
return jsonify({"error": "Bad Request", "message": str(error)}), 400
@app.errorhandler(404)
def not_found(error):
"""
Handle 404 Not Found error. Returns a JSON response with the error details.
Returns:
JSON response with error message and status code 404.
"""
return jsonify({"error": "Not Found", "message": str(error)}), 404
@app.errorhandler(500)
def internal_error(error):
"""
Handle 500 Internal Server Error. Returns a JSON response with the error details.
Returns:
JSON response with error message and status code 500.
"""
return jsonify({"error": "Internal Server Error", "message": str(error)}), 500
# ---------------- TEST ROUTE ----------------
@app.route("/test", methods=["GET"])
@jwt_required() # Ensure the user is authenticated
@cache.cached(
timeout=600, key_prefix=lambda: f"test_operations_{get_jwt_identity()}"
) # Cache per user
def test_operations():
"""
Test endpoint to check JWT authentication and caching functionality.
Returns:
JSON response with a message for the authenticated user.
"""
try:
current_user_id = get_jwt_identity()
# Handle invalid UUID format
try:
user = User.query.get(current_user_id)
except Exception as e:
return jsonify({"error": "Invalid user ID format", "message": str(e)}), 400
if not user:
return jsonify({"error": "User not found"}), 404
return jsonify(
{
"message": f"Hello {user.username}, you are authenticated!",
"user_id": current_user_id,
}
)
except Exception as e:
return jsonify({"error": "Internal server error", "message": str(e)}), 500
return app
if __name__ == "__main__":
"""
Main entry point for running the Flask application.
When this script is executed directly, it runs the Flask development server
in debug mode for testing and development.
"""
app = create_app()
app.run(debug=True)