diff --git a/routes/__pycache__/main.cpython-313.pyc b/routes/__pycache__/main.cpython-313.pyc index 00d9c04..3f073ba 100644 Binary files a/routes/__pycache__/main.cpython-313.pyc and b/routes/__pycache__/main.cpython-313.pyc differ diff --git a/routes/main.py b/routes/main.py index 43c1503..40eae0c 100644 --- a/routes/main.py +++ b/routes/main.py @@ -5,6 +5,18 @@ import os from werkzeug.utils import secure_filename from sqlalchemy import func, case, literal_column, text from datetime import datetime, timedelta +import logging +import sys + +# Set up logging to show in console +logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.StreamHandler(sys.stdout) + ] +) +logger = logging.getLogger(__name__) def init_routes(main_bp): @main_bp.route('/') @@ -16,6 +28,7 @@ def init_routes(main_bp): @main_bp.route('/dashboard') @login_required def dashboard(): + logger.info("Loading dashboard...") # Get 3 most recent users recent_contacts = User.query.order_by(User.created_at.desc()).limit(3).all() # Count active and inactive users @@ -24,10 +37,13 @@ def init_routes(main_bp): # Room count and size logic if current_user.is_admin: + logger.info("Loading admin dashboard...") room_count = Room.query.count() # Get total file and folder counts for admin file_count = RoomFile.query.filter_by(type='file').count() folder_count = RoomFile.query.filter_by(type='folder').count() + logger.info(f"Admin stats - Files: {file_count}, Folders: {folder_count}") + # Get total size of all files including trash total_size = db.session.query(func.sum(RoomFile.size)).filter(RoomFile.type == 'file').scalar() or 0 # Get recent activity for all files @@ -39,10 +55,21 @@ def init_routes(main_bp): Room, RoomFile.room_id == Room.id ).join( User, RoomFile.uploaded_by == User.id + ).filter( + RoomFile.deleted == False, + RoomFile.uploaded_at.isnot(None) ).order_by( RoomFile.uploaded_at.desc() ).limit(10).all() + logger.info(f"Recent activity query results: {len(recent_activity)}") + if len(recent_activity) == 0: + # Debug query to see what files exist + all_files = RoomFile.query.filter_by(deleted=False).all() + logger.info(f"Total non-deleted files: {len(all_files)}") + for file in all_files[:5]: # Log first 5 files for debugging + logger.info(f"File: {file.name}, Uploaded: {file.uploaded_at}, Type: {file.type}") + # Format the activity data formatted_activity = [] for file, room, user in recent_activity: @@ -57,7 +84,8 @@ def init_routes(main_bp): 'can_download': True # Admin can download everything } formatted_activity.append(activity) - recent_activity = formatted_activity + formatted_activities = formatted_activity + logger.info(f"Formatted activities: {len(formatted_activities)}") # Get storage usage by file type including trash storage_by_type = db.session.query( case( @@ -122,11 +150,24 @@ def init_routes(main_bp): ).join( User, RoomFile.uploaded_by == User.id ).filter( - RoomFile.room_id.in_(room_ids) + RoomFile.room_id.in_(room_ids), + RoomFile.deleted == False, + RoomFile.uploaded_at.isnot(None) # Ensure uploaded_at is not null ).order_by( RoomFile.uploaded_at.desc() ).limit(10).all() + logger.info(f"Recent activity query results (non-admin): {len(recent_activity)}") + if len(recent_activity) == 0: + # Debug query to see what files exist + all_files = RoomFile.query.filter( + RoomFile.room_id.in_(room_ids), + RoomFile.deleted == False + ).all() + logger.info(f"Total non-deleted files in accessible rooms: {len(all_files)}") + for file in all_files[:5]: # Log first 5 files for debugging + logger.info(f"File: {file.name}, Uploaded: {file.uploaded_at}, Type: {file.type}") + # Format the activity data formatted_activity = [] user_perms = {p.room_id: p for p in RoomMemberPermission.query.filter( @@ -147,7 +188,7 @@ def init_routes(main_bp): 'can_download': perm.can_download if perm else False } formatted_activity.append(activity) - recent_activity = formatted_activity + formatted_activities = formatted_activity # Get storage usage by file type for accessible rooms including trash storage_by_type = db.session.query( case( @@ -204,7 +245,6 @@ def init_routes(main_bp): file_count=file_count, folder_count=folder_count, total_size=total_size, - recent_activity=recent_activity, storage_by_type=storage_by_type, trash_count=trash_count, starred_count=starred_count, diff --git a/static/css/dashboard.css b/static/css/dashboard.css new file mode 100644 index 0000000..8595c0d --- /dev/null +++ b/static/css/dashboard.css @@ -0,0 +1,139 @@ +:root { + --primary-color: #16767b; + --secondary-color: #741b5f; + --primary-light: #1a8a90; + --secondary-light: #8a2170; + --warning-color: #ffd700; + --danger-color: #dc3545; +} + +/* Masonry Layout */ +.masonry { + column-count: 1; + column-gap: 1.5rem; +} + +@media (min-width: 768px) { + .masonry { column-count: 2; } +} + +@media (min-width: 1200px) { + .masonry { column-count: 3; } +} + +.masonry-card { + display: inline-block; + width: 100%; + margin-bottom: 1.5rem; +} + +/* Card Styles */ +.card { + border: none; + border-radius: 10px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.card-title { + color: var(--primary-color); +} + +.card-title i { + color: var(--primary-color); +} + +/* Button Styles */ +.btn-primary { + background-color: var(--primary-color); + border-color: var(--primary-color); +} + +.btn-primary:hover { + background-color: var(--primary-light); + border-color: var(--primary-light); +} + +/* Icon Colors */ +.icon-primary { + color: var(--primary-color); +} + +.icon-danger { + color: var(--danger-color); +} + +.icon-warning { + color: var(--warning-color); +} + +/* Text Colors */ +.text-primary { + color: var(--primary-color) !important; +} + +.text-danger { + color: var(--danger-color) !important; +} + +/* Badge Styles */ +.badge-starred { + background-color: rgba(255, 215, 0, 0.15) !important; + color: var(--warning-color) !important; +} + +.badge-trash { + background-color: rgba(220, 53, 69, 0.15) !important; + color: var(--danger-color) !important; +} + +/* Contact Link Styles */ +.contact-link { + background-color: rgba(22, 118, 123, 0.08); + color: var(--primary-color); + transition: all 0.2s; +} + +.contact-link:hover { + background-color: rgba(22, 118, 123, 0.12); + color: var(--primary-color); +} + +/* Chart Container */ +.chart-container { + position: relative; + height: 200px; +} + +/* Alert Styles */ +.alert-info { + background-color: rgba(22, 118, 123, 0.08); + border-color: rgba(22, 118, 123, 0.2); + color: var(--primary-color); +} + +/* List Group Styles */ +.list-group-item { + border: none; + padding: 1rem 0; +} + +.list-group-item:not(:last-child) { + border-bottom: 1px solid rgba(0, 0, 0, 0.05); +} + +/* Download Button */ +.btn-download { + background-color: var(--primary-color); + border: none; + border-radius: 6px; + box-shadow: 0 1px 2px rgba(22, 118, 123, 0.08); + color: white; + transition: all 0.2s; +} + +.btn-download:hover { + background-color: var(--primary-light); + color: white; + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(22, 118, 123, 0.12); +} \ No newline at end of file diff --git a/templates/components/contact_status.html b/templates/components/contact_status.html new file mode 100644 index 0000000..41287de --- /dev/null +++ b/templates/components/contact_status.html @@ -0,0 +1,28 @@ +{% macro contact_status(active_count, inactive_count) %} +
+
+
+
+
Contact Status
+
+ View All + + Add +
+
+
+ +
+
+
+
{{ active_count }}
+
Active
+
+
+
{{ inactive_count }}
+
Inactive
+
+
+
+
+
+{% endmacro %} \ No newline at end of file diff --git a/templates/components/contacts.html b/templates/components/contacts.html new file mode 100644 index 0000000..6a8b038 --- /dev/null +++ b/templates/components/contacts.html @@ -0,0 +1,38 @@ +{% macro contacts(recent_contacts) %} +
+
+
+
+
Recent Contacts
+
+ View All + + Add +
+
+ {% if recent_contacts %} + + {% else %} +
No contacts yet.
+ {% endif %} +
+
+
+{% endmacro %} \ No newline at end of file diff --git a/templates/components/recent_activity.html b/templates/components/recent_activity.html new file mode 100644 index 0000000..bbb32e3 --- /dev/null +++ b/templates/components/recent_activity.html @@ -0,0 +1,59 @@ +{% macro recent_activity(activities) %} +
+
+
+
+
Recent Activity
+ View All +
+
+
+
+ {% for activity in activities %} +
+
+
+ {% if activity.type == 'folder' %} + + {% else %} + + {% endif %} +
+
+
+
+
+
{{ activity.name }}
+ {% if activity.is_starred %} + + Starred + + {% endif %} + {% if activity.is_deleted %} + + Trash + + {% endif %} +
+ + {{ activity.room.name }} • + {{ activity.uploader.username }} {{ activity.uploader.last_name }} • + {% if activity.uploaded_at %}{{ activity.uploaded_at|timeago }}{% else %}Unknown{% endif %} + +
+ {% if activity.type == 'file' and activity.can_download %} + + + + {% endif %} +
+
+
+
+ {% endfor %} +
+
+
+
+{% endmacro %} \ No newline at end of file diff --git a/templates/components/starred_files.html b/templates/components/starred_files.html new file mode 100644 index 0000000..3b865bf --- /dev/null +++ b/templates/components/starred_files.html @@ -0,0 +1,25 @@ +{% macro starred_files(starred_count, file_count) %} +
+
+
+
+
Starred Files
+ View All +
+
+ +
+
+
+
{{ starred_count }}
+
Starred
+
+
+
{{ file_count - starred_count }}
+
Unstarred
+
+
+
+
+
+{% endmacro %} \ No newline at end of file diff --git a/templates/components/storage_overview.html b/templates/components/storage_overview.html new file mode 100644 index 0000000..f16dc3e --- /dev/null +++ b/templates/components/storage_overview.html @@ -0,0 +1,44 @@ +{% from 'macros.html' import format_size %} + +{% macro storage_overview(room_count, file_count, folder_count, total_size) %} +
+
+
+
+
Storage Overview
+ Browse +
+
+
+
+ + Rooms: +
+
{{ room_count }}
+
+
+
+ + Files: +
+
{{ file_count }}
+
+
+
+ + Folders: +
+
{{ folder_count }}
+
+
+
+ + Total Size: +
+
{{ format_size(total_size) }}
+
+
+
+
+
+{% endmacro %} \ No newline at end of file diff --git a/templates/components/storage_usage.html b/templates/components/storage_usage.html new file mode 100644 index 0000000..6641211 --- /dev/null +++ b/templates/components/storage_usage.html @@ -0,0 +1,32 @@ +{% from 'macros.html' import format_size %} + +{% macro storage_usage(storage_by_type) %} +
+
+
+
+
Storage Usage
+ View Details +
+ {% if storage_by_type %} +
+ +
+
+ {% for type in storage_by_type %} +
+
+ + {{ type.extension|upper }}: +
+
{{ format_size(type.total_size) }}
+
+ {% endfor %} +
+ {% else %} +
No storage data available
+ {% endif %} +
+
+
+{% endmacro %} \ No newline at end of file diff --git a/templates/components/trash.html b/templates/components/trash.html new file mode 100644 index 0000000..b8faafa --- /dev/null +++ b/templates/components/trash.html @@ -0,0 +1,53 @@ +{% from 'macros.html' import format_size %} + +{% macro trash(trash_count, pending_deletion, oldest_trash_date, trash_size) %} +
+
+
+
+
Trash
+ View All +
+
+
+
+ + Files in trash: +
+
{{ trash_count }}
+
+
+
+ + Deleting in 7 days: +
+
{{ pending_deletion }}
+
+
+
+ + Oldest deletion: +
+
{{ oldest_trash_date|default('N/A') }}
+
+
+
+ + Storage used: +
+
{{ format_size(trash_size) }}
+
+
+
+ +
+
Files will be permanently deleted after 30 days
+
You can restore files before they are permanently deleted
+
+
+
+
+
+
+
+{% endmacro %} \ No newline at end of file diff --git a/templates/components/trash_type.html b/templates/components/trash_type.html new file mode 100644 index 0000000..4df623f --- /dev/null +++ b/templates/components/trash_type.html @@ -0,0 +1,30 @@ +{% macro trash_type(trash_by_type) %} +
+
+
+
+
Trash by Type
+ View All +
+ {% if trash_by_type %} +
+ +
+
+ {% for type in trash_by_type %} +
+
+ + {{ type.extension|upper }}: +
+
{{ type.count }}
+
+ {% endfor %} +
+ {% else %} +
No files in trash
+ {% endif %} +
+
+
+{% endmacro %} \ No newline at end of file diff --git a/templates/dashboard.html b/templates/dashboard.html index 5cc2c29..f1b4e85 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -2,6 +2,10 @@ {% block title %}Dashboard - DocuPulse{% endblock %} +{% block extra_css %} + +{% endblock %} + {% block content %}

