def dashboard():
    try:
        number_sites = len(database.list("sites"))
    except:
        number_sites = 0
        
    try:
        number_learning_objects = len(database.list("learning_objects"))
    except:
        number_learning_objects = 0
    
    sites = database.list("sites")    
    list_names_objets_for_sites = []
    list_numbers_objets_for_sites = []
    list_colors = []
    
    try:
        for site in sites:
            objects_for_sites = database.filter_by("learning_objects", {"classification.taxon_path.source": str(site["site"]["name"])})
            if objects_for_sites:
                list_names_objets_for_sites.append(objects_for_sites[0]['classification']['taxon_path']['source'])
                list_numbers_objets_for_sites.append(len(objects_for_sites))        
        x = 0
        while x < len(list_names_objets_for_sites):
            r = lambda: random.randint(0,255)
            list_colors.append('#%02X%02X%02X' % (r(),r(),r()))
            x += 1
    except:
        list_names_objets_for_sites.append("Nenhum")
        list_numbers_objets_for_sites.append(0)
        list_colors.append('#000000')
        
    return render_template("dashboard.html", number_sites=number_sites, number_learning_objects=number_learning_objects, list_names_objets_for_sites=list_names_objets_for_sites, list_numbers_objets_for_sites=list_numbers_objets_for_sites, list_colors=list_colors)
def login():
    if not current_user.is_authenticated:
        form = LoginForm()
        if form.validate_on_submit():
            email = form.email.data
            password = form.password.data
            remember = form.remember.data
            query = database.filter_by('users', {"email": email})
            if query:
                user_bd = query[0]
                if check_password_hash(user_bd['password'], password):
                    user = User(user_bd['name'], user_bd['email'], user_bd['password'], user_bd['role'], user_bd['search_limit'])
                    login_user(user, remember=remember)
                    return redirect(url_for("index"))
                else:
                    flash('Ocorreu um erro ao tentar fazer login. Por favor verifique sua senha!', 'danger')
                    return redirect(url_for("login"))  
            else:
                flash('Ocorreu um erro ao tentar fazer login. Email não registrado!', 'danger')
                return redirect(url_for("login")) 
        else:                
            return render_template('login.html', form=form)
    else:
        flash('Você já está logado no sistema!', 'info')
        return redirect(url_for("index"))
def profile():
    form = ProfileForm()
    if form.validate_on_submit():
        name = form.name.data
        current_password = form.current_password.data
        new_password = form.new_password.data
        confirm_new_password = form.confirm_new_password.data
        #busca dados do usuário no banco
        query = database.filter_by('users', {"email": current_user.email})
        if query:
            user_bd = query[0]
            #verificar se a senha atual é igual a sanha no banco de dados
            if check_password_hash(user_bd['password'], current_password):       
                if new_password == confirm_new_password:
                    user_temp = User(name, current_user.email, new_password, current_user.role, current_user.search_limit)
                    database.update("users", user_bd, user_temp.get_as_json())
                    form.name.data = name
                    flash('Dados do perfil alterados com sucesso!', 'success')
                    return render_template('profile.html', form=form)
                else:
                    flash('A confirmação de senha está incorreta!', 'danger')                    
                    return render_template('profile.html', form=form)
            else:
                flash('A senha atual informada está incorreta!', 'danger')                        
                return render_template('profile.html', form=form)
        else:
            abort(500)
    else:
        form.name.data = current_user.name
        return render_template('profile.html', form=form)
def update_learning_object(id_learning_object_0, id_learning_object_1):
    save_edit_learning_object = request.get_json()
    if save_edit_learning_object:
        learning_object_db = database.filter_by('learning_objects', {"general.identifier": id_learning_object_0,"general.identifier": id_learning_object_1})
        database.update("learning_objects", learning_object_db[0], save_edit_learning_object)
        #print('\n',json.dumps(save_edit_learning_object, indent=2),'\n')
    return redirect(url_for("view_learning_objects"))
def register():
    if not current_user.is_authenticated:
        form = RegisterForm()
        if form.validate_on_submit():
            name = form.name.data
            email = form.email.data
            password = form.password.data
            confirm_password = form.confirm_password.data
            query = database.filter_by('users', {"email": email})
            if not query:
                if password == confirm_password:
                    user = User(name, email, password, "standard", SEARCH_LIMIT)
                    database.create("users", user)
                    flash('Conta registrada com sucesso!', 'success')
                    return redirect(url_for("login"))
                else:
                    flash('A senha de confirmação está incorreta!', 'danger')
                    return render_template('register.html', form=form)
            else:
                flash('Email já cadastrado!', 'danger')
                return render_template('register.html', form=form)
        return render_template('register.html', form=form)
    else:
        flash('Você já está logado no sistema!', 'info')
        return redirect(url_for("index"))
