From 884cc0e69407f9dd151c1644ec81889716eb01c7 Mon Sep 17 00:00:00 2001
From: Ethan-clay03 <ethanclay2017@gmail.com>
Date: Tue, 7 Jan 2025 18:09:34 +0000
Subject: [PATCH] Fix super admin being unable to access admin pages, begin to
 move admin to separate bp route and work on adding bookings via UI

---
 app/__init__.py                   | 29 +++++++++++---------
 app/bookings/routes.py            |  2 --
 app/logger/__init__.py            |  2 +-
 app/profile/routes.py             | 16 +++++++++--
 app/templates/admin/index.html    | 44 +++++++++++++++++++++++++++++++
 app/templates/admin/listings.html | 12 +++++++++
 app/templates/base.html           |  3 +++
 7 files changed, 91 insertions(+), 17 deletions(-)
 create mode 100644 app/templates/admin/index.html
 create mode 100644 app/templates/admin/listings.html

diff --git a/app/__init__.py b/app/__init__.py
index be141ad..7daa6ca 100644
--- a/app/__init__.py
+++ b/app/__init__.py
@@ -6,6 +6,7 @@ from flask_login import LoginManager, current_user
 from flask_principal import Principal, Permission, RoleNeed, identity_loaded
 from flask_wtf.csrf import CSRFProtect
 from dotenv import load_dotenv
+from app.logger import auth_logger
 from functools import wraps
 import os
 
@@ -21,7 +22,7 @@ def permission_required(permission):
         @wraps(f)
         def decorated_function(*args, **kwargs):
             if not permission.can():
-                current_app.logger.debug(f'Permission denied for {current_user} attempting to access {request.endpoint}.')
+                auth_logger.debug(f'Permission denied for {current_user} attempting to access {request.endpoint}.')
                 abort(403)
             return f(*args, **kwargs)
         return decorated_function
@@ -50,6 +51,7 @@ def create_app(config_class=Config):
     app.config['SECRET_KEY'] = os.getenv('SECRET_KEY') or 'your_secret_key'
     app.config['SQLALCHEMY_DATABASE_URI'] = f"mysql+pymysql://{db_user}:{db_password}@{db_host}/{db_name}"
 
+    # Initialize extensions with the app
     db.init_app(app)
     migrate.init_app(app, db)
     login_manager.init_app(app)
@@ -69,11 +71,10 @@ def create_app(config_class=Config):
             if user and user.role:
                 identity.provides.add(RoleNeed(user.role.name))
                 if user.role.name == 'super-admin':
-                    identity.provides.add(RoleNeed('admin'))
-                    identity.provides.add(RoleNeed('super-admin'))
+                    identity.provides.add(RoleNeed('admin'))  # Super admin should also inherit admin permissions
+                auth_logger.debug(f'Roles provided to identity for {current_user}: {identity.provides}')
             else:
-                current_app.logger.debug(f'No role found for user {identity.user.username}.')
-
+                auth_logger.debug(f'No role found for user {identity.user.username}.')
 
 
     # Add global template variables
@@ -102,27 +103,31 @@ def create_app(config_class=Config):
 
     @app.before_request
     def before_request():
-        g.admin_permission = admin_permission
-        g.user_permission = user_permission
-        g.super_admin_permission = super_admin_permission
+        g.admin_permission = None
+        g.user_permission = None
+        g.super_admin_permission = None
+        g.is_admin = False
+        g.is_super_admin = False
 
         if current_user.is_authenticated:
             role = current_user.role
             if role:
+                g.user_permission = user_permission
                 if role.name == 'super-admin':
                     g.super_admin_permission = super_admin_permission
                     g.admin_permission = admin_permission
-                    g.user_permission = user_permission
+                    g.is_super_admin = True
+                    g.is_admin = True
                 elif role.name == 'admin':
                     g.admin_permission = admin_permission
-                    g.user_permission = user_permission
-                elif role.name == 'user':
-                    g.user_permission = user_permission
+                    g.is_admin = True
+        auth_logger.debug(f'Permissions for {current_user}: Admin: {g.admin_permission}, User: {g.user_permission}, Super Admin: {g.super_admin_permission}')
 
     login_manager.login_view = 'profile.login'
     
     return app
 
