2024-06-14 09:35:53 +00:00
|
|
|
from flask import Flask, render_template, request, redirect, url_for, session, jsonify, send_from_directory, make_response
|
2024-06-13 13:57:02 +00:00
|
|
|
from flask_sqlalchemy import SQLAlchemy
|
2024-06-13 17:47:01 +00:00
|
|
|
from cryptography.fernet import Fernet, InvalidToken
|
2024-06-13 13:57:02 +00:00
|
|
|
import os
|
2024-06-14 09:35:53 +00:00
|
|
|
from datetime import datetime, timedelta, timezone
|
2024-06-13 13:57:02 +00:00
|
|
|
from werkzeug.security import generate_password_hash, check_password_hash
|
|
|
|
from flask_socketio import SocketIO, emit, join_room, leave_room
|
2024-06-14 09:35:53 +00:00
|
|
|
import logging
|
|
|
|
import jwt
|
2024-06-24 08:50:18 +00:00
|
|
|
from flask_migrate import Migrate
|
2024-06-14 09:35:53 +00:00
|
|
|
|
|
|
|
# Set up logging
|
|
|
|
logging.basicConfig(filename='app.log', level=logging.DEBUG,
|
|
|
|
format='%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]', filemode='w')
|
|
|
|
logger = logging.getLogger(__name__)
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
app.config['SECRET_KEY'] = os.urandom(24)
|
|
|
|
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
|
|
|
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
2024-06-13 17:47:01 +00:00
|
|
|
app.config['UPLOAD_FOLDER'] = 'cdn'
|
|
|
|
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
2024-06-13 13:57:02 +00:00
|
|
|
db = SQLAlchemy(app)
|
|
|
|
socketio = SocketIO(app)
|
2024-06-24 08:50:18 +00:00
|
|
|
migrate = Migrate(app, db)
|
2024-06-13 13:57:02 +00:00
|
|
|
|
2024-06-13 17:47:01 +00:00
|
|
|
# Load encryption key
|
2024-06-13 13:57:02 +00:00
|
|
|
def load_key():
|
|
|
|
return open("secret.key", "rb").read()
|
|
|
|
|
|
|
|
# Ensure the key file exists
|
|
|
|
if not os.path.exists("secret.key"):
|
2024-06-13 17:47:01 +00:00
|
|
|
key = Fernet.generate_key()
|
|
|
|
with open("secret.key", "wb") as key_file:
|
|
|
|
key_file.write(key)
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
key = load_key()
|
|
|
|
cipher = Fernet(key)
|
|
|
|
|
2024-06-14 09:35:53 +00:00
|
|
|
# JWT Utility Functions
|
|
|
|
def generate_token(user_id):
|
|
|
|
payload = {
|
|
|
|
'user_id': user_id,
|
|
|
|
'exp': datetime.now(timezone.utc) + timedelta(days=7)
|
|
|
|
}
|
|
|
|
token = jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')
|
|
|
|
return token
|
|
|
|
|
|
|
|
def decode_token(token):
|
|
|
|
try:
|
|
|
|
payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
|
|
|
|
return payload['user_id']
|
|
|
|
except jwt.ExpiredSignatureError:
|
|
|
|
return None
|
|
|
|
except jwt.InvalidTokenError:
|
|
|
|
return None
|
|
|
|
|
2024-06-13 13:57:02 +00:00
|
|
|
class User(db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
username = db.Column(db.String(150), unique=True, nullable=False)
|
|
|
|
password = db.Column(db.String(150), nullable=False)
|
|
|
|
online = db.Column(db.Boolean, nullable=False, default=False)
|
2024-06-24 08:50:18 +00:00
|
|
|
is_admin = db.Column(db.Boolean, nullable=False, default=False)
|
|
|
|
disabled = db.Column(db.Boolean, nullable=False, default=False)
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
class Message(db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
2024-06-24 08:50:18 +00:00
|
|
|
sender_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
|
|
receiver_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
2024-06-13 13:57:02 +00:00
|
|
|
content = db.Column(db.Text, nullable=False)
|
2024-06-13 17:47:01 +00:00
|
|
|
content_type = db.Column(db.String(20), nullable=False, default='text')
|
2024-06-14 09:35:53 +00:00
|
|
|
timestamp = db.Column(db.DateTime, nullable=False, default=datetime.now(timezone.utc))
|
2024-06-24 08:50:18 +00:00
|
|
|
sender = db.relationship('User', foreign_keys=[sender_id])
|
|
|
|
receiver = db.relationship('User', foreign_keys=[receiver_id])
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
class PendingMessage(db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
sender = db.Column(db.String(150), nullable=False)
|
|
|
|
receiver = db.Column(db.String(150), nullable=False)
|
|
|
|
content = db.Column(db.Text, nullable=False)
|
2024-06-13 17:47:01 +00:00
|
|
|
content_type = db.Column(db.String(20), nullable=False, default='text')
|
2024-06-14 09:35:53 +00:00
|
|
|
timestamp = db.Column(db.DateTime, nullable=False, default=datetime.now(timezone.utc))
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
class Friend(db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
|
|
friend_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
|
|
user = db.relationship('User', foreign_keys=[user_id])
|
|
|
|
friend = db.relationship('User', foreign_keys=[friend_id])
|
|
|
|
|
|
|
|
class FriendRequest(db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
sender_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
|
|
receiver_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
|
|
status = db.Column(db.String(20), nullable=False, default='pending')
|
|
|
|
sender = db.relationship('User', foreign_keys=[sender_id])
|
|
|
|
receiver = db.relationship('User', foreign_keys=[receiver_id])
|
|
|
|
|
2024-06-24 08:50:18 +00:00
|
|
|
class Group(db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
name = db.Column(db.String(150), unique=True, nullable=False)
|
|
|
|
admin_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
|
|
admin = db.relationship('User', foreign_keys=[admin_id])
|
|
|
|
|
|
|
|
class GroupMember(db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
group_id = db.Column(db.Integer, db.ForeignKey('group.id'), nullable=False)
|
|
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
|
|
user = db.relationship('User', foreign_keys=[user_id])
|
|
|
|
group = db.relationship('Group', foreign_keys=[group_id])
|
|
|
|
|
|
|
|
class GroupMessage(db.Model):
|
|
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
|
|
group_id = db.Column(db.Integer, db.ForeignKey('group.id'), nullable=False)
|
|
|
|
sender_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
|
|
content = db.Column(db.Text, nullable=False)
|
|
|
|
content_type = db.Column(db.String(20), nullable=False, default='text')
|
|
|
|
timestamp = db.Column(db.DateTime, nullable=False, default=datetime.now(timezone.utc))
|
|
|
|
group = db.relationship('Group', foreign_keys=[group_id])
|
|
|
|
sender = db.relationship('User', foreign_keys=[sender_id])
|
|
|
|
|
|
|
|
|
2024-06-13 13:57:02 +00:00
|
|
|
@app.route('/')
|
|
|
|
def index():
|
2024-06-14 09:35:53 +00:00
|
|
|
token = request.cookies.get('token')
|
|
|
|
if token:
|
|
|
|
user_id = decode_token(token)
|
|
|
|
if user_id:
|
|
|
|
user = User.query.get(user_id)
|
|
|
|
if user:
|
|
|
|
session['username'] = user.username
|
|
|
|
session['user_id'] = user.id
|
|
|
|
return redirect(url_for('dashboard'))
|
2024-06-13 13:57:02 +00:00
|
|
|
return redirect(url_for('login'))
|
|
|
|
|
|
|
|
@app.route('/register', methods=['GET', 'POST'])
|
|
|
|
def register():
|
|
|
|
if request.method == 'POST':
|
2024-06-24 08:50:18 +00:00
|
|
|
username = request.form['username'].lower()
|
2024-06-13 13:57:02 +00:00
|
|
|
password = request.form['password']
|
|
|
|
hashed_password = generate_password_hash(password) # Default method
|
|
|
|
new_user = User(username=username, password=hashed_password)
|
|
|
|
try:
|
|
|
|
db.session.add(new_user)
|
|
|
|
db.session.commit()
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"New user registered: {username}")
|
2024-06-13 13:57:02 +00:00
|
|
|
return redirect(url_for('login'))
|
2024-06-13 17:47:01 +00:00
|
|
|
except Exception as e:
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.error(f"Error registering user {username}: {e}")
|
2024-06-13 13:57:02 +00:00
|
|
|
return 'Username already exists!'
|
|
|
|
return render_template('register.html')
|
|
|
|
|
|
|
|
@app.route('/login', methods=['GET', 'POST'])
|
|
|
|
def login():
|
2024-06-24 08:50:18 +00:00
|
|
|
if 'username' in session:
|
|
|
|
return redirect(url_for('dashboard'))
|
|
|
|
|
2024-06-13 13:57:02 +00:00
|
|
|
if request.method == 'POST':
|
2024-06-24 08:50:18 +00:00
|
|
|
username = request.form['username'].lower()
|
2024-06-13 13:57:02 +00:00
|
|
|
password = request.form['password']
|
|
|
|
user = User.query.filter_by(username=username).first()
|
2024-06-24 08:50:18 +00:00
|
|
|
if user:
|
|
|
|
if user.disabled:
|
|
|
|
logger.warning(f"Disabled account login attempt: {username}")
|
|
|
|
return jsonify({'status': 'error', 'message': 'Account Disabled. Contact Support'})
|
|
|
|
if check_password_hash(user.password, password):
|
|
|
|
session['username'] = user.username
|
|
|
|
session['user_id'] = user.id
|
|
|
|
session['is_admin'] = user.is_admin
|
|
|
|
token = generate_token(user.id)
|
|
|
|
response = make_response(jsonify({'status': 'success'}))
|
|
|
|
expires = datetime.now(timezone.utc) + timedelta(days=7)
|
|
|
|
response.set_cookie('token', token, httponly=True, expires=expires)
|
|
|
|
logger.info(f"User logged in: {username}")
|
|
|
|
return response
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.warning(f"Invalid login attempt for user: {username}")
|
2024-06-24 08:50:18 +00:00
|
|
|
return jsonify({'status': 'error', 'message': 'Invalid credentials. Please try again.'})
|
2024-06-13 13:57:02 +00:00
|
|
|
return render_template('login.html')
|
|
|
|
|
2024-06-24 08:50:18 +00:00
|
|
|
|
|
|
|
@app.route('/change_password', methods=['GET', 'POST'])
|
|
|
|
def change_password():
|
|
|
|
if request.method == 'POST':
|
|
|
|
username = request.form['username'].lower()
|
|
|
|
current_password = request.form['current_password']
|
|
|
|
new_password = request.form['new_password']
|
|
|
|
|
|
|
|
user = User.query.filter_by(username=username).first()
|
|
|
|
if user and check_password_hash(user.password, current_password):
|
|
|
|
hashed_new_password = generate_password_hash(new_password)
|
|
|
|
user.password = hashed_new_password
|
|
|
|
db.session.commit()
|
|
|
|
logger.info(f"Password changed for user: {username}")
|
|
|
|
return jsonify({'status': 'Password changed successfully'})
|
|
|
|
logger.warning(f"Password change failed for user: {username}")
|
|
|
|
return jsonify({'status': 'error'})
|
|
|
|
|
|
|
|
return render_template('change_password.html')
|
|
|
|
|
|
|
|
|
|
|
|
# Update your admin check accordingly
|
|
|
|
@app.route('/admin', methods=['GET'])
|
|
|
|
def admin_panel():
|
|
|
|
if 'username' in session:
|
|
|
|
user = User.query.filter_by(username=session['username']).first()
|
|
|
|
if user and user.is_admin:
|
|
|
|
users = User.query.all()
|
|
|
|
return render_template('admin_panel.html', users=users)
|
|
|
|
return redirect(url_for('login'))
|
|
|
|
|
|
|
|
@app.route('/admin/change_password', methods=['POST'])
|
|
|
|
def admin_change_password():
|
|
|
|
if 'username' in session:
|
|
|
|
admin_user = User.query.filter_by(username=session['username']).first()
|
|
|
|
logger.debug(f"Admin User: {admin_user.username}, Is Admin: {admin_user.is_admin}")
|
|
|
|
if admin_user and admin_user.is_admin: # Check if the user is an admin
|
|
|
|
try:
|
|
|
|
data = request.get_json() # Parse the JSON data from the request
|
|
|
|
user_id = data['user_id']
|
|
|
|
new_password = data['new_password']
|
|
|
|
user = User.query.get(user_id)
|
|
|
|
if user:
|
|
|
|
user.password = generate_password_hash(new_password)
|
|
|
|
db.session.commit()
|
|
|
|
return jsonify({'status': 'success'})
|
|
|
|
return jsonify({'status': 'user not found'}), 404
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(f"Error changing password: {e}")
|
|
|
|
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
|
|
logger.warning(f"Unauthorized attempt to access admin change password by user {session.get('username', 'unknown')}")
|
|
|
|
return jsonify({'status': 'error'}), 401
|
|
|
|
|
|
|
|
@app.route('/admin/disable_account', methods=['POST'])
|
|
|
|
def admin_disable_account():
|
|
|
|
if 'username' in session and session.get('is_admin'):
|
|
|
|
try:
|
|
|
|
data = request.get_json()
|
|
|
|
user_id = data['user_id']
|
|
|
|
user = User.query.get(user_id)
|
|
|
|
if user:
|
|
|
|
user.disabled = True
|
|
|
|
db.session.commit()
|
|
|
|
return jsonify({'status': 'success'})
|
|
|
|
return jsonify({'status': 'user not found'}), 404
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(f"Error disabling account: {e}")
|
|
|
|
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
|
|
logger.warning(f"Unauthorized attempt to disable account by user {session.get('username', 'unknown')}")
|
|
|
|
return jsonify({'status': 'error'}), 401
|
|
|
|
|
|
|
|
@app.route('/admin/enable_account', methods=['POST'])
|
|
|
|
def admin_enable_account():
|
|
|
|
if 'username' in session and session.get('is_admin'):
|
|
|
|
try:
|
|
|
|
data = request.get_json()
|
|
|
|
user_id = data['user_id']
|
|
|
|
user = User.query.get(user_id)
|
|
|
|
if user:
|
|
|
|
user.disabled = False
|
|
|
|
db.session.commit()
|
|
|
|
return jsonify({'status': 'success'})
|
|
|
|
return jsonify({'status': 'user not found'}), 404
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(f"Error enabling account: {e}")
|
|
|
|
return jsonify({'status': 'error', 'message': str(e)}), 500
|
|
|
|
logger.warning(f"Unauthorized attempt to enable account by user {session.get('username', 'unknown')}")
|
|
|
|
return jsonify({'status': 'error'}), 401
|
|
|
|
|
2024-06-13 13:57:02 +00:00
|
|
|
@app.route('/dashboard')
|
|
|
|
def dashboard():
|
|
|
|
if 'username' in session:
|
|
|
|
user = User.query.filter_by(username=session['username']).first()
|
|
|
|
friends = Friend.query.filter_by(user_id=user.id).all()
|
|
|
|
friend_ids = [friend.friend_id for friend in friends]
|
|
|
|
friend_users = User.query.filter(User.id.in_(friend_ids)).all()
|
|
|
|
|
|
|
|
friend_requests = FriendRequest.query.filter_by(receiver_id=user.id, status='pending').all()
|
|
|
|
pending_messages = PendingMessage.query.filter_by(receiver=session['username']).all()
|
2024-06-24 08:50:18 +00:00
|
|
|
messages = Message.query.filter_by(receiver_id=user.id).all() # Updated line
|
|
|
|
|
|
|
|
# Fetch groups for the user
|
|
|
|
group_memberships = GroupMember.query.filter_by(user_id=user.id).all()
|
|
|
|
group_ids = [membership.group_id for membership in group_memberships]
|
|
|
|
groups = Group.query.filter(Group.id.in_(group_ids)).all()
|
2024-06-13 13:57:02 +00:00
|
|
|
|
2024-06-13 17:47:01 +00:00
|
|
|
decrypted_pending_messages = []
|
|
|
|
for msg in pending_messages:
|
|
|
|
try:
|
|
|
|
decrypted_pending_messages.append((msg.sender, cipher.decrypt(msg.content.encode()).decode(), msg.timestamp))
|
|
|
|
except InvalidToken:
|
|
|
|
decrypted_pending_messages.append((msg.sender, "Invalid encrypted message", msg.timestamp))
|
|
|
|
|
|
|
|
decrypted_messages = []
|
|
|
|
for msg in messages:
|
|
|
|
try:
|
|
|
|
decrypted_messages.append((msg.sender, cipher.decrypt(msg.content.encode()).decode(), msg.timestamp))
|
|
|
|
except InvalidToken:
|
|
|
|
decrypted_messages.append((msg.sender, "Invalid encrypted message", msg.timestamp))
|
|
|
|
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"User {session['username']} accessed dashboard")
|
2024-06-24 08:50:18 +00:00
|
|
|
return render_template('dashboard.html', username=session['username'], user_id=user.id, friends=friend_users, friend_requests=friend_requests, pending_messages=decrypted_pending_messages, messages=decrypted_messages, groups=groups, is_admin=user.is_admin)
|
2024-06-13 13:57:02 +00:00
|
|
|
return redirect(url_for('login'))
|
|
|
|
|
2024-06-13 17:47:01 +00:00
|
|
|
@app.route('/chat/<int:friend_id>')
|
|
|
|
def chat(friend_id):
|
2024-06-13 13:57:02 +00:00
|
|
|
if 'username' in session:
|
2024-06-13 17:47:01 +00:00
|
|
|
current_user_id = session['user_id']
|
|
|
|
friend = Friend.query.filter_by(user_id=current_user_id, friend_id=friend_id).first()
|
2024-06-13 13:57:02 +00:00
|
|
|
if friend:
|
2024-06-13 17:47:01 +00:00
|
|
|
friend_user = User.query.filter_by(id=friend_id).first()
|
|
|
|
user = User.query.filter_by(id=current_user_id).first()
|
|
|
|
friends = Friend.query.filter_by(user_id=user.id).all()
|
|
|
|
friend_ids = [f.friend_id for f in friends]
|
|
|
|
friend_users = User.query.filter(User.id.in_(friend_ids)).all()
|
|
|
|
|
|
|
|
friend_requests = FriendRequest.query.filter_by(receiver_id=user.id, status='pending').all()
|
2024-06-24 08:50:18 +00:00
|
|
|
|
|
|
|
# Fetch groups for the user
|
|
|
|
group_memberships = GroupMember.query.filter_by(user_id=user.id).all()
|
|
|
|
group_ids = [membership.group_id for membership in group_memberships]
|
|
|
|
groups = Group.query.filter(Group.id.in_(group_ids)).all()
|
|
|
|
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"User {session['username']} opened chat with {friend_user.username}")
|
2024-06-24 08:50:18 +00:00
|
|
|
return render_template('chat.html', username=session['username'], friend_id=friend_id, friend_username=friend_user.username, friends=friend_users, friend_requests=friend_requests, groups=groups, is_admin=user.is_admin)
|
2024-06-13 13:57:02 +00:00
|
|
|
else:
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.warning(f"User {session['username']} attempted to access chat with non-friend user_id: {friend_id}")
|
2024-06-13 17:47:01 +00:00
|
|
|
return redirect(url_for('dashboard'))
|
|
|
|
return redirect(url_for('login'))
|
2024-06-13 13:57:02 +00:00
|
|
|
|
2024-06-13 17:47:01 +00:00
|
|
|
@app.route('/send_message/<receiver>', methods=['POST'])
|
|
|
|
def send_message(receiver):
|
|
|
|
if 'username' in session:
|
|
|
|
try:
|
|
|
|
content = request.form.get('content')
|
|
|
|
timestamp = request.form.get('timestamp')
|
2024-06-14 09:35:53 +00:00
|
|
|
file = request.files.get('file')
|
2024-06-13 17:47:01 +00:00
|
|
|
content_type = 'text'
|
|
|
|
|
|
|
|
if file:
|
2024-06-14 09:35:53 +00:00
|
|
|
filename = f"{datetime.now(timezone.utc).timestamp()}_{file.filename}"
|
2024-06-13 17:47:01 +00:00
|
|
|
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
|
|
|
|
content = filename
|
|
|
|
content_type = 'file'
|
|
|
|
|
2024-06-14 09:35:53 +00:00
|
|
|
if content:
|
2024-06-13 17:47:01 +00:00
|
|
|
# Encrypt text content only, do not encrypt file names
|
|
|
|
encrypted_content = cipher.encrypt(content.encode()).decode() if content_type == 'text' else content
|
2024-06-14 09:35:53 +00:00
|
|
|
timestamp_dt = datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc)
|
2024-06-13 17:47:01 +00:00
|
|
|
|
|
|
|
# Check if they are friends
|
2024-06-24 08:50:18 +00:00
|
|
|
sender_user = User.query.filter_by(username=session['username']).first()
|
2024-06-13 17:47:01 +00:00
|
|
|
receiver_user = User.query.filter_by(id=receiver).first()
|
|
|
|
if not receiver_user:
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.error(f"Message send failed: User not found {receiver}")
|
2024-06-13 17:47:01 +00:00
|
|
|
return jsonify({'error': 'User not found'}), 404
|
2024-06-24 08:50:18 +00:00
|
|
|
friend = Friend.query.filter_by(user_id=sender_user.id, friend_id=receiver_user.id).first()
|
2024-06-13 17:47:01 +00:00
|
|
|
|
|
|
|
if friend:
|
2024-06-24 08:50:18 +00:00
|
|
|
new_message = Message(sender_id=sender_user.id, receiver_id=receiver_user.id, content=encrypted_content, content_type=content_type, timestamp=timestamp_dt)
|
2024-06-13 17:47:01 +00:00
|
|
|
db.session.add(new_message)
|
|
|
|
db.session.commit()
|
|
|
|
decrypted_content = cipher.decrypt(encrypted_content.encode()).decode() if content_type == 'text' else encrypted_content
|
|
|
|
socketio.emit('new_message', {
|
|
|
|
'sender': session['username'],
|
|
|
|
'content': decrypted_content,
|
|
|
|
'content_type': content_type,
|
2024-06-14 09:35:53 +00:00
|
|
|
'timestamp': timestamp,
|
|
|
|
'id': new_message.id
|
2024-06-13 17:47:01 +00:00
|
|
|
}, room=receiver_user.username)
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"Message sent from {session['username']} to {receiver_user.username}")
|
|
|
|
return jsonify({'status': 'Message sent', 'message_id': new_message.id}), 200
|
2024-06-13 17:47:01 +00:00
|
|
|
else:
|
|
|
|
pending_message = PendingMessage(sender=session['username'], receiver=receiver_user.username, content=encrypted_content, content_type=content_type, timestamp=timestamp_dt)
|
|
|
|
db.session.add(pending_message)
|
|
|
|
db.session.commit()
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"Pending message from {session['username']} to {receiver_user.username}")
|
2024-06-13 17:47:01 +00:00
|
|
|
|
2024-06-14 09:35:53 +00:00
|
|
|
return jsonify({'status': 'Pending message sent', 'message_id': pending_message.id}), 200
|
2024-06-13 17:47:01 +00:00
|
|
|
return jsonify({'error': 'No content or file provided'}), 400
|
|
|
|
except Exception as e:
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.error(f"Error sending message from {session['username']} to {receiver}: {e}")
|
2024-06-13 17:47:01 +00:00
|
|
|
return jsonify({'error': str(e)}), 500
|
2024-06-13 13:57:02 +00:00
|
|
|
return jsonify({'error': 'Unauthorized'}), 401
|
|
|
|
|
2024-06-13 17:47:01 +00:00
|
|
|
@app.route('/get_messages/<int:friend_id>', methods=['GET'])
|
|
|
|
def get_messages(friend_id):
|
2024-06-13 13:57:02 +00:00
|
|
|
if 'username' in session:
|
2024-06-13 17:47:01 +00:00
|
|
|
current_user_id = session['user_id']
|
|
|
|
current_user = User.query.filter_by(id=current_user_id).first()
|
|
|
|
friend_user = User.query.filter_by(id=friend_id).first()
|
|
|
|
if friend_user:
|
|
|
|
friend = Friend.query.filter_by(user_id=current_user_id, friend_id=friend_id).first()
|
|
|
|
if friend:
|
|
|
|
messages = Message.query.filter(
|
2024-06-24 08:50:18 +00:00
|
|
|
((Message.sender_id == current_user.id) & (Message.receiver_id == friend_user.id)) |
|
|
|
|
((Message.sender_id == friend_user.id) & (Message.receiver_id == current_user.id))
|
2024-06-13 17:47:01 +00:00
|
|
|
).all()
|
|
|
|
decrypted_messages = [
|
2024-06-24 08:50:18 +00:00
|
|
|
{
|
|
|
|
'id': msg.id,
|
|
|
|
'sender': msg.sender.username,
|
|
|
|
'content': cipher.decrypt(msg.content.encode()).decode() if msg.content_type == 'text' else msg.content,
|
|
|
|
'content_type': msg.content_type,
|
|
|
|
'timestamp': msg.timestamp.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
}
|
2024-06-13 17:47:01 +00:00
|
|
|
for msg in messages
|
|
|
|
]
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"Messages retrieved for chat between {current_user.username} and {friend_user.username}")
|
2024-06-13 17:47:01 +00:00
|
|
|
return jsonify({'messages': decrypted_messages})
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.warning(f"Unauthorized message retrieval attempt by user {session.get('username', 'unknown')}")
|
2024-06-13 13:57:02 +00:00
|
|
|
return jsonify({'error': 'Unauthorized'}), 401
|
|
|
|
|
2024-06-24 08:50:18 +00:00
|
|
|
|
2024-06-13 17:47:01 +00:00
|
|
|
@app.route('/cdn/<filename>')
|
|
|
|
def uploaded_file(filename):
|
|
|
|
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
|
|
|
|
|
2024-06-13 13:57:02 +00:00
|
|
|
@app.route('/add_friend', methods=['POST'])
|
|
|
|
def add_friend():
|
|
|
|
if 'username' in session:
|
2024-06-24 08:50:18 +00:00
|
|
|
friend_username = request.form['friend_username'].lower() # Convert to lowercase
|
2024-06-13 13:57:02 +00:00
|
|
|
user = User.query.filter_by(username=session['username']).first()
|
|
|
|
friend = User.query.filter_by(username=friend_username).first()
|
|
|
|
if friend and user != friend:
|
2024-06-24 08:50:18 +00:00
|
|
|
# Check if friend request already exists
|
|
|
|
existing_request = FriendRequest.query.filter_by(sender_id=user.id, receiver_id=friend.id).first()
|
|
|
|
if existing_request:
|
|
|
|
return jsonify({'status': 'Friend request already sent'})
|
|
|
|
|
|
|
|
# Check if already friends
|
|
|
|
existing_friend = Friend.query.filter(
|
|
|
|
((Friend.user_id == user.id) & (Friend.friend_id == friend.id)) |
|
|
|
|
((Friend.user_id == friend.id) & (Friend.friend_id == user.id))
|
|
|
|
).first()
|
|
|
|
if existing_friend:
|
|
|
|
return jsonify({'status': 'Already friends'})
|
|
|
|
|
2024-06-13 13:57:02 +00:00
|
|
|
friend_request = FriendRequest(sender_id=user.id, receiver_id=friend.id)
|
|
|
|
db.session.add(friend_request)
|
|
|
|
db.session.commit()
|
|
|
|
socketio.emit('friend_request', {
|
|
|
|
'sender': session['username'],
|
|
|
|
'receiver': friend_username
|
|
|
|
}, room=friend_username)
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"Friend request sent from {session['username']} to {friend_username}")
|
2024-06-24 08:50:18 +00:00
|
|
|
return jsonify({'status': 'Friend request sent'})
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.warning(f"Friend request failed from {session['username']} to {friend_username}: Friend not found or cannot add yourself as a friend")
|
2024-06-24 08:50:18 +00:00
|
|
|
return jsonify({'status': 'Friend not found or cannot add yourself as a friend'})
|
|
|
|
return jsonify({'status': 'Unauthorized'}), 401
|
|
|
|
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
@app.route('/accept_friend/<int:request_id>', methods=['POST'])
|
|
|
|
def accept_friend(request_id):
|
|
|
|
if 'username' in session:
|
|
|
|
friend_request = FriendRequest.query.get(request_id)
|
|
|
|
if friend_request and friend_request.receiver.username == session['username']:
|
|
|
|
friend_request.status = 'accepted'
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
# Create friendships both ways
|
|
|
|
user_id = friend_request.receiver_id
|
|
|
|
friend_id = friend_request.sender_id
|
|
|
|
new_friend_1 = Friend(user_id=user_id, friend_id=friend_id)
|
|
|
|
new_friend_2 = Friend(user_id=friend_id, friend_id=user_id)
|
|
|
|
db.session.add(new_friend_1)
|
|
|
|
db.session.add(new_friend_2)
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
# Move pending messages to messages
|
|
|
|
pending_messages = PendingMessage.query.filter_by(sender=friend_request.sender.username, receiver=friend_request.receiver.username).all()
|
|
|
|
for pm in pending_messages:
|
2024-06-13 17:47:01 +00:00
|
|
|
new_message = Message(sender=pm.sender, receiver=pm.receiver, content=pm.content, content_type=pm.content_type, timestamp=pm.timestamp)
|
2024-06-13 13:57:02 +00:00
|
|
|
db.session.add(new_message)
|
|
|
|
db.session.delete(pm)
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
socketio.emit('friend_request_accepted', {
|
|
|
|
'sender': friend_request.sender.username,
|
|
|
|
'receiver': friend_request.receiver.username
|
|
|
|
}, room=friend_request.sender.username)
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"Friend request accepted by {session['username']} from {friend_request.sender.username}")
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
return redirect(url_for('dashboard'))
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.warning(f"Friend request accept failed: Friend request not found or unauthorized access by {session['username']}")
|
2024-06-13 13:57:02 +00:00
|
|
|
return 'Friend request not found'
|
|
|
|
return redirect(url_for('login'))
|
|
|
|
|
|
|
|
@app.route('/reject_friend/<int:request_id>', methods=['POST'])
|
|
|
|
def reject_friend(request_id):
|
|
|
|
if 'username' in session:
|
|
|
|
friend_request = FriendRequest.query.get(request_id)
|
|
|
|
if friend_request and friend_request.receiver.username == session['username']:
|
|
|
|
db.session.delete(friend_request)
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
socketio.emit('friend_request_rejected', {
|
|
|
|
'sender': friend_request.sender.username,
|
|
|
|
'receiver': friend_request.receiver.username
|
|
|
|
}, room=friend_request.sender.username)
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"Friend request rejected by {session['username']} from {friend_request.sender.username}")
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
return redirect(url_for('dashboard'))
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.warning(f"Friend request reject failed: Friend request not found or unauthorized access by {session['username']}")
|
2024-06-13 13:57:02 +00:00
|
|
|
return 'Friend request not found'
|
|
|
|
return redirect(url_for('login'))
|
|
|
|
|
|
|
|
@app.route('/remove_friend/<int:friend_id>', methods=['POST'])
|
|
|
|
def remove_friend(friend_id):
|
|
|
|
if 'username' in session:
|
|
|
|
user = User.query.filter_by(username=session['username']).first()
|
|
|
|
friend = Friend.query.filter_by(user_id=user.id, friend_id=friend_id).first()
|
|
|
|
if friend:
|
|
|
|
db.session.delete(friend)
|
|
|
|
reciprocal_friend = Friend.query.filter_by(user_id=friend.friend_id, friend_id=user.id).first()
|
|
|
|
if reciprocal_friend:
|
|
|
|
db.session.delete(reciprocal_friend)
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
socketio.emit('friend_removed', {
|
|
|
|
'sender': session['username'],
|
|
|
|
'receiver': friend.friend.username
|
|
|
|
}, room=friend.friend.username)
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"Friend {friend.friend.username} removed by {session['username']}")
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
return redirect(url_for('dashboard'))
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.warning(f"Friend removal failed: Friend not found or unauthorized access by {session['username']}")
|
2024-06-13 13:57:02 +00:00
|
|
|
return 'Friend not found'
|
|
|
|
return redirect(url_for('login'))
|
|
|
|
|
2024-06-24 08:50:18 +00:00
|
|
|
@app.route('/create_group', methods=['POST'])
|
|
|
|
def create_group():
|
|
|
|
if 'username' in session:
|
|
|
|
user = User.query.filter_by(username=session['username']).first()
|
|
|
|
group_name = request.form['group_name']
|
|
|
|
member_usernames = [username.strip() for username in request.form['members'].split(',')]
|
|
|
|
|
|
|
|
# Create a new group
|
|
|
|
new_group = Group(name=group_name, admin_id=user.id)
|
|
|
|
db.session.add(new_group)
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
# Add the group creator as a member
|
|
|
|
new_group_member = GroupMember(group_id=new_group.id, user_id=user.id)
|
|
|
|
db.session.add(new_group_member)
|
|
|
|
|
|
|
|
# Add other members to the group
|
|
|
|
for username in member_usernames:
|
|
|
|
member = User.query.filter_by(username=username).first()
|
|
|
|
if member:
|
|
|
|
new_group_member = GroupMember(group_id=new_group.id, user_id=member.id)
|
|
|
|
db.session.add(new_group_member)
|
|
|
|
|
|
|
|
db.session.commit()
|
|
|
|
|
|
|
|
return redirect(url_for('dashboard'))
|
|
|
|
return redirect(url_for('login'))
|
|
|
|
|
|
|
|
@app.route('/invite_to_group', methods=['POST'])
|
|
|
|
def invite_to_group():
|
|
|
|
if 'username' in session:
|
|
|
|
group_id = request.form['group_id']
|
|
|
|
friend_username = request.form['friend_username']
|
|
|
|
group = Group.query.filter_by(id=group_id).first()
|
|
|
|
if group and group.admin.username == session['username']:
|
|
|
|
friend = User.query.filter_by(username=friend_username).first()
|
|
|
|
if friend:
|
|
|
|
existing_member = GroupMember.query.filter_by(group_id=group.id, user_id=friend.id).first()
|
|
|
|
if not existing_member:
|
|
|
|
group_member = GroupMember(group_id=group.id, user_id=friend.id)
|
|
|
|
db.session.add(group_member)
|
|
|
|
db.session.commit()
|
|
|
|
return jsonify({'status': 'User added to group'})
|
|
|
|
return jsonify({'status': 'User already in group'})
|
|
|
|
return jsonify({'status': 'User not found'})
|
|
|
|
return jsonify({'status': 'Unauthorized'})
|
|
|
|
return jsonify({'status': 'Unauthorized'}), 401
|
|
|
|
|
|
|
|
@app.route('/group_chat/<int:group_id>')
|
|
|
|
def group_chat(group_id):
|
|
|
|
if 'username' in session:
|
|
|
|
group = db.session.get(Group, group_id)
|
|
|
|
user = User.query.filter_by(username=session['username']).first()
|
|
|
|
friends = Friend.query.filter_by(user_id=user.id).all()
|
|
|
|
friend_ids = [friend.friend_id for friend in friends]
|
|
|
|
friend_users = User.query.filter(User.id.in_(friend_ids)).all()
|
|
|
|
|
|
|
|
group_memberships = GroupMember.query.filter_by(user_id=user.id).all()
|
|
|
|
group_ids = [membership.group_id for membership in group_memberships]
|
|
|
|
groups = Group.query.filter(Group.id.in_(group_ids)).all()
|
|
|
|
|
|
|
|
if group:
|
|
|
|
members = GroupMember.query.filter_by(group_id=group_id).all()
|
|
|
|
member_ids = [member.user_id for member in members]
|
|
|
|
member_users = User.query.filter(User.id.in_(member_ids)).all()
|
|
|
|
|
|
|
|
logger.info(f"User {session['username']} accessed group chat: {group.name}")
|
|
|
|
return render_template('group_chat.html', username=session['username'], group=group, members=member_users, friends=friend_users, groups=groups, is_admin=user.is_admin)
|
|
|
|
logger.warning(f"Group not found with id: {group_id}")
|
|
|
|
return redirect(url_for('dashboard'))
|
|
|
|
return redirect(url_for('login'))
|
|
|
|
|
|
|
|
@app.route('/send_group_message/<int:group_id>', methods=['POST'])
|
|
|
|
def send_group_message(group_id):
|
|
|
|
if 'username' in session:
|
|
|
|
try:
|
|
|
|
content = request.form.get('content')
|
|
|
|
timestamp = request.form.get('timestamp')
|
|
|
|
file = request.files.get('file')
|
|
|
|
content_type = 'text'
|
|
|
|
|
|
|
|
if file:
|
|
|
|
filename = f"{datetime.now(timezone.utc).timestamp()}_{file.filename}"
|
|
|
|
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
|
|
|
|
content = filename
|
|
|
|
content_type = 'file'
|
|
|
|
|
|
|
|
if content:
|
|
|
|
encrypted_content = cipher.encrypt(content.encode()).decode() if content_type == 'text' else content
|
|
|
|
timestamp_dt = datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc)
|
|
|
|
|
|
|
|
# Fetch the sender user object
|
|
|
|
sender_user = User.query.filter_by(username=session['username']).first()
|
|
|
|
if not sender_user:
|
|
|
|
return jsonify({'error': 'User not found'}), 404
|
|
|
|
|
|
|
|
# Create new group message
|
|
|
|
new_message = GroupMessage(group_id=group_id, sender_id=sender_user.id, content=encrypted_content, content_type=content_type, timestamp=timestamp_dt)
|
|
|
|
db.session.add(new_message)
|
|
|
|
db.session.commit()
|
|
|
|
decrypted_content = cipher.decrypt(encrypted_content.encode()).decode() if content_type == 'text' else encrypted_content
|
|
|
|
|
|
|
|
socketio.emit('new_group_message', {
|
|
|
|
'group_id': group_id,
|
|
|
|
'sender': session['username'],
|
|
|
|
'content': decrypted_content,
|
|
|
|
'content_type': content_type,
|
|
|
|
'timestamp': timestamp,
|
|
|
|
'id': new_message.id
|
|
|
|
}, room=f"group_{group_id}")
|
|
|
|
logger.info(f"Group message sent from {session['username']} to group {group_id}")
|
|
|
|
return jsonify({'status': 'Message sent', 'message_id': new_message.id}), 200
|
|
|
|
return jsonify({'error': 'No content or file provided'}), 400
|
|
|
|
except Exception as e:
|
|
|
|
logger.error(f"Error sending group message from {session['username']} to group {group_id}: {e}")
|
|
|
|
return jsonify({'error': 'Internal server error'}), 500
|
|
|
|
return jsonify({'error': 'Unauthorized'}), 401
|
|
|
|
|
|
|
|
@app.route('/get_group_messages/<int:group_id>', methods=['GET'])
|
|
|
|
def get_group_messages(group_id):
|
|
|
|
if 'username' in session:
|
|
|
|
group = db.session.get(Group, group_id)
|
|
|
|
if group:
|
|
|
|
messages = db.session.query(GroupMessage, User).join(User, GroupMessage.sender_id == User.id).filter(GroupMessage.group_id == group_id).all()
|
|
|
|
message_list = [
|
|
|
|
{
|
|
|
|
'id': msg.GroupMessage.id,
|
|
|
|
'group_id': msg.GroupMessage.group_id,
|
|
|
|
'sender': msg.User.username, # Use the username from the User table
|
|
|
|
'content': cipher.decrypt(msg.GroupMessage.content.encode()).decode() if msg.GroupMessage.content_type == 'text' else msg.GroupMessage.content,
|
|
|
|
'content_type': msg.GroupMessage.content_type,
|
|
|
|
'timestamp': msg.GroupMessage.timestamp.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
}
|
|
|
|
for msg in messages
|
|
|
|
]
|
|
|
|
logger.info(f"Messages retrieved for group {group_id}")
|
|
|
|
return jsonify({'messages': message_list})
|
|
|
|
else:
|
|
|
|
logger.warning(f"Group not found with id: {group_id}")
|
|
|
|
return jsonify({'error': 'Group not found'}), 404
|
|
|
|
logger.warning(f"Unauthorized message retrieval attempt by user {session.get('username', 'unknown')}")
|
|
|
|
return jsonify({'error': 'Unauthorized'}), 401
|
|
|
|
|
|
|
|
@app.route('/get_groups', methods=['GET'])
|
|
|
|
def get_groups():
|
|
|
|
if 'username' in session:
|
|
|
|
user = User.query.filter_by(username=session['username']).first()
|
|
|
|
if user:
|
|
|
|
group_memberships = GroupMember.query.filter_by(user_id=user.id).all()
|
|
|
|
group_ids = [membership.group_id for membership in group_memberships]
|
|
|
|
groups = Group.query.filter(Group.id.in_(group_ids)).all()
|
|
|
|
|
|
|
|
group_list = [{'id': group.id, 'name': group.name} for group in groups]
|
|
|
|
return jsonify({'groups': group_list})
|
|
|
|
return jsonify({'error': 'Unauthorized'}), 401
|
|
|
|
|
|
|
|
@app.route('/settings', methods=['GET', 'POST'])
|
|
|
|
def settings():
|
|
|
|
if 'username' in session:
|
|
|
|
if request.method == 'POST':
|
|
|
|
theme = request.form['theme']
|
|
|
|
session['theme'] = theme
|
|
|
|
return redirect(url_for('settings'))
|
|
|
|
current_theme = session.get('theme', 'automatic')
|
|
|
|
return render_template('settings.html', current_theme=current_theme)
|
|
|
|
return redirect(url_for('login'))
|
|
|
|
|
2024-06-13 13:57:02 +00:00
|
|
|
@app.route('/logout')
|
|
|
|
def logout():
|
|
|
|
session.pop('username', None)
|
2024-06-13 17:47:01 +00:00
|
|
|
session.pop('user_id', None)
|
2024-06-14 09:35:53 +00:00
|
|
|
response = make_response(redirect(url_for('login')))
|
|
|
|
response.set_cookie('token', '', expires=0)
|
|
|
|
logger.info(f"User logged out")
|
|
|
|
return response
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
@socketio.on('connect')
|
|
|
|
def handle_connect():
|
|
|
|
if 'username' in session:
|
|
|
|
user = User.query.filter_by(username=session['username']).first()
|
|
|
|
if user:
|
|
|
|
user.online = True
|
|
|
|
db.session.commit()
|
|
|
|
emit('user_online', {'username': user.username}, broadcast=True)
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"User {session['username']} connected")
|
2024-06-13 13:57:02 +00:00
|
|
|
|
|
|
|
@socketio.on('disconnect')
|
|
|
|
def handle_disconnect():
|
|
|
|
if 'username' in session:
|
|
|
|
user = User.query.filter_by(username=session['username']).first()
|
|
|
|
if user:
|
|
|
|
user.online = False
|
|
|
|
db.session.commit()
|
|
|
|
emit('user_offline', {'username': user.username}, broadcast=True)
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"User {session['username']} disconnected")
|
2024-06-13 13:57:02 +00:00
|
|
|
|
2024-06-13 17:47:01 +00:00
|
|
|
@socketio.on('join')
|
|
|
|
def handle_join(data):
|
|
|
|
username = data['username']
|
|
|
|
join_room(username)
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"User {username} joined room {username}")
|
2024-06-13 17:47:01 +00:00
|
|
|
|
|
|
|
@socketio.on('leave')
|
|
|
|
def handle_leave(data):
|
|
|
|
username = data['username']
|
|
|
|
leave_room(username)
|
2024-06-14 09:35:53 +00:00
|
|
|
logger.info(f"User {username} left room {username}")
|
2024-06-13 17:47:01 +00:00
|
|
|
|
2024-06-24 08:50:18 +00:00
|
|
|
@socketio.on('join_group')
|
|
|
|
def handle_join_group(data):
|
|
|
|
group_id = data['group_id']
|
|
|
|
username = session['username']
|
|
|
|
join_room(f"group_{group_id}")
|
|
|
|
logger.info(f"User {username} joined group room {group_id}")
|
|
|
|
|
|
|
|
@socketio.on('leave_group')
|
|
|
|
def handle_leave_group(data):
|
|
|
|
group_id = data['group_id']
|
|
|
|
username = session['username']
|
|
|
|
leave_room(f"group_{group_id}")
|
|
|
|
logger.info(f"User {username} left group room {group_id}")
|
|
|
|
|
2024-06-13 13:57:02 +00:00
|
|
|
if __name__ == '__main__':
|
|
|
|
with app.app_context():
|
|
|
|
db.create_all()
|
2024-06-24 08:50:18 +00:00
|
|
|
socketio.run(app, host='0.0.0.0', port=8086, debug=True, allow_unsafe_werkzeug=True)
|