-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathadmin_blueprint.py
More file actions
165 lines (141 loc) · 5.89 KB
/
admin_blueprint.py
File metadata and controls
165 lines (141 loc) · 5.89 KB
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
from flask import Blueprint, render_template, request, redirect, url_for, flash, current_app, session
from flask_login import login_required, current_user
import psycopg2
import bcrypt
admin = Blueprint("admin", __name__)
def fetch_data(query, params=None):
"""Fetch data using Flask connection pool."""
conn = current_app.config["DB_POOL"].getconn()
try:
with conn.cursor() as cur:
cur.execute(query, params or ())
column_names = [desc[0] for desc in cur.description]
return [dict(zip(column_names, row)) for row in cur.fetchall()]
finally:
current_app.config["DB_POOL"].putconn(conn)
def execute_query(query, params=None):
"""Execute write operations with proper transaction handling."""
conn = current_app.config["DB_POOL"].getconn()
try:
with conn.cursor() as cur:
cur.execute(query, params or ())
conn.commit()
except Exception as e:
conn.rollback()
raise e
finally:
current_app.config["DB_POOL"].putconn(conn)
@admin.route('/dashboard')
@login_required
def admin_dashboard():
if not current_user.is_admin:
flash("Admin privileges required", "error")
return redirect(url_for('portfolio.view_portfolio'))
try:
# Get all users with brokerage info
users = fetch_data("""
SELECT u.user_id, u.name, b.name as brokerage_name, u.balance
FROM Users u
JOIN Brokers b ON u.brokerage_id = b.brokerage_id
ORDER BY u.name
""")
# Get brokerage user counts
brokerages = fetch_data("""
SELECT b.brokerage_id, b.name, COUNT(u.user_id) as user_count
FROM Brokers b
LEFT JOIN Users u ON b.brokerage_id = u.brokerage_id
GROUP BY b.brokerage_id, b.name
ORDER BY user_count DESC
""")
# Get all stocks
stocks = fetch_data("SELECT ticker, name, price FROM Stock ORDER BY ticker")
return render_template('admin_dashboard.html',
users_data=users,
brokerages_data=brokerages,
stocks_data=stocks)
except Exception as e:
flash(f"Error loading dashboard: {str(e)}", "error")
return redirect(url_for('portfolio.view_portfolio'))
@admin.route("/delete_user/<int:user_id>")
@login_required
def delete_user(user_id):
if not current_user.is_admin:
flash("Admin privileges required", "error")
return redirect(url_for("portfolio.view_portfolio"))
try:
execute_query("DELETE FROM Users WHERE user_id = %s", (user_id,))
flash("User deleted successfully", "success")
except Exception as e:
flash(f"Error deleting user: {str(e)}", "error")
return redirect(url_for("admin.admin_dashboard"))
@admin.route("/reset_password/<int:user_id>", methods=["POST"])
@login_required
def reset_password(user_id):
if not current_user.is_admin:
flash("Admin privileges required", "error")
return redirect(url_for("portfolio.view_portfolio"))
new_password = request.form.get("new_password")
if not new_password or len(new_password) < 8:
flash("Password must be at least 8 characters", "error")
return redirect(url_for("admin.admin_dashboard"))
try:
hashed_password = bcrypt.hashpw(new_password.encode(), bcrypt.gensalt()).decode()
execute_query(
"UPDATE Users SET password_hash = %s WHERE user_id = %s",
(hashed_password, user_id)
)
flash("Password reset successfully", "success")
except Exception as e:
flash(f"Error resetting password: {str(e)}", "error")
return redirect(url_for("admin.admin_dashboard"))
@admin.route("/add_stock", methods=["POST"])
@login_required
def add_stock():
if not current_user.is_admin:
flash("Admin privileges required", "error")
return redirect(url_for("portfolio.view_portfolio"))
ticker = request.form.get("ticker", "").upper()
name = request.form.get("stock_name", "")
price = request.form.get("stock_price", 0)
if not ticker or not name:
flash("Ticker and name are required", "error")
return redirect(url_for("admin.admin_dashboard"))
try:
execute_query(
"""INSERT INTO Stock (ticker, name, price)
VALUES (%s, %s, %s)
ON CONFLICT (ticker) DO UPDATE
SET name = EXCLUDED.name,
price = EXCLUDED.price""",
(ticker, name, float(price))
)
flash(f"Stock {ticker} added/updated successfully", "success")
except psycopg2.IntegrityError:
flash(f"Stock {ticker} already exists", "error")
except Exception as e:
flash(f"Error adding stock: {str(e)}", "error")
return redirect(url_for("admin.admin_dashboard"))
@admin.route("/delete_stock/<ticker>", methods=["POST"])
@login_required
def delete_stock(ticker):
if not current_user.is_admin:
flash("Admin privileges required", "error")
return redirect(url_for("portfolio.view_portfolio"))
try:
# First delete from Portfolio (watchlists) to avoid FK constraint errors
execute_query("DELETE FROM Portfolio WHERE stock_ticker = %s", (ticker,))
# Then delete the stock
execute_query("DELETE FROM Stock WHERE ticker = %s", (ticker,))
flash(f"Stock {ticker} deleted successfully", "success")
except Exception as e:
flash(f"Error deleting stock: {str(e)}", "error")
return redirect(url_for("admin.admin_dashboard"))
@admin.route('/check_session')
def check_session():
"""Debug endpoint to check session status"""
return f"""
Logged in: {current_user.is_authenticated}<br>
User ID: {getattr(current_user, 'user_id', None)}<br>
Admin: {getattr(current_user, 'is_admin', None)}<br>
Session: {dict(session)}
"""