from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired
from flask_mysqldb import MySQL
from dbutils.pooled_db import PooledDB
from flask import (
    Flask,
    get_flashed_messages,
    render_template,
    request,
    redirect,
    url_for,
    session,
    flash,
    jsonify,
    render_template,
)
from flask_sqlalchemy import SQLAlchemy
from flask_login import (
    LoginManager,
    UserMixin,
    login_user,
    login_required,
    current_user,
)
from werkzeug.security import generate_password_hash, check_password_hash
import os
from urllib.parse import quote
import secrets
from pathlib import Path
from flask_migrate import Migrate
from datetime import datetime
from sqlalchemy import Null, func, or_, ForeignKey
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import relationship
import MySQLdb
import logging
from sqlalchemy import create_engine








Admin_User = ""

app = Flask(__name__)

SECRET_FILE_PATH = Path(".flask_secret")
try:
    with SECRET_FILE_PATH.open("r") as secret_file:
        app.secret_key = secret_file.read()
except FileNotFoundError:
    with SECRET_FILE_PATH.open("w") as secret_file:
        app.secret_key = secrets.token_hex(32)
        secret_file.write(app.secret_key)

app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+mysqlconnector://{username}:{password}@{host}/{database}'.format(
    username='hidden',
    password='hidden',
    host='hidden.mysql.pythonanywhere-services.com',
    database='hidden$MySQL_Server'
)
app.config['SECRET_KEY'] = open(".flask_secret", "rb").read()
app.config['ALLOW_USER_REGISTRATION'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_POOL_SIZE'] = 300  # Set your desired pool size
app.config['SQLALCHEMY_POOL_TIMEOUT'] = 60  # Set your desired pool timeout
app.config['SQLALCHEMY_POOL_RECYCLE'] = 60  # 60 minutes (in seconds)
app.config['SQLALCHEMY_POOL_PRE_PING'] = True

db = SQLAlchemy(app)
migrate = Migrate(app, db)
login_manager = LoginManager(app)
login_manager.login_view = 'login'

logging.basicConfig()
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)





class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(100), unique=True, nullable=False)
    password = db.Column(db.String(100), nullable=False)
    first_name = db.Column(db.String(100), nullable=False)
    last_name = db.Column(db.String(100), nullable=False)
    location = db.Column(db.String(100))
    position = db.Column(db.String(100))
    employment_status = db.Column(db.String(2), nullable=False)
    change_password_required = db.Column(db.Boolean, default=True)
    supervisor_email = db.Column(db.String(100))
    second_approver_email = db.Column(db.String(100))
    is_admin = db.Column(db.Boolean, default=False) #Set the admin users with True
    time_off_requests = db.relationship('time_off_request', backref='requestor', lazy=True)


