add order panel to regular and admin dashboards

This commit is contained in:
deflax 2018-02-07 18:19:55 +02:00
parent 1b3234f49f
commit 9350e875bf
9 changed files with 39 additions and 70 deletions

View file

@ -7,7 +7,14 @@ from ..models import User, Role, Region
from flask_wtf import FlaskForm, RecaptchaField from flask_wtf import FlaskForm, RecaptchaField
from wtforms import StringField, PasswordField, BooleanField, SubmitField, SelectField, DecimalField from wtforms import StringField, PasswordField, BooleanField, SubmitField, SelectField, DecimalField
from wtforms import validators, ValidationError from wtforms import validators, ValidationError
from wtforms.fields.html5 import EmailField from wtforms.fields.html5 import EmailField, DecimalRangeField
class OrderForm(FlaskForm):
cpu = DecimalRangeField('Processor Cores', default=2)
memory = DecimalRangeField('Memory', default=512)
storage = DecimalRangeField('Storage', default=20)
alias = StringField('Machine Alias:', [validators.Regexp(message='ex.: myservice1.com, myservice2.local', regex='^[a-zA-Z0-9][a-zA-Z0-9-_]{0,61}[a-zA-Z0-9]{0,1}\.([a-zA-Z]{1,6}|[a-zA-Z0-9-]{1,30}\.[a-zA-Z]{2,3})$'), validators.Length(6,64)])
submit = SubmitField('Create')
class ChargeForm(FlaskForm): class ChargeForm(FlaskForm):
amount = DecimalField('Стойност:', [validators.DataRequired(), validators.NumberRange(min=1, max=500)]) amount = DecimalField('Стойност:', [validators.DataRequired(), validators.NumberRange(min=1, max=500)])

View file

@ -157,6 +157,9 @@ def transaction(user_pid=0):
@fresh_login_required @fresh_login_required
@admin_required @admin_required
def dashboard(user_pid=0): def dashboard(user_pid=0):
form = OrderForm()
sys_regions = Region.query.all()
cuser = User.query.filter_by(pid=user_pid).first() cuser = User.query.filter_by(pid=user_pid).first()
inv_deployments = cuser.inv_deployments.filter_by(deleted=False).order_by(Deployment.date_created.desc()).all() inv_deployments = cuser.inv_deployments.filter_by(deleted=False).order_by(Deployment.date_created.desc()).all()
@ -206,6 +209,5 @@ def dashboard(user_pid=0):
status = { unit_id : query['status'] } status = { unit_id : query['status'] }
statuses.update(status) statuses.update(status)
current_app.logger.info('[{}] Enabled deployments: {}, services: {}, domains: {}, addresses: {}'.format(cuser.email, inv_deployments_list, inv_services_list, inv_domains_list, inv_addresses_list)) current_app.logger.info('[{}] Enabled deployments: {}, services: {}, domains: {}, addresses: {}'.format(cuser.email, inv_deployments_list, inv_services_list, inv_domains_list, inv_addresses_list))
return render_template('panel/dashboard.html', rrd=rrd, status=statuses, inv_deployments=inv_deployments, inv_services=inv_services, inv_domains=inv_domains, inv_addresses=inv_addresses, regions=regions) return render_template('panel/dashboard.html', form=form, sys_regions=sys_regions, inv_deployments=inv_deployments, inv_services=inv_services, inv_domains=inv_domains, inv_addresses=inv_addresses, rrd=rrd, status=statuses, regions=regions)

View file