def create_learning_object(index_list_results, index_result, name_site, api_site):
    list_results = []
    list_sites_api = []
    update_results = []
    cache_user = []
    global cache_app_after_login
    index_user = None
    for x in range(len(cache_app_after_login)):
        if current_user.email == cache_app_after_login[x][0]:              
            cache_user = cache_app_after_login[x]
            index_user = x
            break  
    if cache_user:                                
        list_results = cache_user[1]
        list_sites_api = cache_user[2]
        update_results = cache_user[3]       
    save_item = list_results[index_list_results][index_result]
    #verificar se já esta no banco de dados e impedir de incluir novamente
    learning_object = LearningObject(save_item, name_site, api_site)
    learning_object_json = learning_object.get_as_json()
    print(learning_object_json)
    item_db = database.filter_by('learning_objects', {"general.identifier": learning_object_json['general']['identifier'][1]})
    if not item_db:
        database.create("learning_objects", learning_object)
        update_results[index_list_results][index_result] = 1
        cache_user[3] = update_results
        cache_app_after_login[index_user] = cache_user
        return render_template("results_search_api.html", list_results=list_results, list_sites_api=list_sites_api, update_results=update_results)
    else:
        database.update("learning_objects", item_db[0])
        return render_template("results_search_api.html", list_results=list_results, list_sites_api=list_sites_api, update_results=update_results)
 def get(user_email):
     query = database.filter_by('users', {"email": user_email})
     if query:
         user_bd = query[0]
         user = User(user_bd['name'], user_bd['email'], user_bd['password'],
                     user_bd['role'], user_bd['search_limit'])
     else:
         user = None
     return user
def delete_user(email):
    if current_user.role != "administrator":
        flash('Acesso negado!', 'danger')
        return redirect(url_for("index"))
    
    user_bd = database.filter_by("users", {"email": email})
    if user_bd:
        database.delete("users", user_bd[0])
        
    users = database.list("users")
    
    flash('Usuário deletado com sucesso!', 'success')
    
    return render_template("view_users.html", users=users)
def remove_admin_access(email):
    if current_user.role != "administrator":
        flash('Acesso negado!', 'danger')
        return redirect(url_for("index"))

    user_bd = database.filter_by("users", {"email": email})
    if user_bd:
        user_aux = user_bd[0]
        user_aux['role'] = "standard"
        user_aux['search_limit'] = 20
        
        database.update("users", user_bd[0], user_aux)
        
        flash('Acesso como administrador removido do usuário!', 'success')
    
    flash('Ocorrreu um problema ao tentar remover o acesso como administrador do usuário !', 'danger')
    
    users = database.list("users")
    return render_template("view_users.html", users=users)
