"""
User based views
"""
# General imports
from flask import current_app as app
from flask import (Flask, jsonify, request, session)
from flask.blueprints import Blueprint
from werkzeug.utils import secure_filename
from passlib.hash import pbkdf2_sha256
from common import *
from models.models import *
from playhouse.shortcuts import *
from datetime import datetime as DT

import logging
import json
import os
import csv
from pathlib import Path
from zipfile import ZipFile
import base64
import numpy as np

# Local import
from views.utils import _error_json, _ok_json, _get_upload_folder, _logged_in_user

user_blueprint = Blueprint('user', __name__, template_folder='templates')

# Views
@auth_check
def home():
    """ Home view """
    return _ok_json("Welcome HOME!")


def logout():
    """ Logout view """
    session.pop('user', None)
    return _ok_json("Logged out.")


def current_user():
    """ Current User view """
    if "user" in session:
        u = session['user']
        nav = _make_nav(u["role"])
        return _ok_json({"user": u, "nav": nav})
    else:
        return _error_json("User not logged in.")


def signup():
    """ Signup view """
    error = None
    try:
        if request.method == 'POST':
            pw_hashed = pbkdf2_sha256.hash(request.form.get('password'))
            u = User(login_id=request.form.get('login_id'),
                     email=request.form.get('email'),
                     first_name=request.form.get('first_name'),
                     last_name=request.form.get('last_name'),
                     password=pw_<PASSWORD>)
            # TODO: Validate user
            u.save()
            return _ok_json("User created. Please login with your credentials.")
        else:
            return _error_json("GET not supported.")

    except Exception as ex:
        logging.exception("Error occurred when signing up.")
        return _error_json(str(ex))


def login():
    """ Login view """
    try:
        lf = request.get_json(force=True)
        login_id = lf.get("login_id")
        plain_pass = lf.get("password")
        logging.debug("Received login request for user {}".format(login_id))

        u = User.get_or_none(User.login_id == login_id)
        valid = False
        if u:
            if u.is_locked == True:
                return _error_json("User is locked! Please contact admin.")
            logging.info("Got user: {0}, {1}".format(u.login_id, u.first_name))
            valid = pbkdf2_sha256.verify(plain_pass, u.password)

        if not valid:
            return _error_json("Invalid user/password.")
        else:
            user_obj = {"id": u.id, "login_id": login_id,
                        "name": "{0} {1}".format(u.first_name, u.last_name), "role_name": u.get_role_label(), "role": u.role}
            session['user'] = user_obj
            nav = _make_nav(u.role)
            return _ok_json({"user": user_obj, "nav": nav})
    except Exception as ex:
        msg = "Error when authenticating."
        logging.exception(msg)
        return _error_json(msg)

@auth_check
def users_upload():
    """ View to upload users """
    try:
        # Only a superuser can add new users
        if not _is_user_in_role("SU"):
            return _error_json("Operation not allowed. Insufficient privileges!")

        users_file = request.files['users_file']
        if users_file.filename == '':
            return _error_json("No file supplied!")
        filename = secure_filename(users_file.filename)
        file_path = os.path.join(_get_upload_folder(), filename)
        users_file.save(file_path)

        with db.atomic() as txn:
            # TODO: Use a better/efficient strategy to add users in DB
            with open(file_path, newline='') as csvfile:
                reader = csv.DictReader(csvfile)
                for row in reader:
                    login_id = row["LOGIN_ID"]
                    fname = row["FIRST_NAME"]
                    lname = row["LAST_NAME"]
                    email = row["EMAIL"]
                    u = User(login_id=login_id, first_name=fname,
                             last_name=lname, email=email,
                             password=<PASSWORD>5<PASSWORD>(random_str(10)))
                    _save_entity(u)
            txn.commit()

        return _ok_json("Users added successfully!")

    except Exception as ex:
        msg = "Error when handling users upload request."
        logging.exception(msg)
        return _error_json(msg)

# Helper views
def _make_nav(role_code):
    """ Helper function to make navigation bar """
    try:
        with open(os.path.join(app.root_path, "nav.json"), "r") as nd:
            nav = json.load(nd)
            links = []
            menus = {}
            for n in nav:
                r = n.pop("roles")
                if "-{}".format(role_code) in r:
                    continue

                if "*" in r or role_code in r:
                    m = n.pop("menu")
                    if m:
                        if m not in menus:
                            menus[m] = []
                        menus[m].append(n)
                    else:
                        links.append(n)

            return {"menus": menus, "links": links}

    except Exception as ex:
        logging.exception("Error occurred when loading nav data.")


def _is_user_in_role(role):
    """ Helper function to get the role of a user """
    u = _logged_in_user()
    return u and u.role in role