Welcome back, {{ current_user.username }}!

@@ -13,17 +17,13 @@
-{% macro format_size(size) %} - {% if size < 1024 %} - {{ size }} B - {% elif size < 1024 * 1024 %} - {{ (size / 1024)|round(1) }} KB - {% elif size < 1024 * 1024 * 1024 %} - {{ (size / (1024 * 1024))|round(1) }} MB - {% else %} - {{ (size / (1024 * 1024 * 1024))|round(1) }} GB - {% endif %} -{% endmacro %} +{% from 'components/storage_overview.html' import storage_overview %} +{% from 'components/storage_usage.html' import storage_usage %} +{% from 'components/contacts.html' import contacts %} +{% from 'components/contact_status.html' import contact_status %} +{% from 'components/starred_files.html' import starred_files %} +{% from 'components/trash.html' import trash %} +{% from 'components/trash_type.html' import trash_type %}
-
-
-
-
-
Storage Overview
- Browse -
-
-
-
- - Rooms: -
-
{{ room_count }}
-
-
-
- - Files: -
-
{{ file_count }}
-
-
-
- - Folders: -
-
{{ folder_count }}
-
-
-
- - Total Size: -
-
{{ format_size(total_size) }}
-
-
-
-
-
- -
-
-
-
-
Recent Activity
- View All -
-
-
-
- {% for activity in recent_activity %} -
-
-
- {% if activity.type == 'folder' %} - - {% else %} - - {% endif %} -
-
-
-
-
-
{{ activity.name }}
- {% if activity.is_starred %} - - Starred - - {% endif %} - {% if activity.is_deleted %} - - Trash - - {% endif %} -
- - {{ activity.room.name }} • - {{ activity.uploader.username }} {{ activity.uploader.last_name }} • - {% if activity.uploaded_at %}{{ activity.uploaded_at|timeago }}{% else %}Unknown{% endif %} - -
- {% if activity.type == 'file' and activity.can_download %} - - - - {% endif %} -
-
-
-
- {% endfor %} -
-
-
-
- -
-
-
-
-
Storage Usage
- View Details -
- {% if storage_by_type %} -
- -
-
- {% for type in storage_by_type %} -
-
- - {{ type.extension|upper }}: -
-
{{ format_size(type.total_size) }}
-
- {% endfor %} -
- {% else %} -
No storage data available
- {% endif %} -
-
-
- + {{ storage_overview(room_count, file_count, folder_count, total_size) }} + {{ storage_usage(storage_by_type) }} + {% if current_user.is_admin %} -
-
-
-
-
Recent Contacts
-
- View All - + Add -
-
- {% if recent_contacts %} - - {% else %} -
No contacts yet.
- {% endif %} -
-
-
-
-
-
-
-
Contact Status
-
- View All - + Add -
-
-
- -
-
-
-
{{ active_count }}
-
Active
-
-
-
{{ inactive_count }}
-
Inactive
-
-
-
-
-
+ {{ contacts(recent_contacts) }} + {{ contact_status(active_count, inactive_count) }} {% endif %} - -
-
-
-
-
Starred Files
- View All -
-
- -
-
-
-
{{ starred_count }}
-
Starred
-
-
-
{{ file_count - starred_count }}
-
Unstarred
-
-
-
-
-
- -
-
-
-
-
Trash
- View All -
-
-
-
- - Files in trash: -
-
{{ trash_count }}
-
-
-
- - Deleting in 7 days: -
-
{{ pending_deletion }}
-
-
-
- - Oldest deletion: -
-
{{ oldest_trash_date|default('N/A') }}
-
-
-
- - Storage used: -
-
{{ format_size(trash_size) }}
-
-
-
- -
-
Files will be permanently deleted after 30 days
-
You can restore files before they are permanently deleted
-
-
-
-
-
-
-
- -
-
-
-
-
Trash by Type
- View All -
- {% if trash_by_type %} -
- -
-
- {% for type in trash_by_type %} -
-
- - {{ type.extension|upper }}: -
-
{{ type.count }}
-
- {% endfor %} -
- {% else %} -
No files in trash
- {% endif %} -
-
-
+ + {{ starred_files(starred_count, file_count) }} + {{ trash(trash_count, pending_deletion, oldest_trash_date, trash_size) }} + {{ trash_type(trash_by_type) }}
{% endblock %} diff --git a/templates/macros.html b/templates/macros.html new file mode 100644 index 0000000..8014364 --- /dev/null +++ b/templates/macros.html @@ -0,0 +1,11 @@ +{% macro format_size(size) %} + {% if size < 1024 %} + {{ size }} B + {% elif size < 1024 * 1024 %} + {{ (size / 1024)|round(1) }} KB + {% elif size < 1024 * 1024 * 1024 %} + {{ (size / (1024 * 1024))|round(1) }} MB + {% else %} + {{ (size / (1024 * 1024 * 1024))|round(1) }} GB + {% endif %} +{% endmacro %} \ No newline at end of file