Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merging main into dev – Bringing All Updates Forward #80

Merged
merged 16 commits into from
Feb 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion Database/admindatahandler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from datetime import datetime
import re

from flask import session

from Database import DatabaseConfig

beehive_admin_collection = DatabaseConfig.get_beehive_admin_collection()
Expand All @@ -22,4 +24,14 @@ def check_admin_available(google_id: str):
}

count = beehive_admin_collection.count_documents(query)
return count == 0
return count == 0

def is_admin():
if 'google_id' in session:
query = {
"google_id": session['google_id']
}
admin = beehive_admin_collection.find_one(query)
if admin and admin.get("role") == "admin":
return True
return False
14 changes: 14 additions & 0 deletions Database/userdatahandler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from datetime import datetime, timedelta
import re

from flask import session

from Database import DatabaseConfig


Expand Down Expand Up @@ -92,6 +94,18 @@ def getallusers():
users = beehive_user_collection.find()
return users

def get_currentuser_from_session():
user_data = session.get('user')
if user_data is None:
return None

user_id = user_data.get('user_id')
if not user_id:
return None

user = beehive_user_collection.find_one({'_id': user_id})
return user

# Get all images from MongoDB
def get_images_by_user(username):
images = beehive_image_collection.find({'username': username})
Expand Down
51 changes: 43 additions & 8 deletions app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import base64
from functools import wraps
import json
import os
import datetime
Expand All @@ -19,10 +20,11 @@
from PIL import Image


from Database.admindatahandler import check_admin_available, create_admin
from Database.admindatahandler import check_admin_available, create_admin, is_admin
from Database.userdatahandler import (
create_user,
delete_image,
delete_image,
get_currentuser_from_session,
get_image_by_id,
get_images_by_user,
get_password_by_username,
Expand Down Expand Up @@ -68,6 +70,32 @@ def wrapper(*args, **kwargs):

return wrapper

def role_required(required_role):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):

if "google_id" in session:
if required_role == 'admin' and not is_admin():
return render_template('403.html')

elif "username" in session:
user = get_currentuser_from_session()

if user is None:
print("User not found in session!")
return render_template('403.html')

if user.get('role') != required_role:
return render_template('403.html')

else:
return render_template('403.html')

return func(*args, **kwargs)

return wrapper
return decorator

# Home page
@app.route('/')
Expand Down Expand Up @@ -179,11 +207,11 @@ def upload_image():

if filename.lower().endswith('.pdf'):
thumbnail_path = generate_pdf_thumbnail(filepath, filename)
return redirect(url_for('profile'))


else:
flash('Invalid file type. Allowed types are: jpg, jpeg, png, gif, webp, heif, pdf', 'danger')
return redirect(url_for('profile'))

return redirect(url_for('profile'))

def generate_pdf_thumbnail(pdf_path, filename):
"""Generate an image from the first page of a PDF using PyMuPDF."""
Expand Down Expand Up @@ -324,31 +352,38 @@ def authorize():
json.dump(session, json_file, indent=4)
return redirect("/admin")
else:
return render_template("404.html")
return render_template("403.html")



@app.route("/admin")
# @login_is_required
@role_required("admin")
@login_is_required
def protected_area():
admin_name = session.get("name")
total_img = total_images()
todays_image = todays_images()
return render_template("admin.html", admin_name=admin_name, total_img=total_img, todays_image = todays_image)


@login_is_required
@role_required("admin")
@app.route("/admin/logout")
def adminlogout():
session.clear()
return redirect("/")



@app.route('/admin/users')
@role_required("admin")
def getallusers():
users = userdatahandler.getallusers()
return render_template('users.html', users=users)



