broadfield-dev's picture
Update app.py
4606c78 verified
# app.py (With JSON Download Feature)
from flask import Flask, render_template, request, redirect, url_for, session, flash, abort, Response
from datetime import datetime
import copy
import json # Import the json library
# --- App Configuration ---
app = Flask(__name__)
app.config['SECRET_KEY'] = 'a-key-for-json-download-demo'
# --- In-Memory Data Store ---
chirps_data = {}
chirp_id_counter = 0
# --- Helper Function to Build the Comment Tree ---
def get_chirp_tree():
nodes = copy.deepcopy(chirps_data)
for chirp_id in nodes:
nodes[chirp_id]['children'] = []
nested_chirps = []
for chirp_id, chirp in nodes.items():
if chirp['parent_id'] is not None:
parent = nodes.get(chirp['parent_id'])
if parent:
parent['children'].append(chirp)
else:
nested_chirps.append(chirp)
for chirp_id in nodes:
nodes[chirp_id]['children'].sort(key=lambda x: x['timestamp'])
nested_chirps.sort(key=lambda x: x['timestamp'], reverse=True)
return nested_chirps
# --- Routes ---
@app.route('/', methods=['GET', 'POST'])
def index():
if 'username' not in session:
return redirect(url_for('join'))
if request.method == 'POST':
global chirp_id_counter
content = request.form.get('content')
if content:
chirp_id_counter += 1
new_chirp = {
'id': chirp_id_counter, 'parent_id': None, 'username': session['username'],
'content': content, 'timestamp': datetime.utcnow()
}
chirps_data[new_chirp['id']] = new_chirp
flash('Your new chirp has been posted!', 'success')
return redirect(url_for('index'))
top_level_posts = get_chirp_tree()
return render_template('index.html', posts=top_level_posts)
@app.route('/chirp/<int:chirp_id>')
def view_chirp(chirp_id):
if 'username' not in session:
return redirect(url_for('join'))
all_chirps_tree = get_chirp_tree()
def find_chirp_in_tree(chirp_id, chirps):
for chirp in chirps:
if chirp['id'] == chirp_id: return chirp
found = find_chirp_in_tree(chirp_id, chirp.get('children', []))
if found: return found
return None
main_chirp = find_chirp_in_tree(chirp_id, all_chirps_tree)
if not main_chirp:
abort(404)
return render_template('view_chirp.html', main_chirp=main_chirp)
@app.route('/reply/<int:parent_id>', methods=['POST'])
def reply(parent_id):
if 'username' not in session:
return redirect(url_for('join'))
global chirp_id_counter
content = request.form.get('content')
if parent_id not in chirps_data:
flash('Cannot reply to a non-existent chirp.', 'danger')
return redirect(url_for('index'))
if content:
chirp_id_counter += 1
new_comment = {
'id': chirp_id_counter, 'parent_id': parent_id, 'username': session['username'],
'content': content, 'timestamp': datetime.utcnow()
}
chirps_data[new_comment['id']] = new_comment
flash('Your reply was posted!', 'success')
else:
flash('Reply cannot be empty.', 'danger')
return redirect(url_for('view_chirp', chirp_id=parent_id))
# --- NEW DOWNLOAD ROUTE ---
@app.route('/download_data')
def download_data():
"""Filters user's chirps and provides them as a JSON file download."""
if 'username' not in session:
flash("You must be logged in to download your data.", "danger")
return redirect(url_for('join'))
current_username = session['username']
# Filter the chirps_data dictionary to get only the user's posts and comments
user_chirps = [
chirp for chirp in chirps_data.values()
if chirp['username'] == current_username
]
# Sort the user's data by time for consistency
user_chirps.sort(key=lambda x: x['timestamp'])
# Prepare the JSON data. `indent=2` makes it human-readable.
# `default=str` is crucial to handle datetime objects, which are not JSON serializable by default.
json_data = json.dumps(user_chirps, indent=2, default=str)
# Create a dynamic filename
filename = f"chirp_data_{current_username}.json"
# Create a Flask Response object
return Response(
json_data,
mimetype="application/json",
headers={"Content-Disposition": f"attachment;filename={filename}"}
)
# --- Standard User Routes ---
@app.route('/join', methods=['GET', 'POST'])
def join():
if 'username' in session:
return redirect(url_for('index'))
if request.method == 'POST':
username = request.form.get('username')
if username:
session['username'] = username
flash(f'Welcome, {username}!', 'success')
return redirect(url_for('index'))
else:
flash('Please enter a name to join.', 'danger')
return render_template('join.html')
@app.route('/logout')
def logout():
session.pop('username', None)
flash('You have been logged out.', 'success')
return redirect(url_for('join'))
if __name__ == '__main__':
app.run(debug=True,host="0.0.0.0",port=7860)