def forgot_password():
    if not current_user.is_authenticated:
        global cache_app_before_login
        form = ForgotPasswordForm()
        if form.validate_on_submit():
            query = database.filter_by('users', {"email": form.email.data})
            if query:
                user_bd = query[0] 
                
                #gera codigo temporário para recuperar a senha
                number = range(0, 9)
                code_temp = ''
                for i in range(6):
                    code_temp += str(random.choice(number))
                
                #gerando hash de segurança do link de recuperação
                token_temp = secrets.token_hex(64)
                
                #gera validade do codigo e do token
                validate_temp = int(datetime.datetime.now().replace(tzinfo=pytz.utc).timestamp()+3600) #soma 3600 segundos ao tempo de validade para ser valido por 1 hora
                        
                #gestão do cache
                cache_user_temp = [] 
                for x in range(len(cache_app_before_login)):
                    if user_bd['email'] == cache_app_before_login[x][0]:              
                        cache_user_temp = cache_app_before_login[x]
                        break        
                if cache_user_temp:
                    cache_user_temp[0] = user_bd
                    cache_user_temp[1] = int(code_temp)
                    cache_user_temp[2] = str(token_temp)
                    cache_user_temp[3] = int(validate_temp)
                else:
                    cache_user_temp.append(user_bd)
                    cache_user_temp.append(int(code_temp))
                    cache_user_temp.append(str(token_temp))
                    cache_user_temp.append(int(validate_temp))
                    cache_app_before_login.append(cache_user_temp)
                
                #envio do email com o código
                msg = Message(
                    'Código para recuperação de senha!',
                    recipients=[form.email.data],
                )
                msg.html = f"""  
                    <div width="100%" style="margin:0;padding:0!important">
                        <center style="width:100%;>
                            <div style="max-width:600px;margin:0 auto" class="m_-2585479850499807075email-container">
                                <table width="100%" cellspacing="0" cellpadding="0" border="0" align="center">
                                    <tbody>
                                        <tr>
                                            <td height="20"></td>
                                        </tr>
                                        <tr>
                                            <td align="center">
                                                <p style="line-height:1.5;font-family:'Lato',Calibri,Arial,sans-serif;font-size:18px;color:#000000;text-align:center;text-decoration:none"> 
                                                    Para recuperar a seu acesso use o código abaixo:
                                                </p>
                                            </td>
                                        </tr>
                                    </tbody>
                                </table>
                                <table style="border:1px solid #4400ff;margin-top:10px" border="0" width="200" cellspacing="0" cellpadding="0" align="center">
                                    <tbody>
                                        <tr>
                                            <td height="60">
                                                <p style="font-family:'Lato',Calibri,Arial,sans-serif;font-size:22px;color:#4400ff;text-align:center">
                                                    <strong>
                                                        {code_temp}
                                                    </strong>
                                                </p>
                                            </td>
                                        </tr>
                                    </tbody>
                                </table>
                                <table width="100%" cellspacing="0" cellpadding="0" border="0" align="center">
                                    <tbody>
                                        <tr>
                                            <td height="20"></td>
                                        </tr>
                                        <tr>
                                            <td align="center">
                                                <p style="line-height:1.5;font-family:'Lato',Calibri,Arial,sans-serif;font-size:12px;color:#000000;text-align:center;text-decoration:none"> 
                                                    Este código é válido por 1 hora.
                                                </p>
                                            </td>
                                        </tr>
                                    </tbody>
                                </table>
                            </div>
                        </center>
                        <div class="yj6qo"></div>
                        <div class="adL"></div>
                    </div>
                """
                try:                    
                    mail.send(msg)
                    flash('Código enviado no email informado!', 'primary')            
                    return redirect(url_for("verify_code_forgot_password", token=token_temp))
                except:
                    flash('Ocorreu um problema ao tentar enviar o código, por favor tente novamente!', 'danger')                                
                    return redirect(url_for("forgot_password"))                    
            else:
                flash('Resgistro não encontrado, por favor realize seu registro no sistema!', 'warning')
                return redirect(url_for("register"))
        else:
            return render_template('forgot_password.html', form=form)
    else:
        flash('Você já está logado no sistema!', 'info')
        return redirect(url_for("index"))
def request_admin_access():
    msg = Message('Solicitação de acesso como administrador!')
    msg.html = f"""  
            <div width="100%" style="margin:0;padding:0!important">
                <center style="width:100%;>
                    <div style="max-width:600px;margin:0 auto" class="m_-2585479850499807075email-container">
                        <table width="100%" cellspacing="0" cellpadding="0" border="0" align="center">
                            <tbody>
                                <tr>
                                    <td height="20"></td>
                                </tr>
                                <tr>
                                    <td align="center">
                                        <p style="line-height:1.5;font-family:'Lato',Calibri,Arial,sans-serif;font-size:18px;color:#000000;text-align:center;text-decoration:none"> 
                                            O usuário abaixo solicitou acesso como administrador:
                                        </p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        <table style="border:1px solid #9400D3;margin-top:10px" border="0" width="200" cellspacing="0" cellpadding="0" align="center">
                            <tbody>
                                <tr>
                                    <td height="60">
                                        <p style="font-family:'Lato',Calibri,Arial,sans-serif;font-size:22px;color:#9400D3;text-align:center">
                                            <strong>
                                                {current_user.email}
                                            </strong>
                                        </p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        <table width="100%" cellspacing="0" cellpadding="0" border="0" align="center">
                            <tbody>
                                <tr>
                                    <td height="20"></td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </center>
                <div class="yj6qo"></div>
                <div class="adL"></div>
            </div>
        """        
    
    error = 0
    success = 0
    
    users = database.filter_by("users", {"role": "administrator"})
    for user in users:    
        print(user)
        #envio do email com o código
        msg.recipients = [user['email']]        
        try:                    
            mail.send(msg)
            success += 1
        except:
            error += 1
    
    if error > 0:
        flash(f"Ocorreu um problema ao tentar enviar a solicitação para os administradores! {success} emails foram enviados e {error} não foram enviados", 'info')
    else:
        flash('Solicitação enviada para todos os administradores!', 'primary')
                                
    return redirect(url_for("profile"))
