diff --git a/__pycache__/models.cpython-313.pyc b/__pycache__/models.cpython-313.pyc index bc5267f..19e3c6d 100644 Binary files a/__pycache__/models.cpython-313.pyc and b/__pycache__/models.cpython-313.pyc differ diff --git a/app.py b/app.py index bd08a76..8d89b5f 100644 --- a/app.py +++ b/app.py @@ -25,7 +25,6 @@ def create_app(): app.config['SECRET_KEY'] = os.getenv('SECRET_KEY', 'your-secure-secret-key-here') app.config['UPLOAD_FOLDER'] = os.path.join(app.root_path, 'static', 'uploads') app.config['CSS_VERSION'] = os.getenv('CSS_VERSION', '1.0.0') # Add CSS version for cache busting - app.config['JS_VERSION'] = os.getenv('JS_VERSION', '1.0.0') # Add JS version for cache busting # Initialize extensions db.init_app(app) diff --git a/models.py b/models.py index 30deecf..02a1fb8 100644 --- a/models.py +++ b/models.py @@ -205,27 +205,46 @@ class MessageAttachment(db.Model): return f'' class EventType(Enum): + # User events USER_LOGIN = 'user_login' USER_LOGOUT = 'user_logout' - USER_REGISTER = 'user_register' + USER_CREATE = 'user_create' USER_UPDATE = 'user_update' + USER_DELETE = 'user_delete' + + # Room events + ROOM_CREATE = 'room_create' + ROOM_UPDATE = 'room_update' + ROOM_DELETE = 'room_delete' + ROOM_MEMBER_ADD = 'room_member_add' + ROOM_MEMBER_REMOVE = 'room_member_remove' + ROOM_PERMISSION_UPDATE = 'room_permission_update' + + # File events FILE_UPLOAD = 'file_upload' - FILE_DELETE = 'file_delete' FILE_DOWNLOAD = 'file_download' - FILE_RESTORE = 'file_restore' - FILE_MOVE = 'file_move' + FILE_DELETE = 'file_delete' FILE_RENAME = 'file_rename' + FILE_MOVE = 'file_move' FILE_STAR = 'file_star' FILE_UNSTAR = 'file_unstar' - ROOM_CREATE = 'room_create' - ROOM_DELETE = 'room_delete' - ROOM_UPDATE = 'room_update' - ROOM_JOIN = 'room_join' - ROOM_LEAVE = 'room_leave' + + # Conversation events CONVERSATION_CREATE = 'conversation_create' + CONVERSATION_UPDATE = 'conversation_update' CONVERSATION_DELETE = 'conversation_delete' - MESSAGE_SENT = 'message_sent' - ATTACHMENT_DOWNLOAD = 'attachment_download' + CONVERSATION_MEMBER_ADD = 'conversation_member_add' + CONVERSATION_MEMBER_REMOVE = 'conversation_member_remove' + + # Message events + MESSAGE_CREATE = 'message_create' + MESSAGE_UPDATE = 'message_update' + MESSAGE_DELETE = 'message_delete' + MESSAGE_ATTACHMENT_ADD = 'message_attachment_add' + MESSAGE_ATTACHMENT_REMOVE = 'message_attachment_remove' + + # Settings events + SETTINGS_UPDATE = 'settings_update' class Event(db.Model): __tablename__ = 'events' diff --git a/routes/__pycache__/auth.cpython-313.pyc b/routes/__pycache__/auth.cpython-313.pyc index 76dea33..3792ef5 100644 Binary files a/routes/__pycache__/auth.cpython-313.pyc and b/routes/__pycache__/auth.cpython-313.pyc differ diff --git a/routes/__pycache__/conversations.cpython-313.pyc b/routes/__pycache__/conversations.cpython-313.pyc index 80b98ba..bc544d1 100644 Binary files a/routes/__pycache__/conversations.cpython-313.pyc and b/routes/__pycache__/conversations.cpython-313.pyc differ diff --git a/routes/__pycache__/main.cpython-313.pyc b/routes/__pycache__/main.cpython-313.pyc index 21b9a7e..28d31bb 100644 Binary files a/routes/__pycache__/main.cpython-313.pyc and b/routes/__pycache__/main.cpython-313.pyc differ diff --git a/routes/auth.py b/routes/auth.py index 9591b6b..15fab4e 100644 --- a/routes/auth.py +++ b/routes/auth.py @@ -2,8 +2,6 @@ from flask import render_template, request, flash, redirect, url_for from flask_login import login_user, logout_user, login_required, current_user from models import db, User from functools import wraps -from utils.event_logger import log_event -from models import EventType def require_password_change(f): @wraps(f) @@ -33,13 +31,6 @@ def init_routes(auth_bp): login_user(user, remember=remember) - # Log successful login - log_event( - event_type=EventType.USER_LOGIN, - user_id=user.id, - details={'remember': remember} - ) - # Check if user is using default password if password == 'changeme': flash('Please change your password before continuing.', 'warning') @@ -78,13 +69,6 @@ def init_routes(auth_bp): db.session.add(new_user) db.session.commit() - # Log user creation - log_event( - event_type=EventType.USER_CREATE, - user_id=new_user.id, - details={'email': email, 'username': username} - ) - login_user(new_user) return redirect(url_for('main.dashboard')) @@ -93,11 +77,6 @@ def init_routes(auth_bp): @auth_bp.route('/logout') @login_required def logout(): - # Log logout before actually logging out - log_event( - event_type=EventType.USER_LOGOUT, - user_id=current_user.id - ) logout_user() return redirect(url_for('auth.login')) @@ -119,14 +98,6 @@ def init_routes(auth_bp): current_user.set_password(new_password) db.session.commit() - - # Log password change - log_event( - event_type=EventType.USER_UPDATE, - user_id=current_user.id, - details={'action': 'password_change'} - ) - flash('Password changed successfully!', 'success') return redirect(url_for('main.dashboard')) diff --git a/routes/conversations.py b/routes/conversations.py index 3eca36c..3bcdbe9 100644 --- a/routes/conversations.py +++ b/routes/conversations.py @@ -1,9 +1,8 @@ from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify, send_file from flask_login import login_required, current_user -from models import db, Conversation, User, Message, MessageAttachment, EventType +from models import db, Conversation, User, Message, MessageAttachment from forms import ConversationForm from routes.auth import require_password_change -from utils.event_logger import log_event import os from werkzeug.utils import secure_filename from datetime import datetime @@ -85,17 +84,6 @@ def create_conversation(): db.session.add(conversation) db.session.commit() - # Log conversation creation - log_event( - event_type=EventType.CONVERSATION_CREATE, - user_id=current_user.id, - details={ - 'conversation_id': conversation.id, - 'conversation_name': conversation.name, - 'member_count': len(conversation.members) - } - ) - flash('Conversation created successfully!', 'success') return redirect(url_for('conversations.conversations')) return render_template('conversations/create_conversation.html', form=form) @@ -239,18 +227,6 @@ def delete_conversation(conversation_id): conversation = Conversation.query.get_or_404(conversation_id) - # Log conversation deletion before deleting - log_event( - event_type=EventType.CONVERSATION_DELETE, - user_id=current_user.id, - details={ - 'conversation_id': conversation_id, - 'conversation_name': conversation.name, - 'message_count': len(conversation.messages), - 'member_count': len(conversation.members) - } - ) - # Delete all messages in the conversation Message.query.filter_by(conversation_id=conversation_id).delete() @@ -348,18 +324,6 @@ def send_message(conversation_id): db.session.commit() - # Log message sent - log_event( - event_type=EventType.MESSAGE_SENT, - user_id=current_user.id, - details={ - 'conversation_id': conversation_id, - 'message_id': message.id, - 'has_attachments': len(attachments) > 0, - 'attachment_count': len(attachments) - } - ) - # Prepare message data for response message_data = { 'id': message.id, @@ -394,19 +358,6 @@ def download_attachment(message_id, attachment_index): try: attachment = message.attachments[attachment_index] - - # Log attachment download - log_event( - event_type=EventType.ATTACHMENT_DOWNLOAD, - user_id=current_user.id, - details={ - 'conversation_id': conversation.id, - 'message_id': message_id, - 'attachment_name': attachment.name, - 'attachment_size': attachment.size - } - ) - return send_file( attachment.path, as_attachment=True, diff --git a/routes/main.py b/routes/main.py index 67159fd..9038adf 100644 --- a/routes/main.py +++ b/routes/main.py @@ -1,8 +1,7 @@ -from flask import render_template, Blueprint, redirect, url_for, request, flash, Response, jsonify +from flask import render_template, Blueprint, redirect, url_for, request, flash, Response from flask_login import current_user, login_required -from models import User, db, Room, RoomFile, RoomMemberPermission, SiteSettings, Event, EventType +from models import User, db, Room, RoomFile, RoomMemberPermission, SiteSettings from routes.auth import require_password_change -from utils.event_logger import log_event import os from werkzeug.utils import secure_filename from sqlalchemy import func, case, literal_column, text @@ -280,14 +279,6 @@ def init_routes(main_bp): os.remove(old_picture_path) current_user.profile_picture = None db.session.commit() - - # Log profile picture removal - log_event( - event_type=EventType.USER_UPDATE, - user_id=current_user.id, - details={'action': 'remove_profile_picture'} - ) - flash('Profile picture removed successfully!', 'success') return redirect(url_for('main.profile')) @@ -298,10 +289,6 @@ def init_routes(main_bp): if existing_user: flash('A user with this email already exists.', 'error') return render_template('profile/profile.html') - - # Track changes for event logging - changes = {} - # Handle profile picture upload file = request.files.get('profile_picture') if file and file.filename: @@ -309,31 +296,14 @@ def init_routes(main_bp): file_path = os.path.join(UPLOAD_FOLDER, filename) file.save(file_path) current_user.profile_picture = filename - changes['profile_picture'] = True - # Update user information - if current_user.username != request.form.get('first_name'): - current_user.username = request.form.get('first_name') - changes['username'] = True - if current_user.last_name != request.form.get('last_name'): - current_user.last_name = request.form.get('last_name') - changes['last_name'] = True - if current_user.email != new_email: - current_user.email = new_email - changes['email'] = True - if current_user.phone != request.form.get('phone'): - current_user.phone = request.form.get('phone') - changes['phone'] = True - if current_user.company != request.form.get('company'): - current_user.company = request.form.get('company') - changes['company'] = True - if current_user.position != request.form.get('position'): - current_user.position = request.form.get('position') - changes['position'] = True - if current_user.notes != request.form.get('notes'): - current_user.notes = request.form.get('notes') - changes['notes'] = True - + current_user.username = request.form.get('first_name') + current_user.last_name = request.form.get('last_name') + current_user.email = new_email + current_user.phone = request.form.get('phone') + current_user.company = request.form.get('company') + current_user.position = request.form.get('position') + current_user.notes = request.form.get('notes') # Handle password change if provided new_password = request.form.get('new_password') confirm_password = request.form.get('confirm_password') @@ -342,20 +312,9 @@ def init_routes(main_bp): flash('Passwords do not match.', 'error') return render_template('profile/profile.html') current_user.set_password(new_password) - changes['password'] = True flash('Password updated successfully.', 'success') - try: db.session.commit() - - # Log profile update if any changes were made - if changes: - log_event( - event_type=EventType.USER_UPDATE, - user_id=current_user.id, - details={'changes': changes} - ) - flash('Profile updated successfully!', 'success') except Exception as e: db.session.rollback() @@ -396,18 +355,11 @@ def init_routes(main_bp): site_settings = SiteSettings.get_settings() active_tab = request.args.get('tab', 'colors') - - # Get events for the events tab - events = [] - if active_tab == 'events': - events = Event.query.order_by(Event.timestamp.desc()).limit(50).all() - return render_template('settings/settings.html', primary_color=site_settings.primary_color, secondary_color=site_settings.secondary_color, active_tab=active_tab, - site_settings=site_settings, - events=events) + site_settings=site_settings) @main_bp.route('/settings/colors', methods=['POST']) @login_required @@ -578,105 +530,4 @@ def init_routes(main_bp): logger.info(f"[Dynamic Colors] Generated CSS with primary color: {primary_color}") logger.info(f"[Dynamic Colors] Cache version: {site_settings.updated_at.timestamp()}") - return Response(css, mimetype='text/css') - - @main_bp.route('/api/events') - @login_required - def get_events(): - if not current_user.is_admin: - return jsonify({'success': False, 'error': 'Unauthorized'}), 403 - - # Get filter parameters - page = request.args.get('page', 1, type=int) - event_type = request.args.get('eventType') - date_range = request.args.get('dateRange', '24h') - user_id = request.args.get('userId') - - # Build query - query = Event.query - - # Apply filters - if event_type: - query = query.filter_by(event_type=event_type) - if user_id: - query = query.filter_by(user_id=user_id) - - # Apply date range filter - if date_range != 'all': - now = datetime.utcnow() - if date_range == '24h': - start_date = now - timedelta(days=1) - elif date_range == '7d': - start_date = now - timedelta(days=7) - elif date_range == '30d': - start_date = now - timedelta(days=30) - query = query.filter(Event.timestamp >= start_date) - - # Get total count for pagination - total_count = query.count() - per_page = 50 - total_pages = (total_count + per_page - 1) // per_page - - # Get paginated results - events = query.order_by(Event.timestamp.desc())\ - .offset((page - 1) * per_page)\ - .limit(per_page)\ - .all() - - return jsonify({ - 'success': True, - 'events': [{ - 'id': event.id, - 'event_type': event.event_type, - 'timestamp': event.timestamp.isoformat(), - 'user': { - 'id': event.user.id, - 'username': event.user.username, - 'last_name': event.user.last_name or '' - }, - 'ip_address': event.ip_address, - 'details': event.details - } for event in events], - 'total_pages': total_pages - }) - - @main_bp.route('/api/events/') - @login_required - def get_event_details(event_id): - if not current_user.is_admin: - return jsonify({'success': False, 'error': 'Unauthorized'}), 403 - - event = Event.query.get_or_404(event_id) - - return jsonify({ - 'success': True, - 'event': { - 'id': event.id, - 'event_type': event.event_type, - 'timestamp': event.timestamp.isoformat(), - 'user': { - 'id': event.user.id, - 'username': event.user.username - }, - 'ip_address': event.ip_address, - 'user_agent': event.user_agent, - 'details': event.details - } - }) - - @main_bp.route('/api/users') - @login_required - def get_users(): - if not current_user.is_admin: - return jsonify({'success': False, 'error': 'Unauthorized'}), 403 - - users = User.query.order_by(User.username).all() - - return jsonify({ - 'success': True, - 'users': [{ - 'id': user.id, - 'username': user.username, - 'last_name': user.last_name or '' - } for user in users] - }) \ No newline at end of file + return Response(css, mimetype='text/css') \ No newline at end of file diff --git a/static/js/events.js b/static/js/events.js deleted file mode 100644 index e1e1147..0000000 --- a/static/js/events.js +++ /dev/null @@ -1,272 +0,0 @@ -/** - * @fileoverview Manages the events page functionality. - * This file handles event filtering, pagination, and modal interactions. - */ - -document.addEventListener('DOMContentLoaded', function() { - // Elements - const eventTypeFilter = document.getElementById('eventTypeFilter'); - const dateRangeFilter = document.getElementById('dateRangeFilter'); - const userFilter = document.getElementById('userFilter'); - const applyFiltersBtn = document.getElementById('applyFilters'); - const eventsTableBody = document.getElementById('eventsTableBody'); - const prevPageBtn = document.getElementById('prevPage'); - const nextPageBtn = document.getElementById('nextPage'); - const currentPageSpan = document.getElementById('currentPage'); - const totalPagesSpan = document.getElementById('totalPages'); - const eventDetailsModal = document.getElementById('eventDetailsModal'); - const eventDetailsContent = document.getElementById('eventDetailsContent'); - - // State - let currentPage = 1; - let totalPages = 1; - let currentFilters = { - eventType: '', - dateRange: '24h', - userId: '' - }; - - /** - * Loads events based on current filters and page - */ - async function loadEvents() { - try { - const response = await fetch(`/api/events?page=${currentPage}&${new URLSearchParams(currentFilters)}`); - const data = await response.json(); - - if (data.success) { - renderEvents(data.events); - updatePagination(data.total_pages); - } else { - console.error('Failed to load events:', data.error); - } - } catch (error) { - console.error('Error loading events:', error); - } - } - - /** - * Renders events in the table - */ - function renderEvents(events) { - if (!Array.isArray(events)) { - console.error('Invalid events data received:', events); - return; - } - - const eventRows = events.map(event => { - if (!event || typeof event !== 'object') { - console.error('Invalid event data:', event); - return ''; - } - - // Determine badge color and text based on event type - let badgeClass = 'bg-secondary'; - let eventText = event.event_type || 'Unknown Event'; - - switch(event.event_type) { - case 'user_login': - badgeClass = 'bg-success'; - eventText = 'User Login'; - break; - case 'user_logout': - badgeClass = 'bg-secondary'; - eventText = 'User Logout'; - break; - case 'user_register': - badgeClass = 'bg-info'; - eventText = 'User Registration'; - break; - case 'user_update': - badgeClass = 'bg-primary'; - eventText = 'User Update'; - break; - case 'file_upload': - badgeClass = 'bg-success'; - eventText = 'File Upload'; - break; - case 'file_delete': - badgeClass = 'bg-danger'; - eventText = 'File Delete'; - break; - case 'file_download': - badgeClass = 'bg-info'; - eventText = 'File Download'; - break; - case 'file_restore': - badgeClass = 'bg-warning'; - eventText = 'File Restore'; - break; - case 'file_move': - badgeClass = 'bg-primary'; - eventText = 'File Move'; - break; - case 'file_rename': - badgeClass = 'bg-info'; - eventText = 'File Rename'; - break; - case 'file_star': - badgeClass = 'bg-warning'; - eventText = 'File Star'; - break; - case 'file_unstar': - badgeClass = 'bg-secondary'; - eventText = 'File Unstar'; - break; - case 'room_create': - badgeClass = 'bg-success'; - eventText = 'Room Create'; - break; - case 'room_delete': - badgeClass = 'bg-danger'; - eventText = 'Room Delete'; - break; - case 'room_update': - badgeClass = 'bg-primary'; - eventText = 'Room Update'; - break; - case 'room_join': - badgeClass = 'bg-info'; - eventText = 'Room Join'; - break; - case 'room_leave': - badgeClass = 'bg-secondary'; - eventText = 'Room Leave'; - break; - case 'conversation_create': - badgeClass = 'bg-success'; - eventText = 'Conversation Create'; - break; - case 'conversation_delete': - badgeClass = 'bg-danger'; - eventText = 'Conversation Delete'; - break; - case 'message_sent': - badgeClass = 'bg-primary'; - eventText = 'Message Sent'; - break; - case 'attachment_download': - badgeClass = 'bg-info'; - eventText = 'Attachment Download'; - break; - } - - const timestamp = event.timestamp ? new Date(event.timestamp).toLocaleString() : '-'; - const username = event.user?.username || 'Unknown User'; - const lastName = event.user?.last_name || ''; - const eventId = event.id || ''; - const ipAddress = event.ip_address || '-'; - - return ` - - ${timestamp} - ${eventText} - ${username} ${lastName} - - - - ${ipAddress} - - `; - }).join(''); - - eventsTableBody.innerHTML = eventRows; - - // Add event listeners to detail buttons - document.querySelectorAll('[data-event-id]').forEach(button => { - button.addEventListener('click', () => { - const eventId = button.dataset.eventId; - if (eventId) { - showEventDetails(eventId); - } - }); - }); - } - - /** - * Updates pagination controls - */ - function updatePagination(total) { - totalPages = total; - currentPageSpan.textContent = currentPage; - totalPagesSpan.textContent = totalPages; - - prevPageBtn.classList.toggle('disabled', currentPage === 1); - nextPageBtn.classList.toggle('disabled', currentPage === totalPages); - } - - /** - * Shows event details in modal - */ - async function showEventDetails(eventId) { - try { - const response = await fetch(`/api/events/${eventId}`); - const data = await response.json(); - - if (data.success) { - const event = data.event; - eventDetailsContent.textContent = JSON.stringify(event.details, null, 2); - } else { - console.error('Failed to load event details:', data.error); - } - } catch (error) { - console.error('Error loading event details:', error); - } - } - - /** - * Loads users for the user filter - */ - async function loadUsers() { - try { - const response = await fetch('/api/users'); - const data = await response.json(); - - const userFilter = document.getElementById('userFilter'); - userFilter.innerHTML = ''; - - data.users.forEach(user => { - const option = document.createElement('option'); - option.value = user.id; - option.textContent = `${user.username} ${user.last_name || ''}`.trim(); - userFilter.appendChild(option); - }); - } catch (error) { - console.error('Error loading users:', error); - } - } - - // Event Listeners - applyFiltersBtn.addEventListener('click', () => { - currentFilters = { - eventType: eventTypeFilter.value, - dateRange: dateRangeFilter.value, - userId: userFilter.value - }; - currentPage = 1; - loadEvents(); - }); - - prevPageBtn.addEventListener('click', () => { - if (currentPage > 1) { - currentPage--; - loadEvents(); - } - }); - - nextPageBtn.addEventListener('click', () => { - if (currentPage < totalPages) { - currentPage++; - loadEvents(); - } - }); - - // Initialize - loadUsers(); - loadEvents(); -}); \ No newline at end of file diff --git a/static/js/file-grid.js b/static/js/file-grid.js index 95a99e2..36ffc80 100644 --- a/static/js/file-grid.js +++ b/static/js/file-grid.js @@ -354,24 +354,6 @@ function toggleStar(filename, path = '', roomId) { .then(r => r.json()) .then(res => { if (res.success) { - // Log the star/unstar event - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': csrfToken - }, - body: JSON.stringify({ - event_type: res.starred ? 'file_star' : 'file_unstar', - details: { - filename: filename, - path: path, - room_id: roomId, - timestamp: new Date().toISOString() - } - }) - }); - // Remove the file from the current view since it's no longer starred currentFiles = currentFiles.filter(f => !(f.name === filename && f.path === path && f.room_id === roomId)); renderFiles(currentFiles); @@ -412,24 +394,6 @@ function restoreFile(filename, path = '', roomId) { .then(r => r.json()) .then(res => { if (res.success) { - // Log the restore event - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': csrfToken - }, - body: JSON.stringify({ - event_type: 'file_restore', - details: { - filename: filename, - path: path, - room_id: roomId, - timestamp: new Date().toISOString() - } - }) - }); - // Remove the file from the current view since it's been restored currentFiles = currentFiles.filter(f => !(f.name === filename && f.path === path && f.room_id === roomId)); renderFiles(currentFiles); @@ -470,7 +434,7 @@ function permanentDeleteFile() { return; } - fetch(`/api/rooms/${roomId}/delete_permanent`, { + fetch(`/api/rooms/${roomId}/delete-permanent`, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -481,40 +445,39 @@ function permanentDeleteFile() { path: path }) }) - .then(r => r.json()) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + // Check if the response is empty + const contentType = response.headers.get('content-type'); + if (contentType && contentType.includes('application/json')) { + return response.json(); + } + return { success: true }; // If no JSON response, assume success + }) .then(res => { if (res.success) { - // Log the permanent delete event - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': csrfToken - }, - body: JSON.stringify({ - event_type: 'file_delete_permanent', - details: { - filename: filename, - path: path, - room_id: roomId, - timestamp: new Date().toISOString() - } - }) - }); - - // Remove the file from the current view + // Remove the file from the current view since it's been deleted currentFiles = currentFiles.filter(f => !(f.name === filename && f.path === path && f.room_id === roomId)); renderFiles(currentFiles); - // Close the modal const modal = bootstrap.Modal.getInstance(document.getElementById('permanentDeleteModal')); - modal.hide(); + if (modal) { + modal.hide(); + } } else { - console.error('Failed to delete file permanently:', res.error); + console.error('Failed to delete file:', res.error || 'Unknown error'); } }) .catch(error => { - console.error('Error deleting file permanently:', error); + console.error('Error deleting file:', error); + // Show error to user + const modal = bootstrap.Modal.getInstance(document.getElementById('permanentDeleteModal')); + if (modal) { + modal.hide(); + } + // You might want to show an error message to the user here }); } diff --git a/static/js/room-members.js b/static/js/room-members.js index 49ef5bf..198174c 100644 --- a/static/js/room-members.js +++ b/static/js/room-members.js @@ -13,95 +13,19 @@ * - Auto-save functionality for permission changes * @function */ -document.addEventListener('DOMContentLoaded', function() { - // Initialize Select2 +$(document).ready(function() { + // Initialize Select2 for user selection $('.select2').select2({ - theme: 'bootstrap-5' + theme: 'bootstrap-5', + width: '100%', + placeholder: 'Search for a user...', + allowClear: true }); - - // Log when a member is added to the room - const addMemberForm = document.querySelector('form[action*="/add_member"]'); - if (addMemberForm) { - addMemberForm.addEventListener('submit', function(e) { - const formData = new FormData(this); - const userId = formData.get('user_id'); - const roomId = this.action.split('/rooms/')[1].split('/add_member')[0]; - - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') - }, - body: JSON.stringify({ - event_type: 'room_join', - details: { - room_id: roomId, - user_id: userId, - timestamp: new Date().toISOString() - } - }) - }); - }); - } - - // Log when a member is removed from the room - const removeMemberForms = document.querySelectorAll('form[action*="/remove_member"]'); - removeMemberForms.forEach(form => { - form.addEventListener('submit', function(e) { - const roomId = this.action.split('/rooms/')[1].split('/remove_member')[0]; - const userId = this.action.split('/users/')[1]; - - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') - }, - body: JSON.stringify({ - event_type: 'room_leave', - details: { - room_id: roomId, - user_id: userId, - timestamp: new Date().toISOString() - } - }) - }); - }); - }); - - // Log when member permissions are updated - const permissionForms = document.querySelectorAll('.auto-save-perms-form'); - permissionForms.forEach(form => { - form.addEventListener('change', function(e) { - const roomId = this.action.split('/rooms/')[1].split('/update_member_permissions')[0]; - const userId = this.action.split('/users/')[1]; - const formData = new FormData(this); - - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') - }, - body: JSON.stringify({ - event_type: 'room_member_permissions_update', - details: { - room_id: roomId, - user_id: userId, - permissions: { - can_view: formData.get('can_view') === '1', - can_download: formData.get('can_download') === 'on', - can_upload: formData.get('can_upload') === 'on', - can_delete: formData.get('can_delete') === 'on', - can_rename: formData.get('can_rename') === 'on', - can_move: formData.get('can_move') === 'on', - can_share: formData.get('can_share') === 'on' - }, - timestamp: new Date().toISOString() - } - }) - }); + + // Auto-submit permission form on checkbox change + document.querySelectorAll('.auto-save-perms-form input[type="checkbox"]').forEach(function(checkbox) { + checkbox.addEventListener('change', function() { + this.closest('form').submit(); }); }); }); \ No newline at end of file diff --git a/static/js/rooms-list.js b/static/js/rooms-list.js index 271fa5c..75068ad 100644 --- a/static/js/rooms-list.js +++ b/static/js/rooms-list.js @@ -46,137 +46,4 @@ document.addEventListener('DOMContentLoaded', function() { form.submit(); }); } - - // Log when rooms page is viewed - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') - }, - body: JSON.stringify({ - event_type: 'room_list_view', - details: { - timestamp: new Date().toISOString() - } - }) - }); - - // Log when a room is opened - const openRoomButtons = document.querySelectorAll('a[href*="/room/"]'); - openRoomButtons.forEach(button => { - button.addEventListener('click', function(e) { - const roomId = this.href.split('/room/')[1]; - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') - }, - body: JSON.stringify({ - event_type: 'room_open', - details: { - room_id: roomId, - timestamp: new Date().toISOString() - } - }) - }); - }); - }); - - // Log when a room is deleted - const deleteRoomForms = document.querySelectorAll('form[action*="/delete"]'); - deleteRoomForms.forEach(form => { - form.addEventListener('submit', function(e) { - const roomId = this.action.split('/rooms/')[1].split('/delete')[0]; - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') - }, - body: JSON.stringify({ - event_type: 'room_delete', - details: { - room_id: roomId, - timestamp: new Date().toISOString() - } - }) - }); - }); - }); - - // Log when a room is created - const createRoomForm = document.querySelector('form[action*="/create"]'); - if (createRoomForm) { - createRoomForm.addEventListener('submit', function(e) { - const formData = new FormData(this); - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') - }, - body: JSON.stringify({ - event_type: 'room_create', - details: { - room_name: formData.get('name'), - description: formData.get('description'), - timestamp: new Date().toISOString() - } - }) - }); - }); - } - - // Log when a room is edited - const editRoomForm = document.querySelector('form[action*="/edit"]'); - if (editRoomForm) { - editRoomForm.addEventListener('submit', function(e) { - const roomId = this.action.split('/rooms/')[1].split('/edit')[0]; - const formData = new FormData(this); - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') - }, - body: JSON.stringify({ - event_type: 'room_update', - details: { - room_id: roomId, - room_name: formData.get('name'), - description: formData.get('description'), - timestamp: new Date().toISOString() - } - }) - }); - }); - } - - // Log when room search is performed - if (searchInput) { - let searchTimeout; - searchInput.addEventListener('input', function(e) { - clearTimeout(searchTimeout); - searchTimeout = setTimeout(() => { - if (this.value.length > 0) { - fetch('/api/events/log', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content') - }, - body: JSON.stringify({ - event_type: 'room_search', - details: { - search_term: this.value, - timestamp: new Date().toISOString() - } - }) - }); - } - }, 500); - }); - } }); \ No newline at end of file diff --git a/templates/settings/settings.html b/templates/settings/settings.html index 5af4a76..d75f4b9 100644 --- a/templates/settings/settings.html +++ b/templates/settings/settings.html @@ -4,7 +4,6 @@ {% from "settings/tabs/company_info.html" import company_info_tab %} {% from "settings/tabs/security.html" import security_tab %} {% from "settings/tabs/debugging.html" import debugging_tab %} -{% from "settings/tabs/events.html" import events_tab %} {% from "settings/components/reset_colors_modal.html" import reset_colors_modal %} {% block title %}Settings - DocuPulse{% endblock %} @@ -37,11 +36,6 @@ Company Info -