@ -17,17 +17,18 @@ def after_request(response):
current_app.logger.warning('Slow query: %s\nParameters: %s\nDuration: %fs\nContext: %s\n' % (query.statement, query.parameters, query.duration, query.context)) current_app.logger.warning('Slow query: %s\nParameters: %s\nDuration: %fs\nContext: %s\n' % (query.statement, query.parameters, query.duration, query.context))
return response return response
@panel.route("/order", methods=['GET', 'POST']) @panel.route("/submitorder", methods=['POST'])
@login_required
def order(): def order():
form = OrderForm()
if form.validate_on_submit(): if form.validate_on_submit():
pass
return redirect('main.index') return redirect('main.index')
return render_template('panel/order.html', form=form)
#DASHBOARD #DASHBOARD
@panel.route("/dashboard", methods=['GET', 'POST']) @panel.route("/dashboard", methods=['GET', 'POST'])
@login_required @login_required
def dashboard(): def dashboard():
form = OrderForm()
sys_regions = Region.query.all() sys_regions = Region.query.all()
cuser = current_user cuser = current_user
@ -77,5 +78,5 @@ def dashboard():
send_email(current_app.config['MAIL_USERNAME'], 'Cube {} is unreachable'.format(unit_id), send_email(current_app.config['MAIL_USERNAME'], 'Cube {} is unreachable'.format(unit_id),
'vmanager/email/adm_unreachable', user=current_user, unit_id=unit_id, error=str(e)) 'vmanager/email/adm_unreachable', user=current_user, unit_id=unit_id, error=str(e))
return render_template('panel/dashboard.html', sys_regions=sys_regions, inv_deployments=inv_deployments, inv_services=inv_services, inv_domains=inv_domains, inv_addresses=inv_addresses, rrd=rrd, status=statuses, regions=regions) return render_template('panel/dashboard.html', form=form, sys_regions=sys_regions, inv_deployments=inv_deployments, inv_services=inv_services, inv_domains=inv_domains, inv_addresses=inv_addresses, rrd=rrd, status=statuses, regions=regions)

View file

@ -26,14 +26,13 @@ class EditProfileForm(FlaskForm):
org_regaddress = StringField('Company Address:') org_regaddress = StringField('Company Address:')
org_responsible = StringField('Accountable Person (optional):') org_responsible = StringField('Accountable Person (optional):')
org_vatnum = StringField('VAT Number:') org_vatnum = StringField('VAT Number:')
twofactor = BooleanField('2-factor authentication') twofactor = BooleanField('Enable 2-factor authentication')
submit = SubmitField('Обнови') submit = SubmitField('Update')
class EditProfileAdminForm(FlaskForm): class EditProfileAdminForm(FlaskForm):
email = StringField('Електроннa поща (логин):', [validators.DataRequired(), validators.Length(1, 64), validators.Email()]) email = StringField('Електроннa поща (логин):', [validators.DataRequired(), validators.Length(1, 64), validators.Email()])
confirmed = BooleanField('Активиран') confirmed = BooleanField('Activated')
role = SelectField('Роля', coerce=int) role = SelectField('Role', coerce=int)
name = StringField('Лице за контакт:', [validators.DataRequired(), validators.Length(3, 60)]) name = StringField('Лице за контакт:', [validators.DataRequired(), validators.Length(3, 60)])
address = StringField('Адрес:', [validators.DataRequired(), validators.Length(2, 50)]) address = StringField('Адрес:', [validators.DataRequired(), validators.Length(2, 50)])

View file

