Skip to content

Commit de95748

Browse files
authored
Refine the file and code (#162)
2 parents c6c6e9a + d9aba53 commit de95748

File tree

11 files changed

+50
-66
lines changed

11 files changed

+50
-66
lines changed

CRITICAL_ISSUES_REPORT.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Critical Issues Report - WikiContest
22

33
**Generated:** $(date)
4-
**Status:** ⚠️ CRITICAL - Immediate Action Required
4+
**Status:** CRITICAL - Immediate Action Required
55

66
## Executive Summary
77

@@ -159,7 +159,7 @@ Debug mode is hardcoded to `True` in the application startup code. This should b
159159
```python
160160
# backend/app/__init__.py:978
161161
app.run(
162-
debug=True, # ⚠️ Hardcoded!
162+
debug=True, # Hardcoded!
163163
host='0.0.0.0',
164164
port=5000
165165
)
@@ -202,7 +202,7 @@ Default database connection string includes weak default password `'password'`.
202202
```python
203203
SQLALCHEMY_DATABASE_URI = os.getenv(
204204
'DATABASE_URL',
205-
'mysql+pymysql://root:password@localhost/wikicontest' # ⚠️ Weak default
205+
'mysql+pymysql://root:password@localhost/wikicontest' # Weak default
206206
)
207207
```
208208

@@ -244,7 +244,7 @@ The `update_contest` route has `@require_auth` but is missing `@handle_errors` d
244244
```python
245245
@contest_bp.route("/<int:contest_id>", methods=["PUT"])
246246
@require_auth
247-
# ⚠️ Missing @handle_errors
247+
# Missing @handle_errors
248248
def update_contest(contest_id):
249249
```
250250

@@ -270,15 +270,15 @@ def update_contest(contest_id):
270270

271271
### Immediate (Before Any Production Deployment)
272272

273-
1. **Fix hardcoded secrets** - Remove `'rohank10'` defaults
274-
2. **Secure debug endpoint** - Add authentication or remove
275-
3. **Revoke OAuth credentials** - Generate new ones, move to env vars
276-
4. **Disable debug mode** - Use environment variable
273+
1. **Fix hardcoded secrets** - Remove `'rohank10'` defaults
274+
2. **Secure debug endpoint** - Add authentication or remove
275+
3. **Revoke OAuth credentials** - Generate new ones, move to env vars
276+
4. **Disable debug mode** - Use environment variable
277277

278278
### High Priority (Before Next Release)
279279

280-
5. **Fix database password default** - Require DATABASE_URL
281-
6. **Add error handler** - Fix update_contest route
280+
5. **Fix database password default** - Require DATABASE_URL
281+
6. **Add error handler** - Fix update_contest route
282282

283283
### Additional Recommendations
284284

backend/app/__init__.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ def create_app():
9292
import secrets
9393
if not secret_key:
9494
secret_key = secrets.token_urlsafe(48)
95-
print("⚠️ WARNING: SECRET_KEY not set in environment. Generated temporary key.")
95+
print(" WARNING: SECRET_KEY not set in environment. Generated temporary key.")
9696
print(" Set SECRET_KEY in environment for production!")
9797
if not jwt_secret_key:
9898
jwt_secret_key = secrets.token_urlsafe(48)
99-
print("⚠️ WARNING: JWT_SECRET_KEY not set in environment. Generated temporary key.")
99+
print(" WARNING: JWT_SECRET_KEY not set in environment. Generated temporary key.")
100100
print(" Set JWT_SECRET_KEY in environment for production!")
101101
flask_app.config['SECRET_KEY'] = secret_key
102102
flask_app.config['JWT_SECRET_KEY'] = jwt_secret_key
@@ -286,9 +286,9 @@ def check_cookie():
286286
print(f'🔐 [COOKIE CHECK] {log_msg}')
287287
# Special check: If username is Adityakumar0545, verify role is superadmin
288288
if db_username == 'Adityakumar0545':
289-
print(f'⚠️ [SPECIAL CHECK] User Adityakumar0545 - Role from DB: {db_role}')
289+
print(f' [SPECIAL CHECK] User Adityakumar0545 - Role from DB: {db_role}')
290290
if db_role != 'superadmin':
291-
print(f' [ERROR] Expected superadmin but got: {db_role}')
291+
print(f' [ERROR] Expected superadmin but got: {db_role}')
292292
else:
293293
print(' [SUCCESS] Role is correct: superadmin')
294294
except Exception as error: # pylint: disable=broad-exception-caught
@@ -352,9 +352,9 @@ def check_cookie():
352352
print(f'🔐 [FINAL RESPONSE] {log_msg}')
353353
# Special check for Adityakumar0545
354354
if response_data.get("username") == 'Adityakumar0545':
355-
print(f'⚠️ [SPECIAL CHECK] Adityakumar0545 - Role in response: {response_data.get("role")}')
355+
print(f' [SPECIAL CHECK] Adityakumar0545 - Role in response: {response_data.get("role")}')
356356
if response_data.get("role") != 'superadmin':
357-
print(f' [ERROR] Role should be superadmin but is: {response_data.get("role")}')
357+
print(f' [ERROR] Role should be superadmin but is: {response_data.get("role")}')
358358
else:
359359
print(' [SUCCESS] Role is correctly set to superadmin in response')
360360
except Exception as error: # pylint: disable=broad-exception-caught
@@ -415,7 +415,7 @@ def debug_user_role(username):
415415
).fetchone()
416416

417417
if not result:
418-
print(f' [DEBUG] User not found: {username}')
418+
print(f' [DEBUG] User not found: {username}')
419419
return jsonify({
420420
'error': 'User not found',
421421
'username': username
@@ -454,7 +454,7 @@ def debug_user_role(username):
454454
# Special check for Adityakumar0545
455455
if username == 'Adityakumar0545':
456456
if user_data['role'] != 'superadmin':
457-
print(f' [ERROR] Adityakumar0545 should have superadmin but has: {user_data["role"]}')
457+
print(f' [ERROR] Adityakumar0545 should have superadmin but has: {user_data["role"]}')
458458
else:
459459
print(' [SUCCESS] Adityakumar0545 has correct superadmin role')
460460

@@ -464,7 +464,7 @@ def debug_user_role(username):
464464
# Catch all exceptions to prevent application crash
465465
error_msg = f'Debug user role error: {str(error)}'
466466
current_app.logger.error(error_msg)
467-
print(f' [ERROR] {error_msg}')
467+
print(f' [ERROR] {error_msg}')
468468
return jsonify({
469469
'error': 'Failed to query user',
470470
'details': str(error)
@@ -1016,7 +1016,7 @@ def internal_error(_error):
10161016
# Default to False for production safety
10171017
debug_mode = os.getenv('FLASK_DEBUG', 'False').lower() == 'true'
10181018
if debug_mode:
1019-
print("⚠️ WARNING: Debug mode is enabled. Disable in production!")
1019+
print(" WARNING: Debug mode is enabled. Disable in production!")
10201020
app.run(
10211021
debug=debug_mode, # Controlled by FLASK_DEBUG environment variable
10221022
host='0.0.0.0', # Allow connections from any IP

backend/app/models/contest_report.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ def to_dict(self):
125125
'error_message': self.error_message if self.is_failed() else None,
126126
'report_metadata': self.get_metadata(),
127127
'generated_by': self.generated_by,
128-
# These come from BaseModel - should work now
128+
# These come from BaseModel - should work now
129129
'created_at': self.created_at.isoformat() if hasattr(self, 'created_at') and self.created_at else None,
130130
'updated_at': self.updated_at.isoformat() if hasattr(self, 'updated_at') and self.updated_at else None,
131131
}

backend/app/routes/report_routes.py

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def generate_report(contest_id):
6060
submission_count = Submission.query.filter_by(contest_id=contest_id).count()
6161

6262
if submission_count == 0:
63-
print(f"⚠️ Warning: No submissions to report on")
63+
print(f" Warning: No submissions to report on")
6464
# Continue anyway - empty report is valid
6565

6666
# Step 6: Create report record
@@ -75,7 +75,6 @@ def generate_report(contest_id):
7575
)
7676
db.session.add(report)
7777
db.session.commit()
78-
print(f" Report ID: {report.id}")
7978
except Exception as db_error:
8079
print(f"Database error creating report: {db_error}")
8180
traceback.print_exc()
@@ -93,14 +92,10 @@ def generate_report(contest_id):
9392

9493
try:
9594
if report_type == 'csv':
96-
print(f" Creating CSV builder...")
9795
builder = CSVReportBuilder(contest, report_metadata)
98-
print(f" Generating CSV...")
9996
file_path = builder.generate()
10097
else: # pdf
101-
print(f" Creating PDF builder...")
10298
builder = PDFReportBuilder(contest, report_metadata)
103-
print(f" Generating PDF...")
10499
file_path = builder.generate()
105100

106101
# Verify file exists
@@ -145,7 +140,7 @@ def generate_report(contest_id):
145140
report.error_message = str(e)
146141
db.session.commit()
147142
except Exception as db_error:
148-
print(f"⚠️ Failed to update report status: {db_error}")
143+
print(f"Failed to update report status: {db_error}")
149144
db.session.rollback()
150145

151146
return jsonify({
@@ -207,7 +202,6 @@ def download_report(report_id):
207202

208203
# Check if report is ready
209204
if report.status != 'completed':
210-
print(f"⚠️ Report not ready: {report.status}")
211205
return jsonify({
212206
'error': 'Report not ready',
213207
'status': report.status,
@@ -216,16 +210,13 @@ def download_report(report_id):
216210

217211
# Check if file exists
218212
if not report.file_path:
219-
print(f"❌ No file path in database")
220213
return jsonify({'error': 'Report file path missing'}), 404
221214

222215
if not os.path.exists(report.file_path):
223-
print(f"❌ File not found: {report.file_path}")
224216
return jsonify({'error': 'Report file not found on disk'}), 404
225217

226218
# Send file
227219
filename = f"contest_{report.contest_id}_report.{report.report_type}"
228-
print(f"✅ Sending file: {filename} ({os.path.getsize(report.file_path)} bytes)")
229220

230221
return send_file(
231222
report.file_path,
@@ -235,7 +226,7 @@ def download_report(report_id):
235226
)
236227

237228
except Exception as e:
238-
print(f" Download error: {e}")
229+
print(f" Download error: {e}")
239230
traceback.print_exc()
240231
return jsonify({'error': f'Failed to download report: {str(e)}'}), 500
241232

@@ -262,7 +253,7 @@ def report_status(report_id):
262253
}), 200
263254

264255
except Exception as e:
265-
print(f" Status check error: {e}")
256+
print(f" Status check error: {e}")
266257
return jsonify({'error': str(e)}), 500
267258

268259

@@ -272,7 +263,6 @@ def report_status(report_id):
272263
def preview_report(contest_id):
273264
"""Preview report data without generating full file"""
274265
try:
275-
print(f"\n👁️ Preview request for contest {contest_id}")
276266

277267
current_user = request.current_user
278268
contest = Contest.query.get_or_404(contest_id)
@@ -289,9 +279,8 @@ def preview_report(contest_id):
289279
# Fetch preview data with error handling
290280
try:
291281
stats = get_submission_statistics(contest_id)
292-
print(f" ✅ Statistics loaded")
293282
except Exception as e:
294-
print(f" Statistics failed: {e}")
283+
print(f" Statistics failed: {e}")
295284
traceback.print_exc()
296285
return jsonify({
297286
'error': 'Failed to fetch statistics',
@@ -300,9 +289,8 @@ def preview_report(contest_id):
300289

301290
try:
302291
top_contributors = get_top_contributors(contest_id, limit=top_n)
303-
print(f" ✅ Top contributors loaded: {len(top_contributors)}")
304292
except Exception as e:
305-
print(f" Contributors failed: {e}")
293+
print(f" Contributors failed: {e}")
306294
traceback.print_exc()
307295
top_contributors = []
308296

@@ -321,7 +309,7 @@ def preview_report(contest_id):
321309
}), 200
322310

323311
except Exception as e:
324-
print(f" Preview error: {e}")
312+
print(f" Preview error: {e}")
325313
traceback.print_exc()
326314
return jsonify({'error': str(e)}), 500
327315

@@ -332,7 +320,6 @@ def preview_report(contest_id):
332320
def delete_report(report_id):
333321
"""Delete a generated report"""
334322
try:
335-
print(f"\n🗑️ Delete request for report {report_id}")
336323

337324
current_user = request.current_user
338325
report = ContestReport.query.get_or_404(report_id)
@@ -346,23 +333,20 @@ def delete_report(report_id):
346333
if report.file_path and os.path.exists(report.file_path):
347334
try:
348335
os.remove(report.file_path)
349-
print(f"✅ Deleted file: {report.file_path}")
350336
except Exception as e:
351-
print(f"⚠️ File delete error: {e}")
337+
print(f" File delete error: {e}")
352338

353339
# Delete database record
354340
db.session.delete(report)
355341
db.session.commit()
356342

357-
print(f"✅ Report {report_id} deleted successfully")
358-
359343
return jsonify({
360344
'success': True,
361345
'message': 'Report deleted successfully'
362346
}), 200
363347

364348
except Exception as e:
365-
print(f" Delete error: {e}")
349+
print(f" Delete error: {e}")
366350
traceback.print_exc()
367351
return jsonify({'error': str(e)}), 500
368352

@@ -382,21 +366,21 @@ def report_health():
382366
db.session.execute('SELECT 1')
383367
dependencies['database'] = True
384368
except Exception as e:
385-
print(f" Database check failed: {e}")
369+
print(f" Database check failed: {e}")
386370

387371
# Check reportlab
388372
try:
389373
import reportlab
390374
dependencies['reportlab'] = True
391375
except ImportError:
392-
print(" reportlab not installed")
376+
print(" reportlab not installed")
393377

394378
# Check matplotlib
395379
try:
396380
import matplotlib
397381
dependencies['matplotlib'] = True
398382
except ImportError:
399-
print(" matplotlib not installed")
383+
print(" matplotlib not installed")
400384

401385
# Check reports directory
402386
try:
@@ -412,7 +396,7 @@ def report_health():
412396
os.remove(test_file)
413397
dependencies['reports_directory'] = True
414398
except Exception as e:
415-
print(f" Reports directory check failed: {e}")
399+
print(f" Reports directory check failed: {e}")
416400

417401
all_ok = all(dependencies.values())
418402

backend/app/utils/report_builder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ def _save_file(self, content, extension):
670670
with open(file_path, 'w', encoding='utf-8') as f:
671671
f.write(content)
672672

673-
print(f" Comprehensive Report saved: {file_path}")
673+
print(f" Comprehensive Report saved: {file_path}")
674674

675675
return file_path
676676

docs/CREATE_LOCAL_OAUTH_CONSUMER.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ WikiContest Local Development
4848
```
4949
OAuth 1.0a
5050
```
51-
⚠️ **Must match:** Your code uses OAuth 1.0a protocol.
51+
**Must match:** Your code uses OAuth 1.0a protocol.
5252

5353
#### Application Description
5454
```
@@ -60,7 +60,7 @@ Local development instance of WikiContest for testing and development purposes
6060
http://localhost:5000/api/user/oauth/callback
6161
```
6262

63-
⚠️ **CRITICAL - Must be EXACTLY:**
63+
**CRITICAL - Must be EXACTLY:**
6464
- **Protocol:** `http://` (NOT `https://`)
6565
- **Host:** `localhost` (NOT `127.0.0.1` or any domain)
6666
- **Port:** `5000` (must match your Flask server port)
@@ -75,7 +75,7 @@ http://localhost:5000/api/user/oauth/callback
7575
```
7676
☐ No (Leave unchecked)
7777
```
78-
⚠️ **IMPORTANT:** Must be set to "No" to allow other users to test your application!
78+
**IMPORTANT:** Must be set to "No" to allow other users to test your application!
7979

8080
#### Applicable Grants / Permissions
8181
```
@@ -92,7 +92,7 @@ After clicking **"Propose consumer"**, you'll receive:
9292
- **Consumer Key:** (e.g., `3f383c834a07a181723f1a1de566f7cf`)
9393
- **Consumer Secret:** (e.g., `62c40e0fde2377613d1f82b9b7aabc9fe2a73b30`)
9494

95-
⚠️ **CRITICAL:** Copy BOTH credentials immediately! The consumer secret is only displayed once. If you lose it, you'll need to create a new consumer.
95+
**CRITICAL:** Copy BOTH credentials immediately! The consumer secret is only displayed once. If you lose it, you'll need to create a new consumer.
9696

9797
**Save them to a secure location temporarily.**
9898

0 commit comments

Comments
 (0)