+
 @login_manager.user_loader
 def load_user(user_id):
     from app.models import User
diff --git a/app/bookings/routes.py b/app/bookings/routes.py
index a340d57..998d5e7 100644
--- a/app/bookings/routes.py
+++ b/app/bookings/routes.py
@@ -1,10 +1,8 @@
 from flask import render_template, redirect, url_for, g
 from app.bookings import bp
 from app.models import Listings, ListingImages 
-from app import admin_permission, permission_required, user_permission, super_admin_permission
 
 @bp.route('/home')
-@permission_required(user_permission)
 def index():
     listing_ids = []
     top_listings = Listings.get_top_listings(5)
diff --git a/app/logger/__init__.py b/app/logger/__init__.py
index 31350b1..8c8e658 100644
--- a/app/logger/__init__.py
+++ b/app/logger/__init__.py
@@ -35,4 +35,4 @@ class LoggerConfig:
 logger_config = LoggerConfig()
 app_logger = logger_config.setup_logger('app', log_file='app.log', level=LOG_LEVELS['debug'])
 db_logger = logger_config.setup_logger('db', log_file='db.log', level=LOG_LEVELS['info'])
-auth_logger = logger_config.setup_logger('auth', log_file='auth.log', level=LOG_LEVELS['warning'])
+auth_logger = logger_config.setup_logger('auth', log_file='auth.log', level=LOG_LEVELS['debug'])
diff --git a/app/profile/routes.py b/app/profile/routes.py
index 4b04a1a..2678dcb 100644
--- a/app/profile/routes.py
+++ b/app/profile/routes.py
@@ -1,13 +1,14 @@
 #https://www.digitalocean.com/community/tutorials/how-to-add-authentication-to-your-app-with-flask-login#step-1-installing-packages
-from flask import render_template, redirect, url_for, request, flash, jsonify, session, current_app
+from flask import render_template, redirect, url_for, request, flash, jsonify, session, current_app, abort
 from flask_principal import Identity, identity_changed
 from flask_login import login_user, logout_user, login_required, current_user
 from werkzeug.security import check_password_hash
 from app.profile import bp
 from app.models import User
 from app.logger import auth_logger
+from app import admin_permission, permission_required, super_admin_permission
 from app import db
-
+from flask_principal import Principal, Permission, RoleNeed, identity_loaded
 
 @bp.route('/signup', methods=['GET', 'POST'])
 def signup():
@@ -86,6 +87,10 @@ def login_post():
 
     return redirect(url_for('profile.index'))
 
+@bp.route('/admin/index')
+@permission_required(admin_permission)
+def admin_index():
+    return render_template('profile/admin-index.html')
 
 
 @bp.route('/check-username', methods=['POST'])
@@ -127,6 +132,7 @@ def logout():
     logout_user()
     return redirect(url_for('main.index'))
 
+
 @bp.route('/login')
 def login():
     if current_user.is_authenticated:
@@ -135,10 +141,12 @@ def login():
     error = request.args.get('error')
     return render_template('profile/login.html', error=error)
 
+
 @bp.route('/password-reset')
 def password_reset():
     return render_template('profile/password-reset.html')
 
+
 @bp.route('/password-reset', methods=['POST'])
 def check_password_reset_1():
     username = request.form.get('username')
@@ -156,10 +164,12 @@ def check_password_reset_1():
     session['password-reset-email'] = email
     return redirect(url_for('profile.password_reset_2'))
 
+
 @bp.route('/password-reset/2FA')
 def password_reset_2():
     return render_template('profile/password-reset-2.html')
 
+
 @bp.route('/password-reset/2FA', methods=['POST'])
 def check_password_reset_2():
     code =  request.form.get('2fa-code')
@@ -170,10 +180,12 @@ def check_password_reset_2():
     
     return flash('Invalid 2FA Code')
 
+
 @bp.route('/password-reset/reset-password')
 def password_reset_3():
     return render_template('profile/password-reset-3.html')
 
+
 @bp.route('/password-reset/reset-password', methods=['POST'])
 def password_reset_process():
     email = session.get('email')