class time_off_request(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    start_date = db.Column(db.Date, nullable=False)
    end_date = db.Column(db.Date, nullable=False)
    status = db.Column(db.String(20), default='Pending')
    requestor_email = db.Column(db.String(100), db.ForeignKey('user.email'), nullable=False)
    system_comments = db.Column(db.String, nullable=False)
    comments = db.Column(db.Text, nullable=True)
    partial_day = db.Column(db.Boolean, nullable=True)
    start_time = db.Column(db.Time, nullable=True)
    end_time = db.Column(db.Time, nullable=True)
    priority =  db.Column(db.String(3), nullable=True)
    current_approver = db.Column(db.String(100), nullable=False)
    coverage_required = db.Column(db.Boolean, nullable=True)

class RegistrationForm(FlaskForm):
    email = StringField('Email', validators=[DataRequired()])
    password = PasswordField('Password', validators=[DataRequired()])
    first_name = StringField('First Name', validators=[DataRequired()])
    last_name = StringField('Last Name', validators=[DataRequired()])
    location = StringField('Location')
    position = StringField('Position')
    has_logged_in = False
    supervisor_email = StringField('Supervisor Email')
    second_approver_email = StringField('Second Approver Email')
    submit = SubmitField('Register')

# Check if the database file exists, and create the tables if it doesn't
if not os.path.exists('C:/Users/mcomer/OneDrive - Fort Worth Community Credit Union/Desktop/web-app/time-off-app/instance/database.db'):
    with app.app_context():
        db.create_all()

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

@app.route('/submit_request', methods=['GET', 'POST'])
@login_required
def submit_request():
    if current_user.change_password_required:
        session.pop('_flashes', None)
        flash("You are not allowed to access this page. Please change your password.", 'error')
        return redirect(url_for('change_password'))

    if request.method == 'POST':
        start_date_str = request.form.get('start_date')
        end_date_str = request.form.get('end_date')
        start_date = datetime.strptime(start_date_str, '%Y-%m-%d').date()
        end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date()
        comments = request.form.get('comments')
        partial_day = request.form.get('toggle_state')
        start_time = request.form.get('start_time')
        end_time = request.form.get('end_time')
        start_hour = request.form.get('start_time_hour')
        start_minute = request.form.get('start_time_minute')
        start_ampm = request.form.get('start_time_ampm')
        end_hour = request.form.get('end_time_hour')
        end_minute = request.form.get('end_time_minute')
        end_ampm = request.form.get('end_time_ampm')
        current_approver = current_user.supervisor_email

        if partial_day == '1':
            partial_day = True
        else:
            partial_day = False

        if current_user.is_authenticated and current_user.employment_status is not None and partial_day == False:
            if current_user.employment_status == 'FT':
                start_time_obj = '9:00 AM'
                end_time_obj = '5:00 PM'
                start_time = datetime.strptime(start_time_obj, '%I:%M %p').time()
                end_time = datetime.strptime(end_time_obj, '%I:%M %p').time()
            elif current_user.employment_status == 'PT':
                start_time_obj = '9:00 AM'
                end_time_obj = '1:00 PM'
                start_time = datetime.strptime(start_time_obj, '%I:%M %p').time()
                end_time = datetime.strptime(end_time_obj, '%I:%M %p').time()
        else:
            start_time_str = f"{start_hour}:{start_minute} {start_ampm}"
            end_time_str = f"{end_hour}:{end_minute} {end_ampm}"
            start_time = datetime.strptime(start_time_str, '%I:%M %p').time()
            end_time = datetime.strptime(end_time_str, '%I:%M %p').time()

        new_request = time_off_request(start_date = start_date, end_date = end_date, requestor_email = current_user.email, comments = comments, partial_day = partial_day, start_time = start_time, end_time = end_time, system_comments = None, current_approver = current_approver,)

        db.session.add(new_request)
        db.session.commit()

        session.pop('_flashes', None)
        flash('Time off request submitted successfully.', 'success')
    return redirect(url_for('requests_viewer') + '?success=true')

    return render_template('requests_viewer.html')

@app.route('/request_time_off')
@login_required
def request_time_off():
    if current_user.change_password_required:
        session.pop('_flashes', None)
        flash("You are not allowed to access this page. Please change your password.", 'error')
        return redirect(url_for('change_password'))

    current_user_requests = time_off_request.query.filter_by(requestor_email = current_user.email).all()
        # Check if the user has any existing requests

    if not current_user_requests:
        # The user doesn't have any existing requests, enforce the requirement
        secret_token = secrets.token_urlsafe(16)
        session['secret_token'] = secret_token  # Store the token in the user's session
        session.pop('_flashes', None)
        flash('You must submit three individual weeks\' requests as stated in FTWCCU Policy. Please choose your three required weeks in order by priority.', 'warning')
        return redirect(url_for('submit_weekly_requests', secret_token=secret_token))

    return render_template('request_time_off.html', current_user=current_user)

@app.route('/change_password', methods=['GET', 'POST'])
@login_required
def change_password():
    # Check if the user needs to change their password
    if not current_user.change_password_required == True:
        session.pop('_flashes', None)
        flash("You are not allowed to access this page.", 'error')
        return redirect(url_for('home'))

    if request.method == 'POST':
        new_password = request.form['new_password']
        confirm_password = request.form['confirm_password']

        if new_password == confirm_password:
            # Update the user's password
            current_user.password = generate_password_hash(new_password)
            current_user.change_password_required = False  # Reset the flag
            db.session.commit()
            session.pop('_flashes', None)
            flash("Password changed successfully.", 'success')


            return redirect(url_for('home'))
        else:
            session.pop('_flashes', None)
            flash("Passwords do not match. Please try again.", 'error')

    return render_template('change_password.html')

@app.route('/submit_weekly_requests', methods=['GET', 'POST'])
@login_required
def submit_weekly_requests():
    if current_user.change_password_required:
        session.pop('_flashes', None)
        flash("You are not allowed to access this page. Please change your password.", 'error')
        return redirect(url_for('change_password'))
    # Retrieve the secret token from the query parameters
    secret_token = request.args.get('secret_token')

    # Check if the token is valid need to fix does not work
    if request.method == 'GET':
        if not secret_token or secret_token != session.get('secret_token'):
            return redirect(url_for('requests_viewer'))


    if request.method == 'POST':
        try:
            with db.session.begin_nested():
                # Process the first section
                start_date1 = request.form.get('start_date1')
                end_date1 = request.form.get('end_date1')
                comments1 = request.form.get('comments1')
                urgent_request_label = request.form.get('urgent_request')


                if urgent_request_label == 'on':
                    system_comments_results = 'User would like all three requests if staffing allows.'
                else:
                    system_comments_results = 'User does not want all three requests.'


                current_approver = current_user.supervisor_email




                if current_user.is_authenticated and current_user.employment_status is not None:
                    if current_user.employment_status == 'FT':
                        start_time_obj = '9:00 AM'
                        end_time_obj = '5:00 PM'
                        start_time_default = datetime.strptime(start_time_obj, '%I:%M %p').time()
                        end_time_default = datetime.strptime(end_time_obj, '%I:%M %p').time()
                    elif current_user.employment_status == 'PT':
                        start_time_obj = '9:00 AM'
                        end_time_obj = '1:00 PM'
                        start_time_default = datetime.strptime(start_time_obj, '%I:%M %p').time()
                        end_time_default = datetime.strptime(end_time_obj, '%I:%M %p').time()

                    if start_date1 is not None and end_date1 is not None:
                        start_date1 = datetime.strptime(start_date1, '%Y-%m-%d').date()
                        end_date1 = datetime.strptime(end_date1, '%Y-%m-%d').date()

                        new_request1 = time_off_request(
                            start_date=start_date1,
                            end_date=end_date1,
                            requestor_email=current_user.email,
                            partial_day=False,
                            comments=comments1,
                            system_comments=system_comments_results,
                            start_time=start_time_default,
                            end_time=end_time_default,
                            priority="1st",
                            current_approver = current_approver,
                        )

                        db.session.add(new_request1)

                    # Process the second section
                    start_date2 = request.form.get('start_date2')
                    end_date2 = request.form.get('end_date2')
                    comments2 = request.form.get('comments2')
                    if start_date2 is not None and end_date2 is not None:
                        start_date2 = datetime.strptime(start_date2, '%Y-%m-%d').date()
                        end_date2 = datetime.strptime(end_date2, '%Y-%m-%d').date()

                        new_request2 = time_off_request(
                            start_date=start_date2,
                            end_date=end_date2,
                            requestor_email=current_user.email,
                            comments=comments2,
                            partial_day = False,
                            system_comments = system_comments_results,
                            start_time=start_time_default,
                            end_time=end_time_default,
                            priority="2nd",
                            current_approver = current_approver,

                        )

                        db.session.add(new_request2)

                    # Process the third section
                    start_date3 = request.form.get('start_date3')
                    end_date3 = request.form.get('end_date3')
                    comments3 = request.form.get('comments3')
                    if start_date3 is not None and end_date3 is not None:
                        start_date3 = datetime.strptime(start_date3, '%Y-%m-%d').date()
                        end_date3 = datetime.strptime(end_date3, '%Y-%m-%d').date()

                        new_request3 = time_off_request(
                            start_date=start_date3,
                            end_date=end_date3,
                            requestor_email=current_user.email,
                            comments=comments3,
                            partial_day = False,
                            system_comments = system_comments_results,
                            start_time=start_time_default,
                            end_time=end_time_default,
                            priority="3rd",
                            current_approver = current_approver,

                        )

                    db.session.add(new_request3)
                    print(db.session.add(new_request1))
                    print(db.session.add(new_request2))
                    print(db.session.add(new_request3))

            db.session.commit()
            session.pop('_flashes', None)
            flash('Weekly requests submitted successfully.', 'success')
            session.pop('secret_token', None)

        except Exception as e:
            db.session.rollback()
            print(f"Error processing requests: {e}")
            session.pop('_flashes', None)
            flash('Error submitting requests. Please try again.', 'error')
            error_message = quote(str(e))
            session.pop('secret_token', None)

            return redirect(url_for('requests_viewer') + f'?success=false&error_message={error_message}')

        return redirect(url_for('requests_viewer') + '?success=true')




    return render_template('submit_weekly_requests.html')

@app.route('/')
def root():
    return redirect(url_for('home'))

@app.route('/requests_viewer')
@login_required
def requests_viewer():
    if current_user.change_password_required:
        session.pop('_flashes', None)
        flash("You are not allowed to access this page. Please change your password.", 'error')
        return redirect(url_for('change_password'))
    current_user_requests = time_off_request.query.filter_by(requestor_email = current_user.email).all()
    return render_template('requests_viewer.html', current_user=current_user, current_user_requests=current_user_requests, User=User)


@app.route('/approvals')
@login_required
def approvals():
    if current_user.change_password_required:
        session.pop('_flashes', None)
        flash("You are not allowed to access this page. Please change your password.", 'error')
        return redirect(url_for('change_password'))


    # Fetch supervisor requests
    supervisor_requests = time_off_request.query.filter_by(current_approver=current_user.email).all()

    # Fetch requests based on the conditions
    requests = []

    # Fetch requests where the requestor's supervisor or second_approver is the current user
    supervisor_or_second_approver_requests = time_off_request.query.filter(or_(
        time_off_request.requestor_email == current_user.email,
        time_off_request.current_approver == current_user.email,
        time_off_request.requestor_email == current_user.supervisor_email,
        time_off_request.requestor_email == current_user.second_approver_email
    )).distinct().all()

    # Fetch requests where the second_approver_email is the current user and status is pre-approved or approved
    second_approver_requests = time_off_request.query.filter(
        (time_off_request.current_approver == current_user.second_approver_email) &
        (time_off_request.status.in_(['pre-Approved', 'approved']))
    ).distinct().all()

    # Combine the results and remove duplicates
    requests = list(set(supervisor_requests + supervisor_or_second_approver_requests + second_approver_requests))

    return render_template('approvals.html', current_user=current_user, current_user_requests=requests, User=User)






@app.route('/deny_request/<request_id>', methods=['POST'])
@login_required
def deny_request(request_id):
    # Fetch the request based on the request_id
    request_to_deny = time_off_request.query.get(request_id)

    if request_to_deny:
        # Update status to "Approved"
        request_to_deny.status = 'Denied'



        approver_name = current_user.first_name + ' ' + current_user.last_name
        current_time_comments = datetime.now().time()
        formatted_time = current_time_comments.strftime("%I:%M %p")


        # Update comments if "comments" is not empty
        comments = request.json.get('comments')



        if not request_to_deny.comments:
            # If request_to_approve.comments is blank
            if comments:
                # Set comments to a new value if comments is provided
                request_to_deny.comments = f"{approver_name} - {formatted_time}: {comments}"
        else:
            # If request_to_approve.comments is not blank
            if comments:
                # Append comments to the existing comments (if any)
                request_to_deny.comments = f"{request_to_deny.comments}\n{approver_name} - {formatted_time}: {comments}"


        # Save the changes to the database
        db.session.commit()

        # Get the updated request details with the requestor's name
        updated_data = {
            'status': request_to_deny.status,
            'current_approver': request_to_deny.current_approver,
            'name': f"{request_to_deny.requestor.first_name} {request_to_deny.requestor.last_name}",
            'position': request_to_deny.requestor.position,
            'department': request_to_deny.requestor.location,
            # Add other relevant fields as needed
        }

        return jsonify(updated_data)
    else:
        flash("Denial Failed", 'error')

@app.route('/approve_request/<request_id>', methods=['POST'])
@login_required
def approve_request(request_id):
    # Fetch the request based on the request_id
    request_to_approve = time_off_request.query.get(request_id)

    if request_to_approve:
        # Update status to "Approved"
        request_to_approve.status = 'Approved'

        # Update coverage_required based on the answer to coverage_question
        coverage_question_answer = request.json.get('coverage_question')
        if coverage_question_answer == 'True':
            request_to_approve.coverage_required = True
        elif coverage_question_answer == 'False':
            request_to_approve.coverage_required = False



        approver_name = current_user.first_name + ' ' + current_user.last_name
        print(approver_name)
        current_time_comments = datetime.now().time()
        formatted_time = current_time_comments.strftime("%I:%M %p")


        # Update comments if "comments" is not empty
        comments = request.json.get('comments')



        if not request_to_approve.comments:
            # If request_to_approve.comments is blank
            if comments:
                # Set comments to a new value if comments is provided
                request_to_approve.comments = f"{approver_name} - {formatted_time}: {comments}"
        else:
            # If request_to_approve.comments is not blank
            if comments:
                # Append comments to the existing comments (if any)
                request_to_approve.comments = f"{request_to_approve.comments}\n{approver_name} - {formatted_time}: {comments}"


        # Save the changes to the database
        db.session.commit()

        # Get the updated request details with the requestor's name
        updated_data = {
            'status': request_to_approve.status,
            'current_approver': request_to_approve.current_approver,
            'name': f"{request_to_approve.requestor.first_name} {request_to_approve.requestor.last_name}",
            'position': request_to_approve.requestor.position,
            'department': request_to_approve.requestor.location,
            # Add other relevant fields as needed
        }

        return jsonify(updated_data)
    else:
        flash("Approval Failed", 'error')

@app.route("/pre_approve_request/<request_id>", methods=["POST"])
@login_required
def pre_approve_request(request_id):
    # Fetch the request based on the request_id
    request_to_pre_approve = time_off_request.query.get(request_id)
    requestor_email = request_to_pre_approve.requestor_email
    requestors = User.query.filter_by(email=requestor_email).first()

    if request_to_pre_approve:
        # Update status to "Pre-Approved"
        request_to_pre_approve.status = "Pre-Approved"

        # Update coverage_required based on the answer to coverage_question
        coverage_question_answer = request.json.get("coverage_question")
        if coverage_question_answer == "True":
            request_to_pre_approve.coverage_required = True
        elif coverage_question_answer == "False":
            request_to_pre_approve.coverage_required = False

        approver_name = current_user.first_name + " " + current_user.last_name
        print(approver_name)
        current_time_comments = datetime.now().time()
        formatted_time = current_time_comments.strftime("%I:%M %p")

        # Update comments if "comments" is not empty
        comments = request.json.get("comments")

        if not request_to_pre_approve.comments:
            # If request_to_approve.comments is blank
            if comments:
                # Set comments to a new value if comments is provided
                request_to_pre_approve.comments = (
                    f"{approver_name} - {formatted_time}: {comments}"
                )
        else:
            # If request_to_approve.comments is not blank
            if comments:
                # Append comments to the existing comments (if any)
                request_to_pre_approve.comments = f"{request_to_pre_approve.comments}\n{approver_name} - {formatted_time}: {comments}"

        if (
            request_to_pre_approve.current_approver != requestors.second_approver_email
            and requestors.second_approver_email is not None
        ):
            request_to_pre_approve.current_approver = requestors.second_approver_email
        else:
            pass
            # Save the changes to the database

        db.session.commit()

        # Get the updated request details with the requestor's name
        updated_data = {
            "status": request_to_pre_approve.status,
            "current_approver": request_to_pre_approve.current_approver,
            "name": f"{request_to_pre_approve.requestor.first_name} {request_to_pre_approve.requestor.last_name}",
            "position": request_to_pre_approve.requestor.position,
            "department": request_to_pre_approve.requestor.location,
            # Add other relevant fields as needed
        }

        return jsonify(updated_data)
    else:
        flash("Approval Failed", "error")

from flask_login import logout_user

@app.route('/logout')
def logout():
    session.clear()
    logout_user()
    session.clear()
    return redirect(url_for('login'))

@app.route('/check_user_exists', methods=['GET'])
def check_user_exists():
    email = request.args.get('email')
    existing_user = User.query.filter_by(email=email).first()
    user_exists = existing_user is not None
    return jsonify({'userExists': user_exists})

@app.route('/register', methods=['POST'])
@login_required
def register():
    if current_user.change_password_required:
        session.pop('_flashes', None)
        flash("You are not allowed to access this page. Please change your password.", 'error')
        return redirect(url_for('change_password'))
    overwrite = int(request.form.get('overwrite', 0))  # Get the overwrite value from form data
    if current_user.email == Admin_User:
        email = request.form.get('email').lower()
        password = request.form.get('password')
        first_name = request.form.get('first_name')
        last_name = request.form.get('last_name')
        location = request.form.get('location')
        position = request.form.get('position')
        supervisor_email = request.form.get('supervisor_email')
        second_approver_email = request.form.get('second_approver_email')
        employment_status = request.form.get('employement_status')

        existing_user = User.query.filter_by(email=email).first()
        print(request.form)
        print(overwrite)

        if existing_user and overwrite == 1:
            # Overwrite the existing user's data
            existing_user.email = email.lower()
            existing_user.password = generate_password_hash(password)
            existing_user.first_name = first_name
            existing_user.last_name = last_name
            existing_user.location = location
            existing_user.position = position
            existing_user.supervisor_email = supervisor_email
            existing_user.second_approver_email = second_approver_email
            existing_user.employment_status = employment_status
            db.session.commit()
            session.pop('_flashes', None)
            flash('User data overwritten successfully.', 'success')
        else:
            # Register a new user
            password_hash = generate_password_hash(password)
            new_user = User(email=email, password=password_hash, first_name=first_name, last_name=last_name,
                            location=location, position=position, supervisor_email=supervisor_email,
                            second_approver_email=second_approver_email, employment_status=employment_status)
            db.session.add(new_user)
            db.session.commit()
            session.pop('_flashes', None)
            flash('User registered successfully.', 'success')

        return redirect(url_for('show_registration_form'))
    else:
        return "User registration is only allowed for the admin."

@app.route('/register', methods=['GET'])
def show_registration_form():
    if current_user.change_password_required:
        session.pop('_flashes', None)
        flash("You are not allowed to access this page. Please change your password.", 'error')
        return redirect(url_for('change_password'))
    overwrite = request.args.get('overwrite')
    return render_template('registration_form.html', overwrite=overwrite)

@app.route('/bulk_create_users', methods=['GET', 'POST'])
@login_required
def bulk_create_users():
    if current_user.change_password_required:
        session.pop('_flashes', None)
        flash("You are not allowed to access this page. Please change your password.", 'error')
        return redirect(url_for('change_password'))
    if current_user.email == Admin_User:
        form = RegistrationForm()  # Create an instance of the RegistrationForm
        if request.method == 'POST':
            # Handle bulk user creation here
            user_data = request.form.get('user_data')
            lines = user_data.strip().split('\n')
            for line in lines:
                data = line.strip().split(',')
                if len(data) < 8:
                    session.pop('_flashes', None)
                    flash(f"Invalid data format: {line}. Skipping this entry.", 'warning')
                    continue

                email, password, first_name, last_name, location, position, supervisor_email, second_approver_email = data
                existing_user = User.query.filter_by(email=email).first()

                if existing_user:
                    session.pop('_flashes', None)
                    flash(f"A user with email {email} already exists. Do you want to overwrite the previous user?", 'warning')
                    continue  # Skip this entry for now; you can handle the overwrite in the HTML form

                hashed_password = generate_password_hash(password)
                new_user = User(
                    email=email.lower(), password=hashed_password, first_name=first_name, last_name=last_name,
                    location=location, position=position, supervisor_email=supervisor_email,
                    second_approver_email=second_approver_email
                )
                db.session.add(new_user)
            db.session.commit()
            flash('Bulk User Creation Completed.', 'success')
        # If it's a GET request, render the template with the form instance in the context
        return render_template('bulk_create_users_form.html', form=form)
    else:
        return "You do not have permission to access this feature."

@app.route('/login', methods=['GET', 'POST'])
def login():
    session.clear()
    if request.method == 'POST':
        email = request.form['email'].lower()
        password = request.form['password']
        user = User.query.filter(func.lower(User.email) == email).first()

        if user and check_password_hash(user.password, password):
            login_user(user)

            # Check if the user needs to change their password
            if user.email != Admin_User and user.change_password_required == True:
                session.pop('_flashes', None)
                flash("You must change your password before accessing the site.")
                return redirect(url_for('change_password'))


            return redirect(url_for('home'))
        else:
            print("Login failed. Check credentials.")
            print(f"Email: {email}, Password: {password}")
            if user:
                print(f"Database Password Hash: {user.password}")

    return render_template('login.html')

@app.context_processor
def inject_is_admin():
    if current_user.is_authenticated:
        isAdmin = current_user.email == Admin_User
    else:
        isAdmin = False
    return dict(isAdmin=isAdmin)

@app.route('/home')
@login_required
def home():
    if current_user.change_password_required:
        session.pop('_flashes', None)
        flash("You are not allowed to access this page. Please change your password.", 'error')
        return redirect(url_for('change_password'))
    return render_template('home.html', Admin_User=Admin_User, current_user=current_user)

if __name__ == '__main__':
    app.run(debug=True)

 

Python Online Compiler

Write, Run & Share Python code online using OneCompiler's Python online compiler for free. It's one of the robust, feature-rich online compilers for python language, supporting both the versions which are Python 3 and Python 2.7. Getting started with the OneCompiler's Python editor is easy and fast. The editor shows sample boilerplate code when you choose language as Python or Python2 and start coding.

Taking inputs (stdin)

OneCompiler's python online editor supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample python program which takes name as input and print your name with hello.

import sys
name = sys.stdin.readline()
print("Hello "+ name)

About Python

Python is a very popular general-purpose programming language which was created by Guido van Rossum, and released in 1991. It is very popular for web development and you can build almost anything like mobile apps, web apps, tools, data analytics, machine learning etc. It is designed to be simple and easy like english language. It's is highly productive and efficient making it a very popular language.

Tutorial & Syntax help

Loops

1. If-Else:

When ever you want to perform a set of operations based on a condition IF-ELSE is used.

if conditional-expression
    #code
elif conditional-expression
    #code
else:
    #code

Note:

Indentation is very important in Python, make sure the indentation is followed correctly

2. For:

For loop is used to iterate over arrays(list, tuple, set, dictionary) or strings.

Example:

mylist=("Iphone","Pixel","Samsung")
for i in mylist:
    print(i)

3. While:

While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.

while condition  
    #code 

Collections

There are four types of collections in Python.

1. List:

List is a collection which is ordered and can be changed. Lists are specified in square brackets.

Example:

mylist=["iPhone","Pixel","Samsung"]
print(mylist)

2. Tuple:

Tuple is a collection which is ordered and can not be changed. Tuples are specified in round brackets.

Example:

myTuple=("iPhone","Pixel","Samsung")
print(myTuple)

Below throws an error if you assign another value to tuple again.

myTuple=("iPhone","Pixel","Samsung")
print(myTuple)
myTuple[1]="onePlus"
print(myTuple)

3. Set:

Set is a collection which is unordered and unindexed. Sets are specified in curly brackets.

Example:

myset = {"iPhone","Pixel","Samsung"}
print(myset)

4. Dictionary:

Dictionary is a collection of key value pairs which is unordered, can be changed, and indexed. They are written in curly brackets with key - value pairs.

Example:

mydict = {
    "brand" :"iPhone",
    "model": "iPhone 11"
}
print(mydict)

Supported Libraries

Following are the libraries supported by OneCompiler's Python compiler

NameDescription
NumPyNumPy python library helps users to work on arrays with ease
SciPySciPy is a scientific computation library which depends on NumPy for convenient and fast N-dimensional array manipulation
SKLearn/Scikit-learnScikit-learn or Scikit-learn is the most useful library for machine learning in Python
PandasPandas is the most efficient Python library for data manipulation and analysis
DOcplexDOcplex is IBM Decision Optimization CPLEX Modeling for Python, is a library composed of Mathematical Programming Modeling and Constraint Programming Modeling