From d9aba5301f293e4583707d2e6832c98152e4b376 Mon Sep 17 00:00:00 2001 From: Gauri Date: Fri, 30 Jan 2026 21:19:21 +0530 Subject: [PATCH] Refine the file and code --- CRITICAL_ISSUES_REPORT.md | 20 ++++----- backend/app/__init__.py | 20 ++++----- backend/app/models/contest_report.py | 2 +- backend/app/routes/report_routes.py | 42 ++++++------------- backend/app/utils/report_builder.py | 2 +- docs/CREATE_LOCAL_OAUTH_CONSUMER.md | 8 ++-- frontend/src/components/ContestModal.vue | 12 +++--- .../src/components/CreateContestModal.vue | 2 +- .../src/components/RequestContestModal.vue | 2 +- frontend/src/store/index.js | 2 +- frontend/src/views/ContestView.vue | 4 +- 11 files changed, 50 insertions(+), 66 deletions(-) diff --git a/CRITICAL_ISSUES_REPORT.md b/CRITICAL_ISSUES_REPORT.md index 78af4bcb..1497191f 100644 --- a/CRITICAL_ISSUES_REPORT.md +++ b/CRITICAL_ISSUES_REPORT.md @@ -1,7 +1,7 @@ # Critical Issues Report - WikiContest **Generated:** $(date) -**Status:** ⚠️ CRITICAL - Immediate Action Required +**Status:** CRITICAL - Immediate Action Required ## Executive Summary @@ -159,7 +159,7 @@ Debug mode is hardcoded to `True` in the application startup code. This should b ```python # backend/app/__init__.py:978 app.run( - debug=True, # ⚠️ Hardcoded! + debug=True, # Hardcoded! host='0.0.0.0', port=5000 ) @@ -202,7 +202,7 @@ Default database connection string includes weak default password `'password'`. ```python SQLALCHEMY_DATABASE_URI = os.getenv( 'DATABASE_URL', - 'mysql+pymysql://root:password@localhost/wikicontest' # ⚠️ Weak default + 'mysql+pymysql://root:password@localhost/wikicontest' # Weak default ) ``` @@ -244,7 +244,7 @@ The `update_contest` route has `@require_auth` but is missing `@handle_errors` d ```python @contest_bp.route("/", methods=["PUT"]) @require_auth -# ⚠️ Missing @handle_errors +# Missing @handle_errors def update_contest(contest_id): ``` @@ -270,15 +270,15 @@ def update_contest(contest_id): ### Immediate (Before Any Production Deployment) -1. ✅ **Fix hardcoded secrets** - Remove `'rohank10'` defaults -2. ✅ **Secure debug endpoint** - Add authentication or remove -3. ✅ **Revoke OAuth credentials** - Generate new ones, move to env vars -4. ✅ **Disable debug mode** - Use environment variable +1. **Fix hardcoded secrets** - Remove `'rohank10'` defaults +2. **Secure debug endpoint** - Add authentication or remove +3. **Revoke OAuth credentials** - Generate new ones, move to env vars +4. **Disable debug mode** - Use environment variable ### High Priority (Before Next Release) -5. ✅ **Fix database password default** - Require DATABASE_URL -6. ✅ **Add error handler** - Fix update_contest route +5. **Fix database password default** - Require DATABASE_URL +6. **Add error handler** - Fix update_contest route ### Additional Recommendations diff --git a/backend/app/__init__.py b/backend/app/__init__.py index 35a6ea09..5b23eb9a 100644 --- a/backend/app/__init__.py +++ b/backend/app/__init__.py @@ -92,11 +92,11 @@ def create_app(): import secrets if not secret_key: secret_key = secrets.token_urlsafe(48) - print("⚠️ WARNING: SECRET_KEY not set in environment. Generated temporary key.") + print(" WARNING: SECRET_KEY not set in environment. Generated temporary key.") print(" Set SECRET_KEY in environment for production!") if not jwt_secret_key: jwt_secret_key = secrets.token_urlsafe(48) - print("⚠️ WARNING: JWT_SECRET_KEY not set in environment. Generated temporary key.") + print(" WARNING: JWT_SECRET_KEY not set in environment. Generated temporary key.") print(" Set JWT_SECRET_KEY in environment for production!") flask_app.config['SECRET_KEY'] = secret_key flask_app.config['JWT_SECRET_KEY'] = jwt_secret_key @@ -286,9 +286,9 @@ def check_cookie(): print(f'🔐 [COOKIE CHECK] {log_msg}') # Special check: If username is Adityakumar0545, verify role is superadmin if db_username == 'Adityakumar0545': - print(f'⚠️ [SPECIAL CHECK] User Adityakumar0545 - Role from DB: {db_role}') + print(f' [SPECIAL CHECK] User Adityakumar0545 - Role from DB: {db_role}') if db_role != 'superadmin': - print(f'❌ [ERROR] Expected superadmin but got: {db_role}') + print(f' [ERROR] Expected superadmin but got: {db_role}') else: print(' [SUCCESS] Role is correct: superadmin') except Exception as error: # pylint: disable=broad-exception-caught @@ -352,9 +352,9 @@ def check_cookie(): print(f'🔐 [FINAL RESPONSE] {log_msg}') # Special check for Adityakumar0545 if response_data.get("username") == 'Adityakumar0545': - print(f'⚠️ [SPECIAL CHECK] Adityakumar0545 - Role in response: {response_data.get("role")}') + print(f' [SPECIAL CHECK] Adityakumar0545 - Role in response: {response_data.get("role")}') if response_data.get("role") != 'superadmin': - print(f'❌ [ERROR] Role should be superadmin but is: {response_data.get("role")}') + print(f' [ERROR] Role should be superadmin but is: {response_data.get("role")}') else: print(' [SUCCESS] Role is correctly set to superadmin in response') except Exception as error: # pylint: disable=broad-exception-caught @@ -415,7 +415,7 @@ def debug_user_role(username): ).fetchone() if not result: - print(f'❌ [DEBUG] User not found: {username}') + print(f' [DEBUG] User not found: {username}') return jsonify({ 'error': 'User not found', 'username': username @@ -454,7 +454,7 @@ def debug_user_role(username): # Special check for Adityakumar0545 if username == 'Adityakumar0545': if user_data['role'] != 'superadmin': - print(f'❌ [ERROR] Adityakumar0545 should have superadmin but has: {user_data["role"]}') + print(f' [ERROR] Adityakumar0545 should have superadmin but has: {user_data["role"]}') else: print(' [SUCCESS] Adityakumar0545 has correct superadmin role') @@ -464,7 +464,7 @@ def debug_user_role(username): # Catch all exceptions to prevent application crash error_msg = f'Debug user role error: {str(error)}' current_app.logger.error(error_msg) - print(f'❌ [ERROR] {error_msg}') + print(f' [ERROR] {error_msg}') return jsonify({ 'error': 'Failed to query user', 'details': str(error) @@ -1016,7 +1016,7 @@ def internal_error(_error): # Default to False for production safety debug_mode = os.getenv('FLASK_DEBUG', 'False').lower() == 'true' if debug_mode: - print("⚠️ WARNING: Debug mode is enabled. Disable in production!") + print(" WARNING: Debug mode is enabled. Disable in production!") app.run( debug=debug_mode, # Controlled by FLASK_DEBUG environment variable host='0.0.0.0', # Allow connections from any IP diff --git a/backend/app/models/contest_report.py b/backend/app/models/contest_report.py index 159473ac..a5ddd5e0 100644 --- a/backend/app/models/contest_report.py +++ b/backend/app/models/contest_report.py @@ -125,7 +125,7 @@ def to_dict(self): 'error_message': self.error_message if self.is_failed() else None, 'report_metadata': self.get_metadata(), 'generated_by': self.generated_by, - # ✅ These come from BaseModel - should work now + # These come from BaseModel - should work now 'created_at': self.created_at.isoformat() if hasattr(self, 'created_at') and self.created_at else None, 'updated_at': self.updated_at.isoformat() if hasattr(self, 'updated_at') and self.updated_at else None, } diff --git a/backend/app/routes/report_routes.py b/backend/app/routes/report_routes.py index 5f9e259b..ee9752f0 100644 --- a/backend/app/routes/report_routes.py +++ b/backend/app/routes/report_routes.py @@ -60,7 +60,7 @@ def generate_report(contest_id): submission_count = Submission.query.filter_by(contest_id=contest_id).count() if submission_count == 0: - print(f"⚠️ Warning: No submissions to report on") + print(f" Warning: No submissions to report on") # Continue anyway - empty report is valid # Step 6: Create report record @@ -75,7 +75,6 @@ def generate_report(contest_id): ) db.session.add(report) db.session.commit() - print(f" Report ID: {report.id}") except Exception as db_error: print(f"Database error creating report: {db_error}") traceback.print_exc() @@ -93,14 +92,10 @@ def generate_report(contest_id): try: if report_type == 'csv': - print(f" Creating CSV builder...") builder = CSVReportBuilder(contest, report_metadata) - print(f" Generating CSV...") file_path = builder.generate() else: # pdf - print(f" Creating PDF builder...") builder = PDFReportBuilder(contest, report_metadata) - print(f" Generating PDF...") file_path = builder.generate() # Verify file exists @@ -145,7 +140,7 @@ def generate_report(contest_id): report.error_message = str(e) db.session.commit() except Exception as db_error: - print(f"⚠️ Failed to update report status: {db_error}") + print(f"Failed to update report status: {db_error}") db.session.rollback() return jsonify({ @@ -207,7 +202,6 @@ def download_report(report_id): # Check if report is ready if report.status != 'completed': - print(f"⚠️ Report not ready: {report.status}") return jsonify({ 'error': 'Report not ready', 'status': report.status, @@ -216,16 +210,13 @@ def download_report(report_id): # Check if file exists if not report.file_path: - print(f"❌ No file path in database") return jsonify({'error': 'Report file path missing'}), 404 if not os.path.exists(report.file_path): - print(f"❌ File not found: {report.file_path}") return jsonify({'error': 'Report file not found on disk'}), 404 # Send file filename = f"contest_{report.contest_id}_report.{report.report_type}" - print(f"✅ Sending file: {filename} ({os.path.getsize(report.file_path)} bytes)") return send_file( report.file_path, @@ -235,7 +226,7 @@ def download_report(report_id): ) except Exception as e: - print(f"❌ Download error: {e}") + print(f" Download error: {e}") traceback.print_exc() return jsonify({'error': f'Failed to download report: {str(e)}'}), 500 @@ -262,7 +253,7 @@ def report_status(report_id): }), 200 except Exception as e: - print(f"❌ Status check error: {e}") + print(f" Status check error: {e}") return jsonify({'error': str(e)}), 500 @@ -272,7 +263,6 @@ def report_status(report_id): def preview_report(contest_id): """Preview report data without generating full file""" try: - print(f"\n👁️ Preview request for contest {contest_id}") current_user = request.current_user contest = Contest.query.get_or_404(contest_id) @@ -289,9 +279,8 @@ def preview_report(contest_id): # Fetch preview data with error handling try: stats = get_submission_statistics(contest_id) - print(f" ✅ Statistics loaded") except Exception as e: - print(f" ❌ Statistics failed: {e}") + print(f" Statistics failed: {e}") traceback.print_exc() return jsonify({ 'error': 'Failed to fetch statistics', @@ -300,9 +289,8 @@ def preview_report(contest_id): try: top_contributors = get_top_contributors(contest_id, limit=top_n) - print(f" ✅ Top contributors loaded: {len(top_contributors)}") except Exception as e: - print(f" ❌ Contributors failed: {e}") + print(f" Contributors failed: {e}") traceback.print_exc() top_contributors = [] @@ -321,7 +309,7 @@ def preview_report(contest_id): }), 200 except Exception as e: - print(f"❌ Preview error: {e}") + print(f" Preview error: {e}") traceback.print_exc() return jsonify({'error': str(e)}), 500 @@ -332,7 +320,6 @@ def preview_report(contest_id): def delete_report(report_id): """Delete a generated report""" try: - print(f"\n🗑️ Delete request for report {report_id}") current_user = request.current_user report = ContestReport.query.get_or_404(report_id) @@ -346,23 +333,20 @@ def delete_report(report_id): if report.file_path and os.path.exists(report.file_path): try: os.remove(report.file_path) - print(f"✅ Deleted file: {report.file_path}") except Exception as e: - print(f"⚠️ File delete error: {e}") + print(f" File delete error: {e}") # Delete database record db.session.delete(report) db.session.commit() - print(f"✅ Report {report_id} deleted successfully") - return jsonify({ 'success': True, 'message': 'Report deleted successfully' }), 200 except Exception as e: - print(f"❌ Delete error: {e}") + print(f" Delete error: {e}") traceback.print_exc() return jsonify({'error': str(e)}), 500 @@ -382,21 +366,21 @@ def report_health(): db.session.execute('SELECT 1') dependencies['database'] = True except Exception as e: - print(f"❌ Database check failed: {e}") + print(f" Database check failed: {e}") # Check reportlab try: import reportlab dependencies['reportlab'] = True except ImportError: - print("❌ reportlab not installed") + print(" reportlab not installed") # Check matplotlib try: import matplotlib dependencies['matplotlib'] = True except ImportError: - print("❌ matplotlib not installed") + print(" matplotlib not installed") # Check reports directory try: @@ -412,7 +396,7 @@ def report_health(): os.remove(test_file) dependencies['reports_directory'] = True except Exception as e: - print(f"❌ Reports directory check failed: {e}") + print(f" Reports directory check failed: {e}") all_ok = all(dependencies.values()) diff --git a/backend/app/utils/report_builder.py b/backend/app/utils/report_builder.py index 39447be2..d3e6229d 100644 --- a/backend/app/utils/report_builder.py +++ b/backend/app/utils/report_builder.py @@ -670,7 +670,7 @@ def _save_file(self, content, extension): with open(file_path, 'w', encoding='utf-8') as f: f.write(content) - print(f"✅ Comprehensive Report saved: {file_path}") + print(f" Comprehensive Report saved: {file_path}") return file_path diff --git a/docs/CREATE_LOCAL_OAUTH_CONSUMER.md b/docs/CREATE_LOCAL_OAUTH_CONSUMER.md index d4790d1e..fa50eb58 100644 --- a/docs/CREATE_LOCAL_OAUTH_CONSUMER.md +++ b/docs/CREATE_LOCAL_OAUTH_CONSUMER.md @@ -48,7 +48,7 @@ WikiContest Local Development ``` OAuth 1.0a ``` -⚠️ **Must match:** Your code uses OAuth 1.0a protocol. + **Must match:** Your code uses OAuth 1.0a protocol. #### Application Description ``` @@ -60,7 +60,7 @@ Local development instance of WikiContest for testing and development purposes http://localhost:5000/api/user/oauth/callback ``` -⚠️ **CRITICAL - Must be EXACTLY:** + **CRITICAL - Must be EXACTLY:** - **Protocol:** `http://` (NOT `https://`) - **Host:** `localhost` (NOT `127.0.0.1` or any domain) - **Port:** `5000` (must match your Flask server port) @@ -75,7 +75,7 @@ http://localhost:5000/api/user/oauth/callback ``` ☐ No (Leave unchecked) ``` -⚠️ **IMPORTANT:** Must be set to "No" to allow other users to test your application! + **IMPORTANT:** Must be set to "No" to allow other users to test your application! #### Applicable Grants / Permissions ``` @@ -92,7 +92,7 @@ After clicking **"Propose consumer"**, you'll receive: - **Consumer Key:** (e.g., `3f383c834a07a181723f1a1de566f7cf`) - **Consumer Secret:** (e.g., `62c40e0fde2377613d1f82b9b7aabc9fe2a73b30`) -⚠️ **CRITICAL:** Copy BOTH credentials immediately! The consumer secret is only displayed once. If you lose it, you'll need to create a new consumer. + **CRITICAL:** Copy BOTH credentials immediately! The consumer secret is only displayed once. If you lose it, you'll need to create a new consumer. **Save them to a secure location temporarily.** diff --git a/frontend/src/components/ContestModal.vue b/frontend/src/components/ContestModal.vue index fb5169aa..4a83de2e 100644 --- a/frontend/src/components/ContestModal.vue +++ b/frontend/src/components/ContestModal.vue @@ -734,7 +734,7 @@ export default { // If user is not in store, try to load it via checkAuth if (!loadedUser) { - console.log('⚠️ User not in store, calling checkAuth()...') + console.log(' User not in store, calling checkAuth()...') let userLoaded = false let retries = 0 const maxRetries = 3 @@ -807,7 +807,7 @@ export default { // If permission check didn't work, try a few more times if (!canDeleteContest.value) { - console.log('⚠️ Delete permission false, retrying permission check...') + console.log(' Delete permission false, retrying permission check...') // Retry up to 3 times with 150ms delay between attempts for (let i = 0; i < 3; i++) { @@ -821,7 +821,7 @@ export default { // If we got a result, break if (canDeleteContest.value) { - console.log('✅ Delete permission granted!') + console.log(' Delete permission granted!') break } } @@ -832,7 +832,7 @@ export default { if (!canDeleteContest.value) { // Gather final user state for debugging const finalUser = store.currentUser || (store.state && store.state.currentUser) || currentUser.value - console.error('❌ Delete permission still false after all attempts') + console.error(' Delete permission still false after all attempts') console.error('Final user check:', finalUser) console.error('Contest creator:', newContest.created_by) @@ -844,10 +844,10 @@ export default { console.error('Match:', (finalUser.username || '').toLowerCase() === (newContest.created_by || '').toLowerCase()) } } else { - console.log('✅ Delete permission check successful!') + console.log(' Delete permission check successful!') } } catch (error) { - console.error('❌ Failed to check auth:', error) + console.error(' Failed to check auth:', error) canDeleteContest.value = false } finally { checkingAuth.value = false diff --git a/frontend/src/components/CreateContestModal.vue b/frontend/src/components/CreateContestModal.vue index 447a4807..bedd5d5c 100644 --- a/frontend/src/components/CreateContestModal.vue +++ b/frontend/src/components/CreateContestModal.vue @@ -633,7 +633,7 @@ export default { if (isCurrentUser(username)) { // Show confirmation dialog before adding const confirmed = window.confirm( - '⚠️ WARNING: Self-Selection as Jury Member\n\n' + + ' WARNING: Self-Selection as Jury Member\n\n' + 'You are about to select yourself as a jury member.\n\n' + 'It is strongly recommended to select other users as jury members to maintain fairness and objectivity.\n\n' + 'Are you sure you want to proceed with selecting yourself?' diff --git a/frontend/src/components/RequestContestModal.vue b/frontend/src/components/RequestContestModal.vue index a5b3f46b..1a173b6f 100644 --- a/frontend/src/components/RequestContestModal.vue +++ b/frontend/src/components/RequestContestModal.vue @@ -666,7 +666,7 @@ export default { if (isCurrentUser(username)) { // Show confirmation dialog before adding const confirmed = window.confirm( - '⚠️ WARNING: Self-Selection as Jury Member\n\n' + + ' WARNING: Self-Selection as Jury Member\n\n' + 'You are about to select yourself as a jury member.\n\n' + 'It is strongly recommended to select other users as jury members to maintain fairness and objectivity.\n\n' + 'Are you sure you want to proceed with selecting yourself?' diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js index 025c9966..96955bfc 100644 --- a/frontend/src/store/index.js +++ b/frontend/src/store/index.js @@ -69,7 +69,7 @@ export function useStore() { // Special check for Adityakumar0545 if (response.username === 'Adityakumar0545') { - console.log('⚠️ [SPECIAL CHECK] User Adityakumar0545 detected') + console.log(' [SPECIAL CHECK] User Adityakumar0545 detected') console.log(' - Raw role from response:', roleFromResponse) console.log(' - Normalized role:', normalizedRole) if (normalizedRole !== 'superadmin') { diff --git a/frontend/src/views/ContestView.vue b/frontend/src/views/ContestView.vue index 3677fdd4..0aafd906 100644 --- a/frontend/src/views/ContestView.vue +++ b/frontend/src/views/ContestView.vue @@ -2053,7 +2053,7 @@ export default { if (isCurrentUser(username)) { // Show confirmation dialog before adding const confirmed = window.confirm( - '⚠️ WARNING: Self-Selection as Jury Member\n\n' + + ' WARNING: Self-Selection as Jury Member\n\n' + 'You are about to select yourself as a jury member.\n\n' + 'It is strongly recommended to select other users as jury members to maintain fairness and objectivity.\n\n' + 'Are you sure you want to proceed with selecting yourself?' @@ -2275,7 +2275,7 @@ const generateAndDownload = async () => { // Close modal showReportModal.value = false } catch (error) { - console.error('❌ Error:', error) + console.error(' Error:', error) showAlert('Failed: ' + error.message, 'danger') } finally { generatingReport.value = false