diff --git a/app/templates/admin/index.html b/app/templates/admin/index.html
new file mode 100644
index 0000000..511b121
--- /dev/null
+++ b/app/templates/admin/index.html
@@ -0,0 +1,44 @@
+{% extends 'base.html' %}
+
+{% block content %}
+<head>
+    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='listings.css')}}">
+    <script src="https://cdn.jsdelivr.net/npm/swiffy-slider@1.6.0/dist/js/swiffy-slider.min.js" crossorigin="anonymous" defer></script>
+    <link href="https://cdn.jsdelivr.net/npm/swiffy-slider@1.6.0/dist/css/swiffy-slider.min.css" rel="stylesheet" crossorigin="anonymous">
+</head>
+<div class="content">
+    <div class="deals_text"><span class="deals_underline">Deals for you</span></div>
+    <div class="swiffy-slider slider-item-show2 slider-item-reveal slider-nav-outside slider-nav-round slider-nav-visible slider-indicators-outside slider-indicators-round slider-indicators-dark slider-nav-animation slider-nav-animation-fadein slider-item-first-visible">
+        <ul class="slider-container py-4">
+            {% for listing in top_listings %}
+            <li class="slide-visible">
+                <div class="card shadow h-100">
+                    <div class="ratio ratio-16x9">
+                        <th>{{top_listing_images[listing.id]}}</th>
+                        <img src="{{ url_for('main.upload_file', filename=top_listing_images[listing.id]) }}" class="card-img-top" loading="lazy" alt="Main Image">
+                    </div>
+                    <div class="card-body p-3 p-xl-4">
+                        <h3 class="card-title h5">{{listing.destination_location}}</h3>
+                        <p class="card-text">Add Location description here once implemented</p>
+                        <div><a href="#" class="btn btn-primary">Book now</a>
+                        </div>
+                    </div>
+                </div>
+            </li>
+            {% endfor %}
+        </ul>
+    
+        <button type="button" class="slider-nav" aria-label="Go left"></button>
+        <button type="button" class="slider-nav slider-nav-next" aria-label="Go left"></button>
+    
+        <div class="slider-indicators">
+            <button class="active" aria-label="Go to slide"></button>
+            <button aria-label="Go to slide" class=""></button>
+            <button aria-label="Go to slide" class=""></button>
+            <button aria-label="Go to slide" class=""></button>
+        </div>
+    </div>
+</div>
+
+<div style="margin-left:50px"> <a href= "{{ url_for('bookings.listings') }}" class="button_1">View All Deals</a></div>
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/admin/listings.html b/app/templates/admin/listings.html
new file mode 100644
index 0000000..5fba48d
--- /dev/null
+++ b/app/templates/admin/listings.html
@@ -0,0 +1,12 @@
+{% extends 'base.html' %}
+# Implements CSS Slider from https://swiffyslider.com/docs/
+{% block content %}
+    <head>
+        <!-- <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='listings.css')}}"> -->
+        <script src="https://cdn.jsdelivr.net/npm/swiffy-slider@1.6.0/dist/js/swiffy-slider.min.js" crossorigin="anonymous" defer></script>
+        <link href="https://cdn.jsdelivr.net/npm/swiffy-slider@1.6.0/dist/css/swiffy-slider.min.css" rel="stylesheet" crossorigin="anonymous">
+    </head>
+    <div class="content">
+        <p>Create full listings page here with search functionality</p>
+    </div>
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/base.html b/app/templates/base.html
index 5f4c7ab..e2c7912 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -39,6 +39,9 @@
                                 </a>
                                 <ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
                                     {% if user_in_session %}
+                                    {% if g.is_admin %}
+                                        <li><a class="dropdown-item" href="{{ url_for('profile.admin_index') }}">Admin Options</a></li>
+                                    {% endif %}
                                         <li><a class="dropdown-item" href="{{ url_for('profile.index') }}">Account Details</a></li>
                                         <li><a class="dropdown-item" href="{{ url_for('profile.manage_bookings')}}">My Bookings</a></li>
                                         <li><a class="dropdown-item" href="{{ url_for('profile.logout') }}">Log Out</a></li>
-- 
GitLab