from flask import Flask, render_template, request, redirect, url_for, session, g, flash import sqlite3 import os from werkzeug.security import generate_password_hash, check_password_hash from werkzeug.utils import secure_filename from datetime import datetime from flask import current_app from flask import jsonify import markdown import re import bleach def render_markdown(text): html = markdown.markdown(text, extensions=['nl2br']) allowed_tags = ['p', 'br', 'strong', 'em', 'a', 'ul', 'ol', 'li'] allowed_attributes = {'a': ['href', 'title']} return bleach.clean(html, tags=allowed_tags, attributes=allowed_attributes, strip=True) def process_tweet_content(content): content = re.sub(r'#(\w+)', r'#\1', content) content = re.sub(r'@(\w+)', r'@\1', content) return content app = Flask(__name__) def get_user_by_id(user_id): db = get_db() user = db.execute('SELECT * FROM users WHERE id = ?', (user_id,)).fetchone() return dict(user) if user else None def init_jinja_env(app): app.jinja_env.globals.update(get_user_by_id=get_user_by_id) app = Flask(__name__) app.secret_key = 'verysecretok' init_jinja_env(app) @app.template_filter('replace_mentions') def replace_mentions(content): return bleach.linkify(re.sub(r'@(\w+)', r'@\1', content)) DATABASE = 'db.sqlite3' UPLOAD_FOLDER = 'static/uploads/' app.config['UPLOAD_FOLDER'] = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static', 'uploads') ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} def add_rendered_content_column(): db = get_db() try: db.execute('ALTER TABLE tweets ADD COLUMN rendered_content TEXT') db.commit() print("Added rendered_content column to tweets table") except sqlite3.OperationalError as e: if "duplicate column name" in str(e): print("rendered_content column already exists") else: raise e def get_db(): db = getattr(g, '_database', None) if db is None: db = g._database = sqlite3.connect(DATABASE) db.row_factory = sqlite3.Row return db def create_tables(): db = get_db() db.execute('''CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, password TEXT NOT NULL, email TEXT NOT NULL, pfp TEXT, banner TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )''') cursor = db.execute("PRAGMA table_info(users)") columns = [column[1] for column in cursor.fetchall()] if 'created_at' not in columns: db.execute('ALTER TABLE users RENAME TO users_old') db.execute('''CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, password TEXT NOT NULL, email TEXT NOT NULL, pfp TEXT, banner TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )''') cursor = db.execute("PRAGMA table_info(users_old)") old_columns = [column[1] for column in cursor.fetchall()] insert_columns = ['id', 'username', 'password'] select_columns = ['id', 'username', 'password'] if 'email' in old_columns: insert_columns.append('email') select_columns.append('email') else: insert_columns.append('email') select_columns.append("'example@email.com' AS email") if 'pfp' in old_columns: insert_columns.append('pfp') select_columns.append('pfp') if 'banner' in old_columns: insert_columns.append('banner') select_columns.append('banner') db.execute(f''' INSERT INTO users({', '.join(insert_columns)}) SELECT {', '.join(select_columns)} FROM users_old ''') db.execute('DROP TABLE users_old') db.commit() db.execute('''CREATE TABLE IF NOT EXISTS tweets ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL, user_id INTEGER, likes INTEGER DEFAULT 0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY(user_id) REFERENCES users(id) )''') db.execute('''CREATE TABLE IF NOT EXISTS comments ( id INTEGER PRIMARY KEY AUTOINCREMENT, content TEXT NOT NULL, tweet_id INTEGER, user_id INTEGER, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY(tweet_id) REFERENCES tweets(id), FOREIGN KEY(user_id) REFERENCES users(id) )''') db.execute('''CREATE TABLE IF NOT EXISTS likes ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, tweet_id INTEGER, FOREIGN KEY(user_id) REFERENCES users(id), FOREIGN KEY(tweet_id) REFERENCES tweets(id), UNIQUE(user_id, tweet_id) )''') db.execute('''CREATE TABLE IF NOT EXISTS group_members ( group_id INTEGER, user_id INTEGER, joined_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (group_id) REFERENCES groups (id), FOREIGN KEY (user_id) REFERENCES users (id), PRIMARY KEY (group_id, user_id) )''') db.execute('''CREATE TABLE IF NOT EXISTS messages ( id INTEGER PRIMARY KEY AUTOINCREMENT, sender_id INTEGER, receiver_id INTEGER, content TEXT, image TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (sender_id) REFERENCES users (id), FOREIGN KEY (receiver_id) REFERENCES users (id) )''') db.execute('''CREATE TABLE IF NOT EXISTS posts ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER, group_id INTEGER, content TEXT NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users (id), FOREIGN KEY (group_id) REFERENCES groups (id) )''') db.execute('''CREATE TABLE IF NOT EXISTS groups ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, description TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, avatar TEXT, vanity_url TEXT )''') cursor = db.execute("PRAGMA table_info(groups)") columns = [column[1] for column in cursor.fetchall()] if 'vanity_url' not in columns: db.execute('''CREATE TABLE groups_new ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, description TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, avatar TEXT, vanity_url TEXT UNIQUE )''') db.execute('INSERT INTO groups_new SELECT id, name, description, created_at, avatar, NULL FROM groups') db.execute('DROP TABLE groups') db.execute('ALTER TABLE groups_new RENAME TO groups') db.execute('CREATE UNIQUE INDEX IF NOT EXISTS idx_groups_vanity_url ON groups (vanity_url)') cursor = db.execute("PRAGMA table_info(users)") columns = [column[1] for column in cursor.fetchall()] if 'created_at' not in columns: add_rendered_content_column() update_existing_tweets() db.commit() @app.teardown_appcontext def close_connection(exception): db = getattr(g, '_database', None) if db is not None: db.close() def add_columns(): db = get_db() try: db.execute('ALTER TABLE users ADD COLUMN pfp TEXT') except sqlite3.OperationalError: pass try: db.execute('ALTER TABLE tweets ADD COLUMN likes INTEGER DEFAULT 0') except sqlite3.OperationalError: pass try: db.execute('ALTER TABLE users ADD COLUMN banner TEXT') except sqlite3.OperationalError: pass try: db.execute('ALTER TABLE messages ADD COLUMN image TEXT') except sqlite3.OperationalError: pass try: db.execute(''' CREATE TABLE IF NOT EXISTS followers ( follower_id INTEGER, followed_id INTEGER, FOREIGN KEY (follower_id) REFERENCES users (id), FOREIGN KEY (followed_id) REFERENCES users (id), PRIMARY KEY (follower_id, followed_id) ) ''') except sqlite3.OperationalError: pass def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS @app.route('/signup', methods=['GET', 'POST']) def signup(): if request.method == 'POST': username = request.form['username'] password = generate_password_hash(request.form['password']) email = request.form['email'] restricted_usernames = ['avery', 'cgcristi', 'cg', 'ceegee'] if username.lower() in restricted_usernames: flash('This username is not allowed. Please choose a different one.', 'error') return render_template('signup.html') db = get_db() try: db.execute('INSERT INTO users (username, password, email) VALUES (?, ?, ?)', (username, password, email)) db.commit() flash('Account created successfully. Please log in.', 'success') return redirect(url_for('login')) except sqlite3.IntegrityError: flash('Username already exists. Please choose a different one.', 'error') return render_template('signup.html') @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] db = get_db() user = db.execute('SELECT * FROM users WHERE username = ?', (username,)).fetchone() if user and check_password_hash(user['password'], password): session['user_id'] = user['id'] session['username'] = user['username'] if not user['pfp']: return redirect(url_for('profile', username=user['username'])) return redirect(url_for('index')) return render_template('login.html') @app.route('/logout') def logout(): session.pop('user_id', None) session.pop('username', None) session.pop('pfp', None) return redirect(url_for('login')) @app.route('/') def index(): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() tweets = db.execute(''' SELECT t.*, u.username, u.pfp as user_pfp, COALESCE(t.rendered_content, t.content) as displayed_content FROM tweets t JOIN users u ON t.user_id = u.id ORDER BY t.created_at DESC ''').fetchall() tweets = [dict(tweet) for tweet in tweets] for tweet in tweets: tweet['created_at'] = datetime.strptime(tweet['created_at'], '%Y-%m-%d %H:%M:%S') tweet['displayed_content'] = bleach.clean(tweet['displayed_content'], strip=True) liked_tweet_ids = {like['tweet_id'] for like in db.execute('SELECT tweet_id FROM likes WHERE user_id = ?', (session['user_id'],)).fetchall()} user = db.execute('SELECT * FROM users WHERE id = ?', (session['user_id'],)).fetchone() if user is None: flash('User not found. Please log in again.', 'error') return redirect(url_for('logout')) user = dict(user) user['created_at'] = datetime.strptime(user['created_at'], '%Y-%m-%d %H:%M:%S') return render_template('index.html', tweets=tweets, liked_tweet_ids=liked_tweet_ids, user=user, get_user_by_id=get_user_by_id) def update_existing_tweets(): db = get_db() tweets = db.execute('SELECT id, content FROM tweets WHERE rendered_content IS NULL').fetchall() for tweet in tweets: rendered_content = render_markdown(tweet['content']) db.execute('UPDATE tweets SET rendered_content = ? WHERE id = ?', (rendered_content, tweet['id'])) db.commit() print(f"Updated {len(tweets)} existing tweets with rendered content") @app.route('/tweet', methods=['POST']) def tweet(): if 'user_id' in session: content = request.form['content'] if len(content) > 280: return redirect(url_for('index')) processed_content = process_tweet_content(content) rendered_content = render_markdown(processed_content) image = request.files.get('image') db = get_db() if image and allowed_file(image.filename): filename = secure_filename(image.filename) image.save(os.path.join(app.config['UPLOAD_FOLDER'], filename)) db.execute('INSERT INTO tweets (content, rendered_content, user_id, image) VALUES (?, ?, ?, ?)', (content, rendered_content, session['user_id'], filename)) else: db.execute('INSERT INTO tweets (content, rendered_content, user_id) VALUES (?, ?, ?)', (content, rendered_content, session['user_id'])) db.commit() return redirect(url_for('index')) @app.route('/retweet/', methods=['POST']) def retweet(tweet_id): if 'user_id' in session: db = get_db() original_tweet = db.execute('SELECT * FROM tweets WHERE id = ?', (tweet_id,)).fetchone() if original_tweet: db.execute('INSERT INTO tweets (content, rendered_content, user_id, original_tweet_id) VALUES (?, ?, ?, ?)', (original_tweet['content'], original_tweet['rendered_content'], session['user_id'], tweet_id)) db.commit() return redirect(url_for('index')) @app.route('/search', methods=['GET']) def search(): query = request.args.get('q', '') db = get_db() users = db.execute('SELECT * FROM users WHERE username LIKE ? LIMIT 10', ('%' + query + '%',)).fetchall() return render_template('search_results.html', users=users, query=query) @app.route('/hashtag/') def hashtag(hashtag): db = get_db() tweets = db.execute(''' SELECT t.*, u.username, u.pfp as user_pfp FROM tweets t JOIN users u ON t.user_id = u.id WHERE t.content LIKE ? ORDER BY t.created_at DESC ''', ('%#' + hashtag + '%',)).fetchall() return render_template('hashtag.html', tweets=tweets, hashtag=hashtag) @app.route('/tweet/') def tweet_detail(tweet_id): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() tweet = db.execute('SELECT t.id, t.content, u.username, u.pfp, t.likes FROM tweets t JOIN users u ON t.user_id = u.id WHERE t.id = ?', (tweet_id,)).fetchone() comments = db.execute('SELECT c.content, u.username FROM comments c JOIN users u ON c.user_id = u.id WHERE c.tweet_id = ?', (tweet_id,)).fetchall() liked_tweet_ids = {like['tweet_id'] for like in db.execute('SELECT tweet_id FROM likes WHERE user_id = ?', (session['user_id'],)).fetchall()} return render_template('tweet_detail.html', tweet=tweet, comments=comments, liked_tweet_ids=liked_tweet_ids) @app.route('/comment/', methods=['POST']) def comment(tweet_id): if 'user_id' not in session: return jsonify({'success': False, 'message': 'User not logged in'}) content = request.form['content'] db = get_db() db.execute('INSERT INTO comments (content, tweet_id, user_id) VALUES (?, ?, ?)', (content, tweet_id, session['user_id'])) db.commit() return jsonify({'success': True}) @app.route('/like/', methods=['POST']) def like(tweet_id): if 'user_id' not in session: return jsonify({'success': False, 'message': 'User not logged in'}), 401 db = get_db() user_id = session['user_id'] try: existing_like = db.execute('SELECT * FROM likes WHERE user_id = ? AND tweet_id = ?', (user_id, tweet_id)).fetchone() if existing_like: db.execute('DELETE FROM likes WHERE user_id = ? AND tweet_id = ?', (user_id, tweet_id)) db.execute('UPDATE tweets SET likes = likes - 1 WHERE id = ?', (tweet_id,)) else: db.execute('INSERT INTO likes (user_id, tweet_id) VALUES (?, ?)', (user_id, tweet_id)) db.execute('UPDATE tweets SET likes = likes + 1 WHERE id = ?', (tweet_id,)) db.commit() updated_likes = db.execute('SELECT likes FROM tweets WHERE id = ?', (tweet_id,)).fetchone()['likes'] return jsonify({'success': True, 'likes': updated_likes}) except Exception as e: db.rollback() print(f"Error in like route: {str(e)}") return jsonify({'success': False, 'message': 'An error occurred while processing your request'}), 500 @app.route('/profile/') def profile(username): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() user = db.execute('SELECT * FROM users WHERE username = ?', (username,)).fetchone() if not user: abort(404) user = dict(user) if 'created_at' not in user or not user['created_at']: first_tweet = db.execute('SELECT MIN(created_at) as first_tweet_date FROM tweets WHERE user_id = ?', (user['id'],)).fetchone() if first_tweet and first_tweet['first_tweet_date']: user['created_at'] = datetime.strptime(first_tweet['first_tweet_date'], '%Y-%m-%d %H:%M:%S') else: user['created_at'] = datetime.now() else: user['created_at'] = datetime.strptime(user['created_at'], '%Y-%m-%d %H:%M:%S') tweets = db.execute('SELECT * FROM tweets WHERE user_id = ? ORDER BY created_at DESC', (user['id'],)).fetchall() tweets = [dict(tweet) for tweet in tweets] for tweet in tweets: tweet['created_at'] = datetime.strptime(tweet['created_at'], '%Y-%m-%d %H:%M:%S') return render_template('profile.html', user=user, tweets=tweets, get_user_by_id=get_user_by_id) @app.route('/change_profile_picture', methods=['POST']) def change_profile_picture(): if 'user_id' not in session: return redirect(url_for('login')) user_id = session['user_id'] if 'profile_picture' in request.files: file = request.files['profile_picture'] if file and allowed_file(file.filename): filename = secure_filename(file.filename) file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(file_path) db = get_db() db.execute("UPDATE users SET pfp = ? WHERE id = ?", (filename, user_id)) db.commit() flash("Profile picture updated successfully.") else: flash("Invalid file type. Please upload a PNG, JPG, JPEG, or GIF.") else: flash("No file uploaded.") return redirect(url_for('profile')) @app.route('/change_banner', methods=['POST']) def change_banner(): if 'user_id' not in session: return redirect(url_for('login')) user_id = session['user_id'] if 'banner' in request.files: file = request.files['banner'] if file and allowed_file(file.filename): filename = secure_filename(file.filename) file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(file_path) db = get_db() db.execute("UPDATE users SET banner = ? WHERE id = ?", (filename, user_id)) db.commit() flash("Banner updated successfully.") else: flash("Invalid file type. Please upload a PNG, JPG, JPEG, or GIF.") else: flash("No file uploaded.") return redirect(url_for('profile')) @app.route('/edit_tweet/', methods=['GET', 'POST']) def edit_tweet(tweet_id): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() tweet = db.execute('SELECT * FROM tweets WHERE id = ? AND user_id = ?', (tweet_id, session['user_id'])).fetchone() if request.method == 'POST': new_content = request.form['content'] db.execute('UPDATE tweets SET content = ? WHERE id = ?', (new_content, tweet_id)) db.commit() return redirect(url_for('index')) return render_template('edit_tweet.html', tweet=tweet) @app.route('/delete_tweet/', methods=['POST']) def delete_tweet(tweet_id): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() db.execute('DELETE FROM tweets WHERE id = ? AND user_id = ?', (tweet_id, session['user_id'])) db.commit() return redirect(url_for('index')) @app.route('/groups') def groups(): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() search_query = request.args.get('search', '') if search_query: groups = db.execute('SELECT * FROM groups WHERE name LIKE ? ORDER BY name', ('%' + search_query + '%',)).fetchall() else: groups = db.execute('SELECT * FROM groups ORDER BY name').fetchall() return render_template('g.html', groups=groups, get_user_by_id=get_user_by_id, search_query=search_query) @app.route('/new_group', methods=['POST']) def new_group(): if 'user_id' not in session: return redirect(url_for('login')) name = request.form['group_name'] vanity_url = request.form['vanity_url'] description = request.form['description'] db = get_db() try: db.execute('INSERT INTO groups (name, vanity_url, description) VALUES (?, ?, ?)', (name, vanity_url, description)) db.commit() group_id = db.execute('SELECT last_insert_rowid()').fetchone()[0] db.execute('INSERT INTO group_members (group_id, user_id) VALUES (?, ?)', (group_id, session['user_id'])) db.commit() if 'group_picture' in request.files: file = request.files['group_picture'] if file and allowed_file(file.filename): filename = secure_filename(file.filename) file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) file.save(file_path) db.execute('UPDATE groups SET avatar = ? WHERE id = ?', (filename, group_id)) db.commit() flash('Group created successfully!', 'success') except sqlite3.IntegrityError: flash('Group name or vanity URL already exists. Please choose a different one.', 'error') return redirect(url_for('groups')) @app.route('/group/') def group_detail(vanity_url): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() group = db.execute('SELECT * FROM groups WHERE vanity_url = ?', (vanity_url,)).fetchone() if not group: abort(404) posts = db.execute(''' SELECT p.*, u.username, u.pfp FROM posts p JOIN users u ON p.user_id = u.id WHERE p.group_id = ? ORDER BY p.created_at DESC ''', (group['id'],)).fetchall() is_member = db.execute('SELECT * FROM group_members WHERE group_id = ? AND user_id = ?', (group['id'], session['user_id'])).fetchone() is not None return render_template('group_detail.html', group=group, posts=posts, is_member=is_member, get_user_by_id=get_user_by_id) @app.route('/join_group/', methods=['POST']) def join_group(group_id): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() db.execute('INSERT INTO group_members (group_id, user_id) VALUES (?, ?)', (group_id, session['user_id'])) db.commit() group = db.execute('SELECT vanity_url FROM groups WHERE id = ?', (group_id,)).fetchone() flash('You have joined the group!', 'success') return redirect(url_for('group_detail', vanity_url=group['vanity_url'])) @app.route('/leave_group/', methods=['POST']) def leave_group(group_id): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() db.execute('DELETE FROM group_members WHERE user_id = ? AND group_id = ?', (session['user_id'], group_id)) db.commit() group = db.execute('SELECT * FROM groups WHERE id = ?', (group_id,)).fetchone() return redirect(url_for('group_detail', vanity_url=group['vanity_url'])) @app.route('/post_in_group/', methods=['POST']) def post_in_group(group_id): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() is_member = db.execute('SELECT * FROM group_members WHERE group_id = ? AND user_id = ?', (group_id, session['user_id'])).fetchone() is not None if not is_member: flash('You must be a member of the group to post.', 'error') else: content = request.form['content'] db.execute('INSERT INTO posts (user_id, group_id, content) VALUES (?, ?, ?)', (session['user_id'], group_id, content)) db.commit() flash('Your post has been added to the group!', 'success') group = db.execute('SELECT vanity_url FROM groups WHERE id = ?', (group_id,)).fetchone() return redirect(url_for('group_detail', vanity_url=group['vanity_url'])) @app.route('/dms') def dms(): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() page = request.args.get('page', 1, type=int) per_page = 10 offset = (page - 1) * per_page conversations = db.execute(''' SELECT DISTINCT CASE WHEN sender_id = ? THEN receiver_id ELSE sender_id END AS other_user_id, MAX(created_at) as last_message_time FROM messages WHERE sender_id = ? OR receiver_id = ? GROUP BY other_user_id ORDER BY last_message_time DESC LIMIT ? OFFSET ? ''', (session['user_id'], session['user_id'], session['user_id'], per_page, offset)).fetchall() dms = [] for conv in conversations: other_user = get_user_by_id(conv['other_user_id']) dms.append({ 'username': other_user['username'], 'pfp': other_user['pfp'] }) has_more = len(dms) == per_page return render_template('dm.html', dms=dms, page=page, has_more=has_more) @app.route('/dm/') def dm_conversation(username): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() other_user = db.execute('SELECT * FROM users WHERE username = ?', (username,)).fetchone() if not other_user: abort(404) messages = db.execute(''' SELECT m.*, u.username, u.pfp FROM messages m JOIN users u ON m.sender_id = u.id WHERE (m.sender_id = ? AND m.receiver_id = ?) OR (m.sender_id = ? AND m.receiver_id = ?) ORDER BY m.created_at ASC ''', (session['user_id'], other_user['id'], other_user['id'], session['user_id'])).fetchall() return render_template('dm_conversation.html', other_user=other_user, messages=messages) @app.route('/edit_group/', methods=['GET', 'POST']) def edit_group(group_id): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() group = db.execute('SELECT * FROM groups WHERE id = ?', (group_id,)).fetchone() if request.method == 'POST': name = request.form['name'] description = request.form['description'] db.execute('UPDATE groups SET name = ?, description = ? WHERE id = ?', (name, description, group_id)) db.commit() flash('Group updated successfully!', 'success') return redirect(url_for('group_detail', vanity_url=group['vanity_url'])) return render_template('edit_group.html', group=group) @app.route('/dm//send', methods=['POST']) def send_message(username): if 'user_id' not in session: return redirect(url_for('login')) content = request.form['content'] image = request.files.get('image') db = get_db() receiver = db.execute('SELECT id FROM users WHERE username = ?', (username,)).fetchone() if receiver: image_filename = None if image and allowed_file(image.filename): image_filename = secure_filename(image.filename) image.save(os.path.join(app.config['UPLOAD_FOLDER'], image_filename)) db.execute('INSERT INTO messages (sender_id, receiver_id, content, image, created_at) VALUES (?, ?, ?, ?, ?)', (session['user_id'], receiver['id'], content, image_filename, datetime.now())) db.commit() return redirect(url_for('dm_conversation', username=username)) @app.route('/check_new_messages/', methods=['GET']) def check_new_messages(username): if 'user_id' not in session: return jsonify({'success': False, 'message': 'Unauthorized'}) db = get_db() other_user = db.execute('SELECT id FROM users WHERE username = ?', (username,)).fetchone() if not other_user: return jsonify({'success': False, 'message': 'User not found'}) last_message_id = request.args.get('last_message_id', 0, type=int) new_messages = db.execute(''' SELECT m.*, u.username, u.pfp FROM messages m JOIN users u ON m.sender_id = u.id WHERE ((m.sender_id = ? AND m.receiver_id = ?) OR (m.sender_id = ? AND m.receiver_id = ?)) AND m.id > ? ORDER BY m.created_at ASC ''', (session['user_id'], other_user['id'], other_user['id'], session['user_id'], last_message_id)).fetchall() if new_messages: return jsonify({ 'success': True, 'messages': [{ 'id': message['id'], 'content': message['content'], 'sender_id': message['sender_id'], 'username': message['username'], 'pfp': message['pfp'], 'created_at': message['created_at'], 'image': message['image'] } for message in new_messages] }) else: return jsonify({'success': False, 'message': 'No new messages'}) @app.route('/delete_group/', methods=['POST']) def delete_group(group_id): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() db.execute('DELETE FROM groups WHERE id = ?', (group_id,)) db.commit() return redirect(url_for('groups')) @app.route('/start_dm', methods=['POST']) def start_dm(): if 'user_id' not in session: return redirect(url_for('login')) username = request.form['username'] return redirect(url_for('dm_conversation', username=username)) @app.route('/edit_message/', methods=['POST']) def edit_message(message_id): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() message = db.execute('SELECT * FROM messages WHERE id = ? AND sender_id = ?', (message_id, session['user_id'])).fetchone() if not message: abort(404) new_content = request.form['content'] db.execute('UPDATE messages SET content = ? WHERE id = ?', (new_content, message_id)) db.commit() return redirect(url_for('dm_conversation', username=request.form['username'])) @app.route('/delete_message/', methods=['POST']) def delete_message(message_id): if 'user_id' not in session: return redirect(url_for('login')) db = get_db() db.execute('DELETE FROM messages WHERE id = ? AND sender_id = ?', (message_id, session['user_id'])) db.commit() return redirect(url_for('dm_conversation', username=request.form['username'])) @app.route('/admin') def admin_panel(): if 'user_id' not in session: return redirect(url_for('login')) user = get_user_by_id(session['user_id']) if not user or user['username'] != '123': return redirect(url_for('login')) db = get_db() users = db.execute('SELECT * FROM users ORDER BY created_at DESC').fetchall() tweets = db.execute(''' SELECT t.*, u.username FROM tweets t JOIN users u ON t.user_id = u.id ORDER BY t.created_at DESC ''').fetchall() groups = db.execute(''' SELECT g.*, COUNT(gm.user_id) as member_count FROM groups g LEFT JOIN group_members gm ON g.id = gm.group_id GROUP BY g.id ORDER BY g.created_at DESC ''').fetchall() user_count = db.execute('SELECT COUNT(*) as count FROM users').fetchone()['count'] tweet_count = db.execute('SELECT COUNT(*) as count FROM tweets').fetchone()['count'] group_count = db.execute('SELECT COUNT(*) as count FROM groups').fetchone()['count'] return render_template('admin_panel.html', users=users, tweets=tweets, groups=groups, user_count=user_count, tweet_count=tweet_count, group_count=group_count) def get_all_users(): db = get_db() users = db.execute('SELECT * FROM users').fetchall() return [dict(user) for user in users] def get_all_tweets(): db = get_db() tweets = db.execute('SELECT t.*, u.username FROM tweets t JOIN users u ON t.user_id = u.id ORDER BY t.created_at DESC').fetchall() return [dict(tweet) for tweet in tweets] def get_all_groups(): db = get_db() groups = db.execute('SELECT * FROM groups ORDER BY created_at DESC').fetchall() return [dict(group) for group in groups] @app.route('/admin/delete_user/', methods=['POST']) def delete_user(user_id): if 'user_id' not in session or get_user_by_id(session['user_id']).username != 'avery': return jsonify({'success': False, 'message': 'Unauthorized'}) db = get_db() db.execute('DELETE FROM users WHERE id = ?', (user_id,)) db.commit() return jsonify({'success': True}) @app.route('/admin/delete_tweet/', methods=['POST']) def delete_tweet_admin(tweet_id): if 'user_id' not in session or get_user_by_id(session['user_id']).username != 'avery': return jsonify({'success': False, 'message': 'Unauthorized'}) db = get_db() db.execute('DELETE FROM tweets WHERE id = ?', (tweet_id,)) db.commit() return jsonify({'success': True}) @app.route('/admin/delete_group/', methods=['POST']) def delete_group_admin(group_id): if 'user_id' not in session or get_user_by_id(session['user_id'])['username'] != 'avery': return jsonify({'success': False, 'message': 'Unauthorized'}) db = get_db() db.execute('DELETE FROM groups WHERE id = ?', (group_id,)) db.execute('DELETE FROM group_members WHERE group_id = ?', (group_id,)) db.execute('DELETE FROM posts WHERE group_id = ?', (group_id,)) db.commit() return jsonify({'success': True}) if __name__ == '__main__': app.run(debug=True, port=4771)