"""
User based views
"""
# General imports
from flask import current_app as app
from flask import (Flask, jsonify, request, session)
from flask.blueprints import Blueprint
from werkzeug.utils import secure_filename
from passlib.hash import pbkdf2_sha256
from common import *
from models.models import *
from playhouse.shortcuts import *
from datetime import datetime as DT

import logging
import json
import os
import csv
from pathlib import Path
from zipfile import ZipFile
import base64
import numpy as np

# Local import
from views.utils import _error_json, _ok_json, _get_upload_folder, _logged_in_user

user_blueprint = Blueprint('user', __name__, template_folder='templates')

# Views
@auth_check
def home():
    """ Home view """
    return _ok_json("Welcome HOME!")


def logout():
    """ Logout view """
    session.pop('user', None)
    return _ok_json("Logged out.")


def current_user():
    """ Current User view """
    if "user" in session:
        u = session['user']
        nav = _make_nav(u["role"])
        return _ok_json({"user": u, "nav": nav})
    else:
        return _error_json("User not logged in.")


def signup():
    """ Signup view """
    error = None
    try:
        if request.method == 'POST':
            pw_hashed = pbkdf2_sha256.hash(request.form.get('password'))
            u = User(login_id=request.form.get('login_id'),
                     email=request.form.get('email'),
                     first_name=request.form.get('first_name'),
                     last_name=request.form.get('last_name'),
                     password=pw_<PASSWORD>)
            # TODO: Validate user
            u.save()
            return _ok_json("User created. Please login with your credentials.")
        else:
            return _error_json("GET not supported.")

    except Exception as ex:
        logging.exception("Error occurred when signing up.")
        return _error_json(str(ex))


def login():
    """ Login view """
    try:
        lf = request.get_json(force=True)
        login_id = lf.get("login_id")
        plain_pass = lf.get("password")
        logging.debug("Received login request for user {}".format(login_id))

        u = User.get_or_none(User.login_id == login_id)
        valid = False
        if u:
            if u.is_locked == True:
                return _error_json("User is locked! Please contact admin.")
            logging.info("Got user: {0}, {1}".format(u.login_id, u.first_name))
            valid = pbkdf2_sha256.verify(plain_pass, u.password)

        if not valid:
            return _error_json("Invalid user/password.")
        else:
            user_obj = {"id": u.id, "login_id": login_id,
                        "name": "{0} {1}".format(u.first_name, u.last_name), "role_name": u.get_role_label(), "role": u.role}
            session['user'] = user_obj
            nav = _make_nav(u.role)
            return _ok_json({"user": user_obj, "nav": nav})
    except Exception as ex:
        msg = "Error when authenticating."
        logging.exception(msg)
        return _error_json(msg)

@auth_check
def users_upload():
    """ View to upload users """
    try:
        # Only a superuser can add new users
        if not _is_user_in_role("SU"):
            return _error_json("Operation not allowed. Insufficient privileges!")

        users_file = request.files['users_file']
        if users_file.filename == '':
            return _error_json("No file supplied!")
        filename = secure_filename(users_file.filename)
        file_path = os.path.join(_get_upload_folder(), filename)
        users_file.save(file_path)

        with db.atomic() as txn:
            # TODO: Use a better/efficient strategy to add users in DB
            with open(file_path, newline='') as csvfile:
                reader = csv.DictReader(csvfile)
                for row in reader:
                    login_id = row["LOGIN_ID"]
                    fname = row["FIRST_NAME"]
                    lname = row["LAST_NAME"]
                    email = row["EMAIL"]
                    u = User(login_id=login_id, first_name=fname,
                             last_name=lname, email=email,
                             password=<PASSWORD>5<PASSWORD>(random_str(10)))
                    _save_entity(u)
            txn.commit()

        return _ok_json("Users added successfully!")

    except Exception as ex:
        msg = "Error when handling users upload request."
        logging.exception(msg)
        return _error_json(msg)

# Helper views
def _make_nav(role_code):
    """ Helper function to make navigation bar """
    try:
        with open(os.path.join(app.root_path, "nav.json"), "r") as nd:
            nav = json.load(nd)
            links = []
            menus = {}
            for n in nav:
                r = n.pop("roles")
                if "-{}".format(role_code) in r:
                    continue

                if "*" in r or role_code in r:
                    m = n.pop("menu")
                    if m:
                        if m not in menus:
                            menus[m] = []
                        menus[m].append(n)
                    else:
                        links.append(n)

            return {"menus": menus, "links": links}

    except Exception as ex:
        logging.exception("Error occurred when loading nav data.")


def _is_user_in_role(role):
    """ Helper function to get the role of a user """
    u = _logged_in_user()
    return u and u.role in role
User based views # General imports # Local import # Views Home view Logout view Current User view Signup view # TODO: Validate user Login view View to upload users # Only a superuser can add new users # TODO: Use a better/efficient strategy to add users in DB # Helper views Helper function to make navigation bar Helper function to get the role of a user