@ -88,7 +88,6 @@ addEventListener("DOMContentLoaded", function() {
<div class="panel panel-info" id="services"> <div class="panel panel-info" id="services">
<div class="panel-heading">Services</div> <div class="panel-heading">Services</div>
<div class="panel-body"> <div class="panel-body">
<div class="no-more-tables">
{% include "panel/services.html" %} {% include "panel/services.html" %}
</div> </div>
</div> </div>
@ -101,7 +100,6 @@ addEventListener("DOMContentLoaded", function() {
<div class="panel panel-info" id="domains"> <div class="panel panel-info" id="domains">
<div class="panel-heading">Domains</div> <div class="panel-heading">Domains</div>
<div class="panel-body"> <div class="panel-body">
<div class="no-more-tables">
{% include "panel/domains.html" %} {% include "panel/domains.html" %}
</div> </div>
</div> </div>
@ -149,5 +147,14 @@ addEventListener("DOMContentLoaded", function() {
<div class="row"> <div class="row">
</div> </div>
<div class="col-md-12">
<div class="panel panel-info" id="orders">
<div class="panel-heading">Create new item</div>
<div class="panel-body">
{% include "panel/order.html" %}
</div>
</div>
</div>
{% endblock %} {% endblock %}

View file

@ -1,59 +1,11 @@
{% extends "base.html" %}
{% block head %}
{{ super() }}
<script type="text/javascript">
function getPeriod()
{
var period = 0;
var periodselect = document.getElementById('period');
period = periodselect.value;
return period;
}
function calculateTotal()
{
//var period = getPeriod();
//var tpm = {{ tpm }};
//var discount = {{ discount }};
//var ppm = {{ ppm }};
var pricetotal = 0;
//pricetotal = period * ppm;
var priceselect = document.getElementById('totalPrice');
priceselect.innerHTML = "Total: 20";
}
</script>
{% endblock %}
{% block title %}Activate deployment{% endblock %}
{% block page_content %} {% block page_content %}
<div class="row">
<div class="col-md-12">
<div class="panel panel-info">
<div class="panel-heading">Order new deployment</div>
<div class="panel-body">
<form method="POST" action="{{ url_for('panel.order') }}"> <form method="POST" action="{{ url_for('panel.order') }}">
{{ form.cpu.label }} {{ form.cpu(min=2, max=16, step=2) }}<br /> {{ form.cpu.label }} {{ form.cpu(min=2, max=16, step=2) }}<br />
{{ form.memory.label }} {{ form.memory(min=512, max=16384, step=512) }}<br /> {{ form.memory.label }} {{ form.memory(min=512, max=16384, step=512) }}<br />
{{ form.storage.label }} {{ form.storage(min=10, max=100, step=10) }}<br /> {{ form.storage.label }} {{ form.storage(min=10, max=100, step=10) }}<br />
<div id="totalPrice">Total: "</div>
<p> <p>
{{ form.csrf_token() }} {{ form.csrf_token() }}
{{ form.submit }} {{ form.submit }}
</p> </p>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View file

@ -37,5 +37,4 @@
</table> </table>
</div> </div>
<!-- <button class="btn btn-default" onclick="window.open('{{ url_for('smanager.requestservice') }}','_self')"><img class="icon icons8-Key-2" width="32" height="32" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAADwUlEQVRYhdXYz0/bVhwA8Bz4I/Yn9A/gwKGHHApxiENwo8IG2rSqh/XUw267cRmJY8dOQpIGOq2cdtguFZNoUQQeiOBnm7h4iB+TRkJwkiJtdZ0GQzPLeTtU0bIQ0qQ8wP1K30sU6X3y/X7fs18cjk89Bsn1fjwEAgQj7nhpQXMFeeilBY1gpV2cFkgsCG7fCAwL8E5fWBQmk7IeX1bNTM6ASrkG83odKuUazOQMGF9WzYmEXPWFxd+xAO+8FphziuvzMRKDkcBKLKt/H2gWzOv1C/NAs2ByRdXdJDD9kc2oc4rru1LcSFj4dTIpn6z9edIR1pqZnAG/mt06GWXExStD+hiJ+SKR1ff/MnvCNVfz69mt1yOMOI8chwV4J0YCq9fKtSZ/aEA3Ccyh6Q0cKdAXFoUUVzJbK8IsFc4IVqoSrFSln+fffWgm83odpriSiVNgDxlukFzvn0zKeuvizFLhzEuL224SDLhJMOClBIlZKpx10+qJhFxBtrPHY9mZaLqgty5EsFLVTYKB5h9CsFK1m1ZH0wX9XlSaRQIkGHEnkzPOLXIZYCZnQIIRd5AAvbSgNQ7h5qSf59/hlCAOkuv9g+R6P06BNWoxf9oNUCnXoJcWNCRAV5C/cJaYFwWjsUmoxfxpN5ukka4gD5EAR8LtK3iZVMo1OBJGVMG7EWmv3QxeJjM5AxKstIsE+Hk8G4+mC29RAqPpo+pYbPMJEiAWBLe/fPyy0st8dXEO1rGQcA8J0OFwOPwRaT+5op47Cz8m51ZLcHwma92NSK+GQ+JnSIBYgHe6SWBedhb5QwN6KAEuKBqcXS1VkCL9kc1ou0deL6395sdt+OinAygfv/8MKdI5xfWNMuLigzmlyh/2Vkn+0IAPn27D737+A26+suDTl9aVIufdJDATK6rWzRv13GoJ4pQAv184gI3vy8f1/yF/WCtbPkYsImv30PTGKE6Bvc53kqI5kZTrY7GstaBo5/CtSOQz6XC83zweCrBtb3UUiLpIcN9LC5UUV2x7AlwL8kMxNL1xy0uLeoorvrE5UtBTvxU12yMfc6q9kZ4Q0FxBHjayExL57u412r1r2qKSnYC2Qg6HwOtPvt2/7P73tIqljyw/Kz2zDbA1t4//gTglnF7pn1AXRad2N+eDJ8obV4C/c+3A5ugEjKXVk7EZed62wPR+BfrCYvlGgZ4Q0GLpI6v1uquUa3A8nn07TPHf3ihwaHrjlp+VnuEUOL0/t6UnllVraVe3B645nFNcnyvA3/FQIOELi2Vb4bqJfwEpWpu91pyNygAAAABJRU5ErkJggg==">Request</button>--> <!-- <button class="btn btn-default" onclick="window.open('{{ url_for('smanager.requestservice') }}','_self')"><img class="icon icons8-Key-2" width="32" height="32" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAADwUlEQVRYhdXYz0/bVhwA8Bz4I/Yn9A/gwKGHHApxiENwo8IG2rSqh/XUw267cRmJY8dOQpIGOq2cdtguFZNoUQQeiOBnm7h4iB+TRkJwkiJtdZ0GQzPLeTtU0bIQ0qQ8wP1K30sU6X3y/X7fs18cjk89Bsn1fjwEAgQj7nhpQXMFeeilBY1gpV2cFkgsCG7fCAwL8E5fWBQmk7IeX1bNTM6ASrkG83odKuUazOQMGF9WzYmEXPWFxd+xAO+8FphziuvzMRKDkcBKLKt/H2gWzOv1C/NAs2ByRdXdJDD9kc2oc4rru1LcSFj4dTIpn6z9edIR1pqZnAG/mt06GWXExStD+hiJ+SKR1ff/MnvCNVfz69mt1yOMOI8chwV4J0YCq9fKtSZ/aEA3Ccyh6Q0cKdAXFoUUVzJbK8IsFc4IVqoSrFSln+fffWgm83odpriSiVNgDxlukFzvn0zKeuvizFLhzEuL224SDLhJMOClBIlZKpx10+qJhFxBtrPHY9mZaLqgty5EsFLVTYKB5h9CsFK1m1ZH0wX9XlSaRQIkGHEnkzPOLXIZYCZnQIIRd5AAvbSgNQ7h5qSf59/hlCAOkuv9g+R6P06BNWoxf9oNUCnXoJcWNCRAV5C/cJaYFwWjsUmoxfxpN5ukka4gD5EAR8LtK3iZVMo1OBJGVMG7EWmv3QxeJjM5AxKstIsE+Hk8G4+mC29RAqPpo+pYbPMJEiAWBLe/fPyy0st8dXEO1rGQcA8J0OFwOPwRaT+5op47Cz8m51ZLcHwma92NSK+GQ+JnSIBYgHe6SWBedhb5QwN6KAEuKBqcXS1VkCL9kc1ou0deL6395sdt+OinAygfv/8MKdI5xfWNMuLigzmlyh/2Vkn+0IAPn27D737+A26+suDTl9aVIufdJDATK6rWzRv13GoJ4pQAv184gI3vy8f1/yF/WCtbPkYsImv30PTGKE6Bvc53kqI5kZTrY7GstaBo5/CtSOQz6XC83zweCrBtb3UUiLpIcN9LC5UUV2x7AlwL8kMxNL1xy0uLeoorvrE5UtBTvxU12yMfc6q9kZ4Q0FxBHjayExL57u412r1r2qKSnYC2Qg6HwOtPvt2/7P73tIqljyw/Kz2zDbA1t4//gTglnF7pn1AXRad2N+eDJ8obV4C/c+3A5ugEjKXVk7EZed62wPR+BfrCYvlGgZ4Q0GLpI6v1uquUa3A8nn07TPHf3ihwaHrjlp+VnuEUOL0/t6UnllVraVe3B645nFNcnyvA3/FQIOELi2Vb4bqJfwEpWpu91pyNygAAAABJRU5ErkJggg==">Request</button>-->
{% endblock %} {% endblock %}

View file

@ -102,4 +102,7 @@
{% else %} {% else %}
<button class="btn btn-default btn-lg btn-block" onclick="window.open('{{ url_for('vmanager.createvm') }}','_self')"><img class="icon icons8-Cloud-Storage" width="48" height="48" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAEEklEQVRYhe3Xy0/bBhwHcA6btEMP0077A3boYYdK23EHLiQ0hQBtVC1S9zjs0L069TCkSUWNpgZCshDYItZOI+tKH7Cibgw6Wu2RAXWMYyc8mpAoUAIEp6VuTR5OwAnJd5dBEbYJKDSA1J/0PfjgXz6y5W/ssrKDNm9dYl4+aqYeq00kSpnK5pGUusX1WkGgxux+/ePLvmQ4lkcp88nPfkHV6DpcEFhpGnnH2D8XKzXwQv98UtXoqioIVDeRH/1IcKlSAzsIbqXSTJ0tCKy2uNt/uy+slhrYez8JrY25XhCotdKDgzNiSXHhWB5DYRFaK+0tfAWt9Pzow9WSA8cereKYheILAo/bGDHE72z5n8E46rsC0LXR0LXRqO8K4O5kbEc7pvg8TrQxuXKD8xVFnLrJ9canVyYTO1k84FvCe+1eXCcWwPLLYPlldJMsPrg4ipsMtyPkmasBQWUk3twKWGm8PRff7kImsoxT7V5MLwrYPPNP0tDbPfh3KrltoGkgIqgaXbVbAT9zuLi00oIHfA6O4ShOOyZQZaFQZ3Pjbx8nwa3NcPAp1CYSersH529NwcuubAn8iXya0VjcXykCtVa6o9cn5JVwZzr9OHcziNBDAWI2hzCXwmourwgEAF7IgEuI6CJZ6FppMJFlRWCfX0BNq6dLEVjdQlODYfmK6RiK4twvwS0xheYasYCGnpAi8N6sCK2V8SsCq76hFsce5WRPPu2YQIBNFgXkEiL0do8icGIxB42Fisviyg3Ol463MtkpmYoZj4qoslAQs7migACgNpFo7Hsge6unl/I4+Z0nW25wHpIAVY2uw593BiQVMx4V8eGlMVwZjhSNA4B4OgtL/zROfsvIIs/eCAoVRuKIHLC26Y+IBGjqn0GHc25XcBvnh39mcaF3WgK03F1IqZoJnQR41EzVO1xPVjaf8P73o2D55V0HTi8K0LXREmAnxWe1VtogrZgW+sbvPkFygt7uAZcQdx2o9MDcnkyh1sb8KgNkvEMyFXP+1hS6SXbXgd0kK1s5rrkMalqYSQlQY6HichXjZVdwqt2LHioKXsgUDeMSIrpJFnU2N9xzacnv+R7noDFTwuaKOXSizSPKVcwasqEnhDqbu+iPI73dg4aekCwuHMtjZikPvd2TLTc4X10HVhiJI19cDe7oLeZ55suukFDRfO/tZxXTTOhMdxZK/iWnFNtf0bTKRLy7DjxmcX99meLFvYat5RodW61uYZo2PsH9fX5pxexV7gTTqGn1DGzswODwbGbPYWsZiWSgtTGhZxVjpoTxRfm3mL2In8tBY6ZS60C1icRFJrevojaReAF8bkAykkcqAxDz+W0dFxOlXVsCU///5aYy2NZxMVHadbCv4H7IC+CuA/djyg7C/AeJ36h1J+7ehgAAAABJRU5ErkJggg=="> Create</button> <button class="btn btn-default btn-lg btn-block" onclick="window.open('{{ url_for('vmanager.createvm') }}','_self')"><img class="icon icons8-Cloud-Storage" width="48" height="48" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAEEklEQVRYhe3Xy0/bBhwHcA6btEMP0077A3boYYdK23EHLiQ0hQBtVC1S9zjs0L069TCkSUWNpgZCshDYItZOI+tKH7Cibgw6Wu2RAXWMYyc8mpAoUAIEp6VuTR5OwAnJd5dBEbYJKDSA1J/0PfjgXz6y5W/ssrKDNm9dYl4+aqYeq00kSpnK5pGUusX1WkGgxux+/ePLvmQ4lkcp88nPfkHV6DpcEFhpGnnH2D8XKzXwQv98UtXoqioIVDeRH/1IcKlSAzsIbqXSTJ0tCKy2uNt/uy+slhrYez8JrY25XhCotdKDgzNiSXHhWB5DYRFaK+0tfAWt9Pzow9WSA8cereKYheILAo/bGDHE72z5n8E46rsC0LXR0LXRqO8K4O5kbEc7pvg8TrQxuXKD8xVFnLrJ9canVyYTO1k84FvCe+1eXCcWwPLLYPlldJMsPrg4ipsMtyPkmasBQWUk3twKWGm8PRff7kImsoxT7V5MLwrYPPNP0tDbPfh3KrltoGkgIqgaXbVbAT9zuLi00oIHfA6O4ShOOyZQZaFQZ3Pjbx8nwa3NcPAp1CYSersH529NwcuubAn8iXya0VjcXykCtVa6o9cn5JVwZzr9OHcziNBDAWI2hzCXwmourwgEAF7IgEuI6CJZ6FppMJFlRWCfX0BNq6dLEVjdQlODYfmK6RiK4twvwS0xheYasYCGnpAi8N6sCK2V8SsCq76hFsce5WRPPu2YQIBNFgXkEiL0do8icGIxB42Fisviyg3Ol463MtkpmYoZj4qoslAQs7migACgNpFo7Hsge6unl/I4+Z0nW25wHpIAVY2uw593BiQVMx4V8eGlMVwZjhSNA4B4OgtL/zROfsvIIs/eCAoVRuKIHLC26Y+IBGjqn0GHc25XcBvnh39mcaF3WgK03F1IqZoJnQR41EzVO1xPVjaf8P73o2D55V0HTi8K0LXREmAnxWe1VtogrZgW+sbvPkFygt7uAZcQdx2o9MDcnkyh1sb8KgNkvEMyFXP+1hS6SXbXgd0kK1s5rrkMalqYSQlQY6HichXjZVdwqt2LHioKXsgUDeMSIrpJFnU2N9xzacnv+R7noDFTwuaKOXSizSPKVcwasqEnhDqbu+iPI73dg4aekCwuHMtjZikPvd2TLTc4X10HVhiJI19cDe7oLeZ55suukFDRfO/tZxXTTOhMdxZK/iWnFNtf0bTKRLy7DjxmcX99meLFvYat5RodW61uYZo2PsH9fX5pxexV7gTTqGn1DGzswODwbGbPYWsZiWSgtTGhZxVjpoTxRfm3mL2In8tBY6ZS60C1icRFJrevojaReAF8bkAykkcqAxDz+W0dFxOlXVsCU///5aYy2NZxMVHadbCv4H7IC+CuA/djyg7C/AeJ36h1J+7ehgAAAABJRU5ErkJggg=="> Create</button>
{% endif %} {% endif %}
</div>
</div>
</div>
{% endblock %} {% endblock %}

View file

@ -129,15 +129,14 @@ $("#{{ form.org_account.id }}").click(function() {
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading">Допълнителна защита на акаунта (2-Factor Authentication)</div> <div class="panel-heading">2-Factor Authentication</div>
<div class="panel-body"> <div class="panel-body">
<p> <p>
<p>За да използвате тази функция изпълнете следните стъпки:<br /> <p>1. Please install <a href="https://fedorahosted.org/freeotp/">FreeOTP</a> on your mobile device. <a href="https://itunes.apple.com/us/app/freeotp/id872559395">iTunes</a> | <a href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">Google Play</a><br />
1. Моля инсталирайте <a href="https://fedorahosted.org/freeotp/">FreeOTP</a> на вашият смартфон. <a href="https://itunes.apple.com/us/app/freeotp/id872559395">iTunes</a> | <a href="https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp">Google Play</a><br /> 2. Scan using the application your QR code.<br />
2. Сканирайте с помоща на приложението вашия QR код. Той е равносилен на допълнителна парола и не трябва да бъде показван или изгубван<br /> <input type="button" value="Show your QR code" onclick="window.open('{{ url_for('auth.qrcode') }}','popUpWindow','height=500,width=400,left=100,top=100,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no, status=yes');"><br />
<input type="button" value="Покажи QR кода" onclick="window.open('{{ url_for('auth.qrcode') }}','popUpWindow','height=500,width=400,left=100,top=100,resizable=yes,scrollbars=yes,toolbar=yes,menubar=no,location=no,directories=no, status=yes');"><br /> 3. After the code is properly loaded in the FreeOTP app, you may activate the 2FA login with the following checkbox:</p>
3. Маркирайте отметката и обновете профила. Не губете своя QR код. </p>
{{ form.twofactor }} {{ form.twofactor.label }}<br /> {{ form.twofactor }} {{ form.twofactor.label }}<br />
</p> </p>