@app.route('/admin/users/<username>')
@role_required("admin")
def user_images_show(username):
user = get_user_by_username(username)
if not user:
Expand Down
Binary file modified requirements.txt
Binary file not shown.
4 changes: 0 additions & 4 deletions static/css/profile.css
Original file line number Diff line number Diff line change
Expand Up @@ -497,8 +497,6 @@ h2{
stroke: black;
stroke-width: 2px;
fill: transparent;
rx: 1em;
ry: 1em;
stroke-dasharray: 25;
transition: fill 0.25s, stroke 0.3s ease;
animation: 4s linear infinite stroke-animation;
Expand Down Expand Up @@ -584,8 +582,6 @@ h2{
stroke: #0055d4;
stroke-width: 2px;
fill: none;
rx: 1em;
ry: 1em;
stroke-dasharray: 0 100;
}

Expand Down
24 changes: 24 additions & 0 deletions static/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,28 @@ button:disabled {
color: #ff0400;
}

@media (max-width: 480px) {
.container {
margin-top: 90px;
max-width: 80%;
padding: 15px;
}

h2 {
font-size: 30px;
}

input {
font-size: 14px;
padding: 8px;
}

button {
font-size: 14px;
padding: 10px;
}

p {
font-size: 15px;
}
}
67 changes: 67 additions & 0 deletions static/js/dragdrop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
document.addEventListener('DOMContentLoaded', function() {
const fileInput = document.querySelector('input[type="file"]');
const uploadButton = document.getElementById('uploadButton');
const fileError = document.getElementById('fileError');
const allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'heif', 'pdf'];

//Validating dropped file
function validateFile(file) {
const fileExtension = file.name.split('.').pop().toLowerCase();
if (!allowedTypes.includes(fileExtension)) {
uploadButton.disabled = true;
fileError.style.display = 'block';
fileInput.value = ''; // Clear the file input
return false;
}
uploadButton.disabled = false;
fileError.style.display = 'none';
return true;
}

// Prevent default drag behaviors
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
document.addEventListener(eventName, preventDefaults, false);
});

function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}

// Changing the Opacity for better visual
['dragenter', 'dragover'].forEach(eventName => {
document.addEventListener(eventName, highlight, false);
});

['dragleave', 'drop'].forEach(eventName => {
document.addEventListener(eventName, unhighlight, false);
});

function highlight(e) {
document.body.style.opacity = '0.7';
document.body.style.transition = 'opacity 0.2s ease';
}

function unhighlight(e) {
document.body.style.opacity = '1';
}

document.addEventListener('drop', function(e) {
const dt = e.dataTransfer;
const files = dt.files;

if (files.length > 0) {
const file = files[0];
if (validateFile(file)) {
// Update the file input with the dropped file
fileInput.files = files;

// Show upload form if hidden
const uploadForm = document.getElementById('uploadForm');
if (uploadForm.style.display === 'none' || uploadForm.style.display === '') {
uploadForm.style.display = 'block';
}
}
}
});
});
18 changes: 18 additions & 0 deletions templates/403.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Beehive</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/index.css') }}">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">

</head>
<body>
<i class="material-icons" style="font-size:100px;">admin_panel_settings</i>


<h2>You don't have permission to access this page. Only admins are allowed due to privacy restrictions.</h2>
<a href="{{ url_for('home') }}"><button>Go Home</button></a>
</body>
</html>
14 changes: 0 additions & 14 deletions templates/404.html

This file was deleted.

1 change: 0 additions & 1 deletion templates/admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ <h1>{{ admin_name }}<span class="badge">Admin</span></h1>
<button class="view-users"><a href="{{ url_for('getallusers') }}">View Users</a></button>
<button class="logout-button"><a href="{{ url_for('adminlogout') }}">Logout</a></button>
</div>

<div class="card-container">
<div class="card">
<h3>Total Images</h3>
Expand Down
7 changes: 4 additions & 3 deletions templates/profile.html
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@
}

</script>
<script src="{{ url_for('static', filename='js/dragdrop.js') }}"></script>
</head>
<body>
<div class="nav">
Expand All @@ -211,7 +212,7 @@ <h1>{{ username }}</h1>
{% endwith %}

<div class="button-container">
<button class="toggle" onclick="toggleUploadForm()">Upload Images</button>
<button class="toggle" onclick="toggleUploadForm()">Click to Upload or Drag & Drop Anywhere</button>
<button class="logout-button"><a href="{{ url_for('logout') }}">Logout</a></button>
</div>

Expand All @@ -230,8 +231,8 @@ <h1>{{ username }}</h1>
<input type="hidden" name="audioData" id="audioData">
<button class="uploadButton" id="uploadButton" type="submit" onclick="handleUpload(event)">
<svg xmlns="http://www.w3.org/2000/svg">
<rect class="border" pathLength="100"></rect>
<rect class="loading" pathLength="100"></rect>
<rect class="border" pathLength="100" rx="10" ry="10"></rect>
<rect class="loading" pathLength="100" rx="10" ry="10"></rect>
</svg>
<div class="txt-upload">Upload</div>
</button>
Expand Down