Initial commit
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-shield-lock"></i> Admin Panel</h2>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-file-earmark-text"></i> Document Statistics</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Total Documents
|
||||
<span class="badge bg-primary rounded-pill">{{ doc_stats.total_documents }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Total Storage Used
|
||||
<span class="badge bg-info rounded-pill">{{ (doc_stats.total_size / (1024*1024))|round(2) }} MB</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Active Contributors
|
||||
<span class="badge bg-success rounded-pill">{{ doc_stats.total_contributors }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-activity"></i> Activity Statistics</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Total Actions
|
||||
<span class="badge bg-primary rounded-pill">{{ activity_stats.total_actions }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Active Users
|
||||
<span class="badge bg-info rounded-pill">{{ activity_stats.active_users }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Accessed Documents
|
||||
<span class="badge bg-success rounded-pill">{{ activity_stats.accessed_documents }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-warning text-dark">
|
||||
<h5 class="mb-0"><i class="bi bi-gear"></i> System Actions</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-outline-primary">
|
||||
<i class="bi bi-arrow-repeat"></i> Rebuild Search Index
|
||||
</button>
|
||||
<button class="btn btn-outline-warning">
|
||||
<i class="bi bi-trash"></i> Clear Expired Shares
|
||||
</button>
|
||||
<button class="btn btn-outline-danger">
|
||||
<i class="bi bi-exclamation-triangle"></i> System Maintenance
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-people"></i> User Management</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th>Role</th>
|
||||
<th>Created</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{ user.id }}</td>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.email }}</td>
|
||||
<td>
|
||||
<span class="badge bg-{{ 'danger' if user.role == 'admin' else 'primary' }}">
|
||||
{{ user.role }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ user.created_at.split(' ')[0] }}</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button class="btn btn-outline-primary">
|
||||
<i class="bi bi-pencil"></i> Edit
|
||||
</button>
|
||||
<button class="btn btn-outline-danger" {% if user.role == 'admin' %}disabled{% endif %}>
|
||||
<i class="bi bi-trash"></i> Delete
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,194 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-speedometer2"></i> Dashboard</h2>
|
||||
|
||||
<div class="row">
|
||||
<!-- Category Summary -->
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-folder"></i> Document Categories</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if category_counts %}
|
||||
<div class="row">
|
||||
{% for category in category_counts %}
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="mb-0">{{ category.category|capitalize }}</h6>
|
||||
<small class="text-muted">{{ category.count }} document{% if category.count != 1 %}s{% endif %}</small>
|
||||
</div>
|
||||
<a href="{{ url_for('files', category=category.category) }}" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-arrow-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i> No documents found. Upload your first document to get started!
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="text-center mt-3">
|
||||
<a href="{{ url_for('files') }}" class="btn btn-primary">
|
||||
<i class="bi bi-table"></i> View All Documents
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-lightning"></i> Quick Actions</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-6 mb-3">
|
||||
<a href="{{ url_for('upload') }}" class="btn btn-outline-success w-100 h-100 d-flex flex-column justify-content-center align-items-center p-4">
|
||||
<i class="bi bi-upload fs-2 mb-2"></i>
|
||||
<span>Upload Document</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-6 mb-3">
|
||||
<a href="{{ url_for('files') }}" class="btn btn-outline-primary w-100 h-100 d-flex flex-column justify-content-center align-items-center p-4">
|
||||
<i class="bi bi-table fs-2 mb-2"></i>
|
||||
<span>View Files</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-6 mb-3">
|
||||
<a href="{{ url_for('files', category='admin') }}" class="btn btn-outline-secondary w-100 h-100 d-flex flex-column justify-content-center align-items-center p-4">
|
||||
<i class="bi bi-briefcase fs-2 mb-2"></i>
|
||||
<span>Admin Files</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-6 mb-3">
|
||||
<a href="{{ url_for('files', category='accounting') }}" class="btn btn-outline-info w-100 h-100 d-flex flex-column justify-content-center align-items-center p-4">
|
||||
<i class="bi bi-calculator fs-2 mb-2"></i>
|
||||
<span>Accounting Files</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Recent Documents -->
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-clock-history"></i> Recent Documents</h5>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
{% if recent_documents %}
|
||||
<div class="list-group list-group-flush">
|
||||
{% for doc in recent_documents %}
|
||||
<a href="{{ url_for('view_document', document_id=doc.id) }}" class="list-group-item list-group-item-action">
|
||||
<div class="d-flex w-100 justify-content-between align-items-center">
|
||||
<div>
|
||||
<div class="d-flex align-items-center">
|
||||
{% if doc.file_type == 'pdf' %}
|
||||
<i class="bi bi-file-earmark-pdf text-danger me-2"></i>
|
||||
{% elif doc.file_type == 'document' %}
|
||||
<i class="bi bi-file-earmark-word text-primary me-2"></i>
|
||||
{% elif doc.file_type == 'spreadsheet' %}
|
||||
<i class="bi bi-file-earmark-excel text-success me-2"></i>
|
||||
{% elif doc.file_type == 'image' %}
|
||||
<i class="bi bi-file-earmark-image text-info me-2"></i>
|
||||
{% elif doc.file_type == 'video' %}
|
||||
<i class="bi bi-file-earmark-play text-warning me-2"></i>
|
||||
{% else %}
|
||||
<i class="bi bi-file-earmark text-secondary me-2"></i>
|
||||
{% endif %}
|
||||
<h6 class="mb-0">{{ doc.custom_filename }}</h6>
|
||||
</div>
|
||||
<small class="text-muted">
|
||||
<span class="badge bg-secondary">{{ doc.category|capitalize }}</span>
|
||||
{{ (doc.file_size / 1024)|round(1) }} KB
|
||||
</small>
|
||||
</div>
|
||||
<small class="text-muted">{{ doc.created_at.split(' ')[0] }}</small>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info m-3">
|
||||
<i class="bi bi-info-circle"></i> No documents found. Upload your first document to get started!
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if recent_documents %}
|
||||
<div class="card-footer text-center">
|
||||
<a href="{{ url_for('files') }}" class="btn btn-sm btn-outline-info">View All Documents</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Analytics (Admin Only) -->
|
||||
{% if session.role == 'admin' and analytics %}
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header bg-warning text-dark">
|
||||
<h5 class="mb-0"><i class="bi bi-graph-up"></i> Analytics Overview</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6>Most Viewed Documents</h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Document</th>
|
||||
<th>Views</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for doc in analytics %}
|
||||
<tr>
|
||||
<td>{{ doc.custom_filename }}</td>
|
||||
<td>{{ doc.view_count }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if user_activity %}
|
||||
<h6 class="mt-4">Most Active Users</h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in user_activity %}
|
||||
<tr>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.action_count }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,77 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-pencil-square"></i> Edit Document</h2>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">Edit Document Details</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ url_for('edit_document', document_id=document.id) }}">
|
||||
<div class="mb-3">
|
||||
<label for="custom_filename" class="form-label">Document Name</label>
|
||||
<input type="text" class="form-control" id="custom_filename" name="custom_filename"
|
||||
value="{{ document.custom_filename }}" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="category" class="form-label">Category</label>
|
||||
<select class="form-select" id="category" name="category" required>
|
||||
{% for category in categories %}
|
||||
<option value="{{ category }}" {% if category == document.category %}selected{% endif %}>
|
||||
{{ category|capitalize }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Visibility</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="visibility" id="private" value="private"
|
||||
{% if document.visibility == 'private' %}checked{% endif %}>
|
||||
<label class="form-check-label" for="private">
|
||||
<i class="bi bi-lock"></i> Private (Only you can access)
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="visibility" id="public" value="public"
|
||||
{% if document.visibility == 'public' %}checked{% endif %}>
|
||||
<label class="form-check-label" for="public">
|
||||
<i class="bi bi-globe"></i> Public (Anyone can access)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<a href="{{ url_for('view_document', document_id=document.id) }}" class="btn btn-secondary">
|
||||
<i class="bi bi-x-circle"></i> Cancel
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-save"></i> Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-info-circle"></i> Document Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Original Filename:</strong> {{ document.original_filename }}</p>
|
||||
<p><strong>File Type:</strong> {{ document.file_type|capitalize }}</p>
|
||||
<p><strong>File Size:</strong> {{ (document.file_size / 1024)|round(1) }} KB</p>
|
||||
<p><strong>Uploaded:</strong> {{ document.created_at.split(' ')[0] }}</p>
|
||||
<p><strong>Last Modified:</strong> {{ document.updated_at.split(' ')[0] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document Management System - Error</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{{ url_for('index') }}">
|
||||
<i class="bi bi-folder2-open"></i> DMS
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container mt-5 pt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8 text-center">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h1 class="display-1 text-danger">{{ error_code }}</h1>
|
||||
<h2 class="mb-4">{{ error_message }}</h2>
|
||||
<p class="lead">Sorry, something went wrong.</p>
|
||||
<a href="{{ url_for('index') }}" class="btn btn-primary mt-3">
|
||||
<i class="bi bi-house"></i> Return to Home
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="bg-dark text-white py-4 mt-5">
|
||||
<div class="container text-center">
|
||||
<p>Document Management System</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="{{ url_for('static', filename='scripts.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,145 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<h2><i class="bi bi-table"></i> Files</h2>
|
||||
</div>
|
||||
<div class="col-md-6 text-end">
|
||||
<a href="{{ url_for('upload') }}" class="btn btn-success">
|
||||
<i class="bi bi-upload"></i> Upload New Document
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0"><i class="bi bi-file-earmark"></i> Document Library</h5>
|
||||
<form class="d-flex" action="{{ url_for('files') }}" method="get">
|
||||
<select name="category" class="form-select form-select-sm me-2" style="width: 150px;" onchange="this.form.submit()">
|
||||
<option value="all" {% if selected_category == 'all' %}selected{% endif %}>All Categories</option>
|
||||
{% for category in categories %}
|
||||
<option value="{{ category }}" {% if selected_category == category %}selected{% endif %}>
|
||||
{{ category|capitalize }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control form-control-sm" placeholder="Search files..." name="search" value="{{ search_query }}">
|
||||
<button class="btn btn-outline-light btn-sm" type="submit">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Category</th>
|
||||
<th>Type</th>
|
||||
<th>Size</th>
|
||||
<th>Uploaded</th>
|
||||
<th>Visibility</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if documents %}
|
||||
{% for doc in documents %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
{% if doc.file_type == 'pdf' %}
|
||||
<i class="bi bi-file-earmark-pdf text-danger me-2"></i>
|
||||
{% elif doc.file_type == 'document' %}
|
||||
<i class="bi bi-file-earmark-word text-primary me-2"></i>
|
||||
{% elif doc.file_type == 'spreadsheet' %}
|
||||
<i class="bi bi-file-earmark-excel text-success me-2"></i>
|
||||
{% elif doc.file_type == 'image' %}
|
||||
<i class="bi bi-file-earmark-image text-info me-2"></i>
|
||||
{% elif doc.file_type == 'video' %}
|
||||
<i class="bi bi-file-earmark-play text-warning me-2"></i>
|
||||
{% else %}
|
||||
<i class="bi bi-file-earmark text-secondary me-2"></i>
|
||||
{% endif %}
|
||||
<span>{{ doc.custom_filename }}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td><span class="badge bg-secondary">{{ doc.category|capitalize }}</span></td>
|
||||
<td>{{ doc.file_type|capitalize }}</td>
|
||||
<td>{{ (doc.file_size / 1024)|round(1) }} KB</td>
|
||||
<td>{{ doc.created_at.split(' ')[0] }}</td>
|
||||
<td>
|
||||
{% if doc.visibility == 'public' %}
|
||||
<span class="badge bg-success">Public</span>
|
||||
{% else %}
|
||||
<span class="badge bg-warning text-dark">Private</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a href="{{ url_for('view_document', document_id=doc.id) }}" class="btn btn-outline-primary" title="View">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
<a href="{{ url_for('edit_document', document_id=doc.id) }}" class="btn btn-outline-secondary" title="Edit">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<a href="{{ url_for('share_document', document_id=doc.id) }}" class="btn btn-outline-info" title="Share">
|
||||
<i class="bi bi-share"></i>
|
||||
</a>
|
||||
<a href="{{ url_for('download_document', document_id=doc.id) }}" class="btn btn-outline-success" title="Download">
|
||||
<i class="bi bi-download"></i>
|
||||
</a>
|
||||
<a href="{{ url_for('delete_document', document_id=doc.id) }}" class="btn btn-outline-danger"
|
||||
onclick="return confirm('Are you sure you want to delete this document?')" title="Delete">
|
||||
<i class="bi bi-trash"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="7" class="text-center py-4">
|
||||
<div class="alert alert-info mb-0">
|
||||
<i class="bi bi-info-circle"></i>
|
||||
{% if search_query %}
|
||||
No documents found matching your search criteria.
|
||||
{% elif selected_category != 'all' %}
|
||||
No documents found in the selected category.
|
||||
{% else %}
|
||||
No documents found. Upload your first document to get started!
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if pagination and pagination.pages > 1 %}
|
||||
<nav aria-label="Document pagination">
|
||||
<ul class="pagination justify-content-center">
|
||||
<li class="page-item {% if pagination.page == 1 %}disabled{% endif %}">
|
||||
<a class="page-link" href="{{ url_for('files', page=pagination.page-1, search=search_query, category=selected_category) }}">Previous</a>
|
||||
</li>
|
||||
|
||||
{% for p in range(1, pagination.pages + 1) %}
|
||||
<li class="page-item {% if pagination.page == p %}active{% endif %}">
|
||||
<a class="page-link" href="{{ url_for('files', page=p, search=search_query, category=selected_category) }}">{{ p }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
<li class="page-item {% if pagination.page == pagination.pages %}disabled{% endif %}">
|
||||
<a class="page-link" href="{{ url_for('files', page=pagination.page+1, search=search_query, category=selected_category) }}">Next</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,17 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8 text-center">
|
||||
<div class="card mt-5">
|
||||
<div class="card-body">
|
||||
<h1 class="display-4 mb-4">Document Management System</h1>
|
||||
<p class="lead">A secure platform for managing, sharing, and collaborating on documents.</p>
|
||||
<hr class="my-4">
|
||||
<p>Please login to access your documents and start managing your files.</p>
|
||||
<a href="{{ url_for('login') }}" class="btn btn-primary btn-lg">Login</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,92 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document Management System</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{{ url_for('index') }}">
|
||||
<i class="bi bi-folder2-open"></i> DMS
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
{% if session.user_id %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('dashboard') }}">Dashboard</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('files') }}">Files</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('upload') }}">Upload</a>
|
||||
</li>
|
||||
{% if session.role == 'admin' %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('admin_panel') }}">Admin</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
{% if session.user_id %}
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="userDropdown" role="button" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-person-circle"></i> {{ session.username }}
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="{{ url_for('logout') }}">Logout</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ url_for('login') }}">Login</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Flash Messages -->
|
||||
<div class="flash-messages">
|
||||
{% for category, message in get_flashed_messages(with_categories=true) %}
|
||||
{% set alert_class = 'alert-info' %}
|
||||
{% if category == 'success' %}
|
||||
{% set alert_class = 'alert-success' %}
|
||||
{% elif category == 'error' %}
|
||||
{% set alert_class = 'alert-danger' %}
|
||||
{% endif %}
|
||||
<div class="alert {{ alert_class }} alert-dismissible fade show">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container mt-4">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="bg-dark text-white py-4 mt-5">
|
||||
<div class="container text-center">
|
||||
<p>Document Management System</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="{{ url_for('static', filename='scripts.js') }}"></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card mt-5">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h4 class="mb-0"><i class="bi bi-person"></i> Login</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ url_for('login') }}">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username</label>
|
||||
<input type="text" class="form-control" id="username" name="username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">Login</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-3 text-center">
|
||||
<!-- <p class="text-muted">Demo Accounts:</p>
|
||||
<p><small>Admin: username: <strong>admin</strong>, password: <strong>admin123</strong></small></p>
|
||||
<p><small>User: username: <strong>user</strong>, password: <strong>user123</strong></small></p> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,163 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-8">
|
||||
<h2><i class="bi bi-share"></i> Share Document: {{ document.original_filename }}</h2>
|
||||
</div>
|
||||
<div class="col-md-4 text-end">
|
||||
<a href="{{ url_for('view_document', document_id=document.id) }}" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left"></i> Back to Document
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-person-plus"></i> Share with User</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ url_for('share_document', document_id=document.id) }}">
|
||||
<input type="hidden" name="share_type" value="user">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username</label>
|
||||
<select class="form-select" id="username" name="username" required>
|
||||
<option value="" selected disabled>Select a user</option>
|
||||
{% for user in users %}
|
||||
<option value="{{ user.username }}">{{ user.username }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-share"></i> Share with User
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-link"></i> Create Shareable Link</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ url_for('share_document', document_id=document.id) }}">
|
||||
<input type="hidden" name="share_type" value="link">
|
||||
<div class="mb-3">
|
||||
<label for="expiry" class="form-label">Link Expiry</label>
|
||||
<select class="form-select" id="expiry" name="expiry">
|
||||
<option value="1">1 day</option>
|
||||
<option value="7" selected>7 days</option>
|
||||
<option value="30">30 days</option>
|
||||
<option value="90">90 days</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-info">
|
||||
<i class="bi bi-link"></i> Generate Link
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-people"></i> Current Shares</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if shares %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Shared With</th>
|
||||
<th>Date Shared</th>
|
||||
<th>Expiry</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for share in shares %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if share.shared_with %}
|
||||
<span class="badge bg-primary"><i class="bi bi-person"></i> User</span>
|
||||
{% elif share.share_link %}
|
||||
<span class="badge bg-info"><i class="bi bi-link"></i> Link</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if share.shared_with %}
|
||||
{{ share.username }}
|
||||
{% elif share.share_link %}
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control form-control-sm" value="{{ request.host_url }}shared/{{ share.share_link }}" readonly id="link-{{ share.id }}">
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="copyLink('link-{{ share.id }}')">
|
||||
<i class="bi bi-clipboard"></i>
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ share.created_at.split(' ')[0] }}</td>
|
||||
<td>
|
||||
{% if share.expires_at %}
|
||||
{{ share.expires_at.split(' ')[0] }}
|
||||
{% else %}
|
||||
Never
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="btn btn-sm btn-danger">
|
||||
<i class="bi bi-x-circle"></i> Revoke
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i> This document hasn't been shared yet.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
function copyLink(elementId) {
|
||||
var copyText = document.getElementById(elementId);
|
||||
copyText.select();
|
||||
copyText.setSelectionRange(0, 99999);
|
||||
navigator.clipboard.writeText(copyText.value);
|
||||
|
||||
// Show a temporary tooltip
|
||||
var tooltip = document.createElement("div");
|
||||
tooltip.innerHTML = "Copied!";
|
||||
tooltip.style.position = "fixed";
|
||||
tooltip.style.backgroundColor = "#4CAF50";
|
||||
tooltip.style.color = "white";
|
||||
tooltip.style.padding = "5px 10px";
|
||||
tooltip.style.borderRadius = "5px";
|
||||
tooltip.style.zIndex = "1000";
|
||||
tooltip.style.top = (event.clientY - 30) + "px";
|
||||
tooltip.style.left = event.clientX + "px";
|
||||
document.body.appendChild(tooltip);
|
||||
|
||||
setTimeout(function() {
|
||||
document.body.removeChild(tooltip);
|
||||
}, 2000);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,140 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-12">
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i> You are viewing a shared document.
|
||||
{% if not session.user_id %}
|
||||
<a href="{{ url_for('login') }}" class="alert-link">Login</a> to access more features.
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-file-earmark"></i> {{ document.original_filename }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="document-viewer">
|
||||
{% if document.file_type == 'pdf' %}
|
||||
<div class="ratio ratio-16x9">
|
||||
<iframe src="{{ url_for('download_shared', share_token=share_token) }}" allowfullscreen></iframe>
|
||||
</div>
|
||||
{% elif document.file_type == 'image' %}
|
||||
<img src="{{ url_for('download_shared', share_token=share_token) }}" class="img-fluid" alt="{{ document.original_filename }}">
|
||||
{% elif document.file_type == 'video' %}
|
||||
<div class="ratio ratio-16x9">
|
||||
<video controls>
|
||||
<source src="{{ url_for('download_shared', share_token=share_token) }}" type="video/mp4">
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i> Preview not available for this file type. Please download the file to view its contents.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="{{ url_for('download_shared', share_token=share_token) }}" class="btn btn-primary">
|
||||
<i class="bi bi-download"></i> Download
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-secondary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-info-circle"></i> Document Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
File Type
|
||||
<span class="badge bg-primary rounded-pill">{{ document.file_type }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Size
|
||||
<span class="badge bg-secondary rounded-pill">{{ (document.file_size / 1024)|round(1) }} KB</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Uploaded
|
||||
<span class="badge bg-info rounded-pill">{{ document.created_at.split(' ')[0] }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-share"></i> Sharing Options</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>This document has been shared with you via a secure link.</p>
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" class="form-control" value="{{ request.url }}" readonly id="share-link">
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="copyLink('share-link')">
|
||||
<i class="bi bi-clipboard"></i> Copy
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-outline-primary" onclick="shareViaEmail()">
|
||||
<i class="bi bi-envelope"></i> Share via Email
|
||||
</button>
|
||||
<button class="btn btn-outline-success" onclick="shareViaWhatsApp()">
|
||||
<i class="bi bi-whatsapp"></i> Share via WhatsApp
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
function copyLink(elementId) {
|
||||
var copyText = document.getElementById(elementId);
|
||||
copyText.select();
|
||||
copyText.setSelectionRange(0, 99999);
|
||||
navigator.clipboard.writeText(copyText.value);
|
||||
|
||||
// Show a temporary tooltip
|
||||
var tooltip = document.createElement("div");
|
||||
tooltip.innerHTML = "Copied!";
|
||||
tooltip.style.position = "fixed";
|
||||
tooltip.style.backgroundColor = "#4CAF50";
|
||||
tooltip.style.color = "white";
|
||||
tooltip.style.padding = "5px 10px";
|
||||
tooltip.style.borderRadius = "5px";
|
||||
tooltip.style.zIndex = "1000";
|
||||
tooltip.style.top = (event.clientY - 30) + "px";
|
||||
tooltip.style.left = event.clientX + "px";
|
||||
document.body.appendChild(tooltip);
|
||||
|
||||
setTimeout(function() {
|
||||
document.body.removeChild(tooltip);
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function shareViaEmail() {
|
||||
var subject = "Shared Document: {{ document.original_filename }}";
|
||||
var body = "I'm sharing a document with you: {{ document.original_filename }}\\n\\nYou can access it here: " + window.location.href;
|
||||
window.location.href = "mailto:?subject=" + encodeURIComponent(subject) + "&body=" + encodeURIComponent(body);
|
||||
}
|
||||
|
||||
function shareViaWhatsApp() {
|
||||
var text = "I'm sharing a document with you: {{ document.original_filename }}\\n\\nYou can access it here: " + window.location.href;
|
||||
window.open("https://wa.me/?text=" + encodeURIComponent(text), "_blank");
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,98 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<h2 class="mb-4"><i class="bi bi-upload"></i> Upload Document</h2>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0">Upload New Document</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{{ url_for('upload') }}" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label for="file" class="form-label">Select File</label>
|
||||
<input type="file" class="form-control" id="file" name="file" required>
|
||||
<div class="form-text">
|
||||
Allowed file types: PDF, DOCX, XLSX, JPG, PNG, MP4, TXT
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="custom_filename" class="form-label">Custom File Name (Optional)</label>
|
||||
<input type="text" class="form-control" id="custom_filename" name="custom_filename" placeholder="Enter a custom name for this file">
|
||||
<div class="form-text">
|
||||
If left blank, the original filename will be used
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="category" class="form-label">Category</label>
|
||||
<select class="form-select" id="category" name="category" required>
|
||||
{% for category in categories %}
|
||||
<option value="{{ category }}" {% if category == 'general' %}selected{% endif %}>
|
||||
{{ category|capitalize }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Visibility</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="visibility" id="private" value="private" checked>
|
||||
<label class="form-check-label" for="private">
|
||||
<i class="bi bi-lock"></i> Private (Only you can access)
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="visibility" id="public" value="public">
|
||||
<label class="form-check-label" for="public">
|
||||
<i class="bi bi-globe"></i> Public (Anyone can access)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-upload"></i> Upload Document
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-info-circle"></i> Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h6>File Size Limits</h6>
|
||||
<p>Maximum file size: 16MB</p>
|
||||
|
||||
<h6>Supported File Types</h6>
|
||||
<ul>
|
||||
<li>Documents: PDF, DOCX, TXT</li>
|
||||
<li>Spreadsheets: XLSX</li>
|
||||
<li>Images: JPG, PNG</li>
|
||||
<li>Videos: MP4</li>
|
||||
</ul>
|
||||
|
||||
<h6>Categories</h6>
|
||||
<ul>
|
||||
<li><strong>Admin:</strong> Administrative documents</li>
|
||||
<li><strong>Accounting:</strong> Financial documents</li>
|
||||
<li><strong>HR:</strong> Human resources documents</li>
|
||||
<li><strong>Marketing:</strong> Marketing materials</li>
|
||||
<li><strong>Legal:</strong> Legal documents</li>
|
||||
<li><strong>General:</strong> General purpose documents</li>
|
||||
<li><strong>Other:</strong> Miscellaneous documents</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,160 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-8">
|
||||
<h2><i class="bi bi-file-earmark"></i> {{ document.original_filename }}</h2>
|
||||
</div>
|
||||
<div class="col-md-4 text-end">
|
||||
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left"></i> Back to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-eye"></i> Document Viewer</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="document-viewer">
|
||||
{% if document.file_type == 'pdf' %}
|
||||
<div class="ratio ratio-16x9">
|
||||
<iframe src="{{ url_for('serve_document_file', document_id=document.id) }}" allowfullscreen></iframe>
|
||||
</div>
|
||||
{% elif document.file_type == 'image' %}
|
||||
<img src="{{ url_for('download_document', document_id=document.id) }}" class="img-fluid" alt="{{ document.original_filename }}">
|
||||
{% elif document.file_type == 'video' %}
|
||||
<div class="ratio ratio-16x9">
|
||||
<video controls>
|
||||
<source src="{{ url_for('download_document', document_id=document.id) }}" type="video/mp4">
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle"></i> Preview not available for this file type. Please download the file to view its contents.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<a href="{{ url_for('download_document', document_id=document.id) }}" class="btn btn-primary">
|
||||
<i class="bi bi-download"></i> Download
|
||||
</a>
|
||||
<a href="{{ url_for('share_document', document_id=document.id) }}" class="btn btn-info">
|
||||
<i class="bi bi-share"></i> Share
|
||||
</a>
|
||||
{% if document.user_id == session.user_id or session.role == 'admin' %}
|
||||
<a href="{{ url_for('delete_document', document_id=document.id) }}" class="btn btn-danger"
|
||||
onclick="return confirm('Are you sure you want to delete this document?')">
|
||||
<i class="bi bi-trash"></i> Delete
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-clock-history"></i> Version History</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Version</th>
|
||||
<th>Date</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for version in versions %}
|
||||
<tr>
|
||||
<td>v{{ version.version_number }}</td>
|
||||
<td>{{ version.created_at }}</td>
|
||||
<td>
|
||||
<a href="#" class="btn btn-sm btn-primary">
|
||||
<i class="bi bi-download"></i> Download
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-secondary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-info-circle"></i> Document Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
File Type
|
||||
<span class="badge bg-primary rounded-pill">{{ document.file_type }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Size
|
||||
<span class="badge bg-secondary rounded-pill">{{ (document.file_size / 1024)|round(1) }} KB</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Uploaded
|
||||
<span class="badge bg-info rounded-pill">{{ document.created_at.split(' ')[0] }}</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Visibility
|
||||
<span class="badge bg-{{ 'success' if document.visibility == 'public' else 'warning' }} rounded-pill">
|
||||
{{ document.visibility }}
|
||||
</span>
|
||||
</li>
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
Versions
|
||||
<span class="badge bg-dark rounded-pill">{{ versions|length }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-share"></i> Sharing Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if shares %}
|
||||
<h6>Shared With</h6>
|
||||
<ul class="list-group list-group-flush mb-3">
|
||||
{% for share in shares %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
{% if share.shared_with %}
|
||||
<span><i class="bi bi-person"></i> {{ share.username }}</span>
|
||||
{% elif share.share_link %}
|
||||
<span><i class="bi bi-link"></i> Via Link</span>
|
||||
<small class="text-muted">
|
||||
{% if share.expires_at %}
|
||||
Expires: {{ share.expires_at.split(' ')[0] }}
|
||||
{% endif %}
|
||||
</small>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% else %}
|
||||
<p>This document hasn't been shared yet.</p>
|
||||
{% endif %}
|
||||
|
||||
<a href="{{ url_for('share_document', document_id=document.id) }}" class="btn btn-success w-100">
|
||||
<i class="bi bi-share"></i> Manage Sharing
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user