def delete_learning_object(id_learning_object_0, id_learning_object_1):
    learning_object_db = database.filter_by('learning_objects', {"general.identifier": id_learning_object_0,"general.identifier": id_learning_object_1})
    database.delete("learning_objects", learning_object_db[0])
    return redirect(url_for("view_learning_objects"))
def edit_learning_object(id_learning_object_0, id_learning_object_1):
    learning_object = database.filter_by('learning_objects', {"general.identifier": id_learning_object_0,"general.identifier": id_learning_object_1})
    return render_template("edit_learning_object.html", learning_object=learning_object[0])
def results_search_api():   
    global cache_app_after_login
    if current_user.search_limit <= 0 and current_user.role != "administrator":
        flash('Limite diário de buscas na API atingido! Novas buscas na API somente a partir de amanhã!', 'danger')
        return redirect(url_for("index")) 
    stackexchange = StackExchange(PAGE_SIZE, MAX_PAGES)
    sites = database.list("sites")
    list_sites_api = []
    list_results = []
    
    #pegar as datas
    try:
        date_start = datetime.datetime.strptime(request.form.get('date_start')[:10], "%d/%m/%Y").replace(tzinfo=pytz.utc).timestamp() #para pegar somente a data
        date_end = datetime.datetime.strptime(request.form.get('date_end')[:10], "%d/%m/%Y").replace(tzinfo=pytz.utc).timestamp() #para pegar somente a data
    except:
        date_start = datetime.datetime.strptime(request.form.get('date_start')[:10], "%m/%d/%Y").replace(tzinfo=pytz.utc).timestamp() #para pegar somente a data
        date_end = datetime.datetime.strptime(request.form.get('date_end')[:10], "%m/%d/%Y").replace(tzinfo=pytz.utc).timestamp() #para pegar somente a data
    #pegar as ordenações
    selected_sort = request.form.get('selected-sort')
    selected_order = request.form.get('selected-order')
    #pegar as tags e não tags
    selected_tagged = request.form.get('selected-tagged')
    selected_nottagged = request.form.get('selected-nottagged')
    #pegar os sites
    selected_sites = request.form.getlist('selected-sites')
    #pegar seleção de somente perguntas aceitas
    accepted = request.form.get('accepted')
    #pegar o tipo da busca
    selected_type_search = request.form.getlist('selected-type-search') 
    #pegar a busca
    search = request.form.get('search')
    
    if selected_sites:
        for option in selected_sites:
            option = option.split("-")[1]
            for site in sites:
                if option == site["site"]["api_parameter"]:
                    list_sites_api.append(site["site"])
                    break
    else:
        for site in sites:
            list_sites_api.append(site["site"])
        
    for site in list_sites_api:
        list_result_items = stackexchange.search_advanced(str(search), str(site["api_parameter"]), date_start, date_end, str(selected_sort), str(selected_order), accepted, selected_tagged, selected_nottagged, str(selected_type_search[0]))
        list_results.append(list_result_items)
    
    update_results = []
    update = []
    for results, site in zip(list_results, list_sites_api):
        for result in results:
            item_db = database.filter_by('learning_objects', {"general.identifier": result["question_id"]})
            if item_db:
                update.append(1)
            else:
                update.append(0)
        update_results.append(update)
        update = []
    
    cache_user = []
    for x in range(len(cache_app_after_login)):
        if current_user.email == cache_app_after_login[x][0]:              
            cache_user = cache_app_after_login[x]
            cache_user[1] = list_results
            cache_user[2] = list_sites_api
            cache_user[3] = update_results
            cache_app_after_login[x] = cache_user
            break        
    if not cache_user:        
        cache_user.append(current_user.email)
        cache_user.append(list_results)
        cache_user.append(list_sites_api)
        cache_user.append(update_results)
        cache_app_after_login.append(cache_user)
     
    #controle do limite de pesquisas diárias na API
    if(current_user.role == "standard"):
        current_user.search_limit -= 1
        database.update("users", database.filter_by('users', {"email": current_user.email})[0], current_user.get_as_json())
    
    
    return render_template("results_search_api.html", list_results=cache_user[1], list_sites_api=cache_user[2], update_results=cache_user[3])
 def get_id(self):
     query = database.filter_by('users', {"email": self.email})
     user_bd = query[0]
     return str(user_bd['email'])