|
41 | 41 | update_questionnaire_upload_metadata, |
42 | 42 | get_user_by_firebase_uid, |
43 | 43 | create_or_update_user, |
| 44 | + list_all_users, |
| 45 | + delete_user, |
| 46 | + set_user_credits, |
| 47 | + get_user_count, |
| 48 | + get_payment_history, |
44 | 49 | ) |
45 | 50 |
|
46 | 51 | # Auth and Payment modules |
47 | | -from auth import require_auth, require_payment, consume_credit, verify_firebase_token, optional_auth |
| 52 | +from auth import require_auth, require_payment, consume_credit, verify_firebase_token, optional_auth, require_admin |
48 | 53 | from payment import ( |
49 | 54 | create_razorpay_order, |
50 | 55 | verify_razorpay_signature, |
@@ -6157,8 +6162,111 @@ def payment_reconcile(): |
6157 | 6162 | "message": "Could not check payment status with Razorpay" |
6158 | 6163 | }), 500 |
6159 | 6164 |
|
| 6165 | +# ============================================================================= |
| 6166 | +# ADMIN ROUTES |
| 6167 | +# ============================================================================= |
| 6168 | + |
| 6169 | +@app.route("/api/admin/stats", methods=["GET"]) |
| 6170 | +@require_auth |
| 6171 | +@require_admin |
| 6172 | +def admin_stats(): |
| 6173 | + """Get dashboard statistics: total users, paid users, users with credits.""" |
| 6174 | + counts = get_user_count() |
| 6175 | + return jsonify({"success": True, "stats": counts}), 200 |
| 6176 | + |
| 6177 | + |
| 6178 | +@app.route("/api/admin/users", methods=["GET"]) |
| 6179 | +@require_auth |
| 6180 | +@require_admin |
| 6181 | +def admin_list_users(): |
| 6182 | + """ |
| 6183 | + List all users with pagination and optional search. |
| 6184 | + Query params: page (default 1), per_page (default 25), search (optional) |
| 6185 | + """ |
| 6186 | + page = request.args.get("page", 1, type=int) |
| 6187 | + per_page = request.args.get("per_page", 25, type=int) |
| 6188 | + search = request.args.get("search", "").strip() or None |
| 6189 | + |
| 6190 | + # Clamp per_page to prevent abuse |
| 6191 | + per_page = min(max(per_page, 1), 100) |
| 6192 | + |
| 6193 | + users, total = list_all_users(page=page, per_page=per_page, search=search) |
| 6194 | + return jsonify({ |
| 6195 | + "success": True, |
| 6196 | + "users": users, |
| 6197 | + "pagination": { |
| 6198 | + "page": page, |
| 6199 | + "per_page": per_page, |
| 6200 | + "total": total, |
| 6201 | + "pages": (total + per_page - 1) // per_page if per_page else 1, |
| 6202 | + }, |
| 6203 | + }), 200 |
| 6204 | + |
| 6205 | + |
| 6206 | +@app.route("/api/admin/users/<firebase_uid>", methods=["GET"]) |
| 6207 | +@require_auth |
| 6208 | +@require_admin |
| 6209 | +def admin_get_user(firebase_uid): |
| 6210 | + """Get single user details including payment history.""" |
| 6211 | + user = get_user_by_firebase_uid(firebase_uid) |
| 6212 | + if not user: |
| 6213 | + return jsonify({"error": "User not found"}), 404 |
| 6214 | + |
| 6215 | + payments = get_payment_history(firebase_uid) |
| 6216 | + return jsonify({ |
| 6217 | + "success": True, |
| 6218 | + "user": user, |
| 6219 | + "payments": payments, |
| 6220 | + }), 200 |
| 6221 | + |
| 6222 | + |
| 6223 | +@app.route("/api/admin/users/<firebase_uid>", methods=["DELETE"]) |
| 6224 | +@require_auth |
| 6225 | +@require_admin |
| 6226 | +def admin_delete_user(firebase_uid): |
| 6227 | + """Delete a user and their payment history.""" |
| 6228 | + deleted = delete_user(firebase_uid) |
| 6229 | + if not deleted: |
| 6230 | + return jsonify({"error": "User not found"}), 404 |
| 6231 | + return jsonify({"success": True, "message": "User deleted"}), 200 |
| 6232 | + |
| 6233 | + |
| 6234 | +@app.route("/api/admin/users/<firebase_uid>/credits", methods=["POST"]) |
| 6235 | +@require_auth |
| 6236 | +@require_admin |
| 6237 | +def admin_set_credits(firebase_uid): |
| 6238 | + """ |
| 6239 | + Set or add credits for a user. |
| 6240 | + Request body: { "credits": int, "mode": "set" | "add" } |
| 6241 | + """ |
| 6242 | + data = request.get_json(force=True) or {} |
| 6243 | + credits = data.get("credits") |
| 6244 | + mode = data.get("mode", "set") |
| 6245 | + |
| 6246 | + if credits is None or not isinstance(credits, int) or credits < 0: |
| 6247 | + return jsonify({"error": "Valid non-negative integer 'credits' required"}), 400 |
| 6248 | + |
| 6249 | + user = get_user_by_firebase_uid(firebase_uid) |
| 6250 | + if not user: |
| 6251 | + return jsonify({"error": "User not found"}), 404 |
| 6252 | + |
| 6253 | + if mode == "add": |
| 6254 | + from db import add_user_credits |
| 6255 | + success = add_user_credits(firebase_uid, credits) |
| 6256 | + else: |
| 6257 | + success = set_user_credits(firebase_uid, credits) |
| 6258 | + |
| 6259 | + if not success: |
| 6260 | + return jsonify({"error": "Failed to update credits"}), 500 |
| 6261 | + |
| 6262 | + updated_user = get_user_by_firebase_uid(firebase_uid) |
| 6263 | + return jsonify({ |
| 6264 | + "success": True, |
| 6265 | + "message": f"Credits {'added' if mode == 'add' else 'set'} successfully", |
| 6266 | + "report_credits": updated_user.get("report_credits", 0), |
| 6267 | + }), 200 |
| 6268 | + |
6160 | 6269 |
|
6161 | 6270 | if __name__ == '__main__': |
6162 | 6271 | port = int(os.environ.get('PORT', 5000)) |
6163 | 6272 | app.run(host='0.0.0.0', port=port, debug=False) |
6164 | | - |
|
0 commit comments