diff --git a/app/__init__.py b/app/__init__.py index 683ee20..6e6e046 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -38,6 +38,9 @@ moment.init_app(app) from .main import main as main_blueprint app.register_blueprint(main_blueprint) +from .panel import panel as panel_blueprint +app.register_blueprint(panel_blueprint, url_prefix='/panel') + from .auth import auth as auth_blueprint app.register_blueprint(auth_blueprint, url_prefix='/auth') diff --git a/app/admin/routes.py b/app/admin/routes.py index 9b2fe8e..fd4622e 100644 --- a/app/admin/routes.py +++ b/app/admin/routes.py @@ -217,6 +217,6 @@ def dashboard(user_pid=0): status = { unit_id : query['status'] } statuses.update(status) current_app.logger.info('[{}] Enabled deployments: {}, services: {}, domains: {}, bridges: {}, addresses: {}'.format(cuser.email, inv_deployments_list, inv_services_list, inv_domains_list, inv_bridges_list, inv_addresses_list)) - return render_template('main/dashboard.html', rrd=rrd, status=statuses, inv_deployments=inv_deployments, inv_legacy=inv_legacy, inv_services=inv_services, inv_domains=inv_domains, inv_bridges=inv_bridges, inv_addresses=inv_addresses, regions=regions) + return render_template('panel/dashboard.html', rrd=rrd, status=statuses, inv_deployments=inv_deployments, inv_legacy=inv_legacy, inv_services=inv_services, inv_domains=inv_domains, inv_bridges=inv_bridges, inv_addresses=inv_addresses, regions=regions) diff --git a/app/auth/routes.py b/app/auth/routes.py index 8f85ca4..2c40553 100644 --- a/app/auth/routes.py +++ b/app/auth/routes.py @@ -72,7 +72,7 @@ def login(): send_email(current_app.config['MAIL_USERNAME'], user.email + ' logged in.', 'auth/email/adm_loginnotify', user=user, ipaddr=lastip ) #flash('Last Login: {} from {}'.format(user.last_seen.strftime("%a %d %B %Y %H:%M"), previp)) flash('Last Login: {}'.format(user.last_seen.strftime("%a %d %B %Y %H:%M"))) - return redirect(request.args.get('next') or url_for('main.dashboard')) + return redirect(request.args.get('next') or url_for('panel.dashboard')) else: flash('Invalid username or password.') @@ -104,7 +104,7 @@ def twofactor(): db.session.add(user) db.session.commit() #send_email(current_app.config['MAIL_USERNAME'], user.email + ' logged in.', 'auth/email/adm_loginnotify', user=user, ipaddr=lastip ) - return redirect(request.args.get('next') or url_for('main.dashboard')) + return redirect(request.args.get('next') or url_for('panel.dashboard')) else: flash('Invalid token.') return render_template('auth/2fa.html', page=page, form=form) diff --git a/app/main/routes.py b/app/main/routes.py index b28d3b5..5837fe8 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -19,7 +19,7 @@ def after_request(response): #STATIC PAGES @main.route("/", methods=['GET']) def index(): - allservers = Server.query.all() + allservers = Server.query.filter_by(enabled=True) return render_template('main/index.html', servers=allservers) @main.route("/chat", methods=['GET']) @@ -54,64 +54,3 @@ def market(group_id=0): abort(404) return render_template('main/marketgroup.html', groupname=allgroups[group_id], products=filtered_products) -#DASHBOARD -@main.route("/dashboard", methods=['GET', 'POST']) -@login_required -def dashboard(): - sys_regions = Region.query.all() - - cuser = current_user - inv_bridges = cuser.inv_bridges.order_by(Bridge.bridge_id.asc()).all() - inv_addresses = cuser.inv_addresses.order_by(Address.ip.asc()).all() - inv_routers = cuser.inv_routers.order_by(Router.date_created.asc()).all() - inv_deployments = cuser.inv_deployments.filter_by(deleted=False).order_by(Deployment.date_created.desc()).all() - inv_legacy = cuser.inv_deployments.filter_by(deleted=False).filter_by(bridge_id=None).order_by(Deployment.date_created.desc()).all() - - regions = {} - for region in sys_regions: - regions[region.pid] = region.description - - inv_deploycubeids = [] - for invcls in inv_deployments: - if invcls.user_id == cuser.pid: - inv_deploycubeids.extend([invcls.machine_id]) - for invcls in inv_legacy: - if invcls.user_id == cuser.pid: - inv_deploycubeids.extend([invcls.machine_id]) - - inv_services = cuser.inv_services.filter_by(deleted=False).order_by(Service.date_last_charge.asc()).all() - inv_domains = cuser.inv_domains.filter_by(deleted=False).order_by(Domain.date_created.desc()).all() - - #extract rrd and status from the deployments - rrd = {} - statuses = {} - #current_app.logger.warning(str(inv_deploycubeids)) - for unit_id in inv_deploycubeids: - rrd[unit_id] = {} - data = { 'unit_id': int(unit_id), - 'type': 'kvm' } - try: - query = contact_proxmaster(data, 'vmrrd') - except Exception as e: - current_app.logger.error(e) - flash('Support is notified.'.format(str(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)) - #current_app.logger.info('debug query:') - #current_app.logger.info(query) - - graphs_list = ['net', 'cpu', 'mem', 'hdd'] - try: - for graph in graphs_list: - raw = query[graph]['image'].encode('raw_unicode_escape') - rrd[unit_id][graph] = base64.b64encode(raw).decode() - status = { unit_id : query['status'] } - statuses.update(status) - except Exception as e: - current_app.logger.error(e) - flash('Support is notified.'.format(str(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)) - - return render_template('main/dashboard.html', sys_regions=sys_regions, inv_bridges=inv_bridges, inv_deployments=inv_deployments, inv_legacy=inv_legacy, inv_services=inv_services, inv_domains=inv_domains, inv_addresses=inv_addresses, rrd=rrd, status=statuses, regions=regions) - diff --git a/app/models.py b/app/models.py index aaa425e..e862a86 100644 --- a/app/models.py +++ b/app/models.py @@ -249,8 +249,11 @@ class Server(db.Model): user_id = db.Column(db.ForeignKey('users.pid')) #FK region_id = db.Column(db.ForeignKey('regions.pid')) #FK + enabled = db.Column(db.Boolean) name = db.Column(db.String) - description = db.Column(db.String) + cpu = db.Column(db.String) + mem = db.Column(db.String) + hdd = db.Column(db.String) address = db.Column(db.String) class Bridge(db.Model): diff --git a/app/panel/__init__.py b/app/panel/__init__.py new file mode 100644 index 0000000..537a5f1 --- /dev/null +++ b/app/panel/__init__.py @@ -0,0 +1,3 @@ +from flask import Blueprint +panel = Blueprint('panel', __name__) +from . import routes diff --git a/app/panel/forms.py b/app/panel/forms.py new file mode 100644 index 0000000..057c7c3 --- /dev/null +++ b/app/panel/forms.py @@ -0,0 +1,14 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, PasswordField, BooleanField, SubmitField, SelectField, DecimalField +from wtforms import validators, ValidationError +from wtforms.fields.html5 import EmailField, DecimalRangeField + +from .. import db + +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') + diff --git a/app/panel/routes.py b/app/panel/routes.py new file mode 100644 index 0000000..1921631 --- /dev/null +++ b/app/panel/routes.py @@ -0,0 +1,87 @@ +from flask import render_template, abort, redirect, url_for, abort, flash, request, current_app, make_response, g +from flask_login import login_required, login_user, logout_user, current_user +from flask_sqlalchemy import get_debug_queries + +from . import panel +from .forms import OrderForm +from .. import db +from ..email import send_email +from ..models import User, Permission, Server, Deployment, Service, Region, Address, Bridge, Router, Domain, contact_proxmaster + +import base64 + +@panel.after_app_request +def after_request(response): + for query in get_debug_queries(): + if query.duration >= current_app.config['SLOW_DB_QUERY_TIME']: + current_app.logger.warning('Slow query: %s\nParameters: %s\nDuration: %fs\nContext: %s\n' % (query.statement, query.parameters, query.duration, query.context)) + return response + +@panel.route("/order", methods=['GET', 'POST']) +def order(): + form = OrderForm() + if form.validate_on_submit(): + return redirect('main.index') + return render_template('panel/order.html', form=form) + +#DASHBOARD +@panel.route("/dashboard", methods=['GET', 'POST']) +@login_required +def dashboard(): + sys_regions = Region.query.all() + + cuser = current_user + inv_bridges = cuser.inv_bridges.order_by(Bridge.bridge_id.asc()).all() + inv_addresses = cuser.inv_addresses.order_by(Address.ip.asc()).all() + inv_routers = cuser.inv_routers.order_by(Router.date_created.asc()).all() + inv_deployments = cuser.inv_deployments.filter_by(deleted=False).order_by(Deployment.date_created.desc()).all() + inv_legacy = cuser.inv_deployments.filter_by(deleted=False).filter_by(bridge_id=None).order_by(Deployment.date_created.desc()).all() + + regions = {} + for region in sys_regions: + regions[region.pid] = region.description + + inv_deploycubeids = [] + for invcls in inv_deployments: + if invcls.user_id == cuser.pid: + inv_deploycubeids.extend([invcls.machine_id]) + for invcls in inv_legacy: + if invcls.user_id == cuser.pid: + inv_deploycubeids.extend([invcls.machine_id]) + + inv_services = cuser.inv_services.filter_by(deleted=False).order_by(Service.date_last_charge.asc()).all() + inv_domains = cuser.inv_domains.filter_by(deleted=False).order_by(Domain.date_created.desc()).all() + + #extract rrd and status from the deployments + rrd = {} + statuses = {} + #current_app.logger.warning(str(inv_deploycubeids)) + for unit_id in inv_deploycubeids: + rrd[unit_id] = {} + data = { 'unit_id': int(unit_id), + 'type': 'kvm' } + try: + query = contact_proxmaster(data, 'vmrrd') + except Exception as e: + current_app.logger.error(e) + flash('Support is notified.'.format(str(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)) + #current_app.logger.info('debug query:') + #current_app.logger.info(query) + + graphs_list = ['net', 'cpu', 'mem', 'hdd'] + try: + for graph in graphs_list: + raw = query[graph]['image'].encode('raw_unicode_escape') + rrd[unit_id][graph] = base64.b64encode(raw).decode() + status = { unit_id : query['status'] } + statuses.update(status) + except Exception as e: + current_app.logger.error(e) + flash('Support is notified.'.format(str(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)) + + return render_template('panel/dashboard.html', sys_regions=sys_regions, inv_bridges=inv_bridges, inv_deployments=inv_deployments, inv_legacy=inv_legacy, inv_services=inv_services, inv_domains=inv_domains, inv_addresses=inv_addresses, rrd=rrd, status=statuses, regions=regions) + diff --git a/app/smanager/routes.py b/app/smanager/routes.py index b90916c..119ab77 100644 --- a/app/smanager/routes.py +++ b/app/smanager/routes.py @@ -77,6 +77,6 @@ def activate(itemid=0): if owner.is_administrator: return redirect(url_for('admin.list_services')) else: - return redirect(url_for('main.dashboard')) + return redirect(url_for('panel.dashboard')) return render_template('smanager/activate.html', form=form, service=service, ppm=ppm, total=(ppm * service.period), currency=owner.currency) diff --git a/app/static/css/range.css b/app/static/css/range.css new file mode 100644 index 0000000..de5b9eb --- /dev/null +++ b/app/static/css/range.css @@ -0,0 +1,86 @@ +input[type=range] { + -webkit-appearance: none; + width: 100%; + margin: 13.8px 0; +} +input[type=range]:focus { + outline: none; +} +input[type=range]::-webkit-slider-runnable-track { + width: 100%; + height: 8.4px; + cursor: pointer; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + background: #3071a9; + border-radius: 1.3px; + border: 0.2px solid #010101; +} +input[type=range]::-webkit-slider-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 36px; + width: 16px; + border-radius: 3px; + background: #f8ffff; + cursor: pointer; + -webkit-appearance: none; + margin-top: -14px; +} +input[type=range]:focus::-webkit-slider-runnable-track { + background: #367ebd; +} +input[type=range]::-moz-range-track { + width: 100%; + height: 8.4px; + cursor: pointer; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + background: #3071a9; + border-radius: 1.3px; + border: 0.2px solid #010101; +} +input[type=range]::-moz-range-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 36px; + width: 16px; + border-radius: 3px; + background: #f8ffff; + cursor: pointer; +} +input[type=range]::-ms-track { + width: 100%; + height: 8.4px; + cursor: pointer; + background: transparent; + border-color: transparent; + color: transparent; +} +input[type=range]::-ms-fill-lower { + background: #2a6495; + border: 0.2px solid #010101; + border-radius: 2.6px; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; +} +input[type=range]::-ms-fill-upper { + background: #3071a9; + border: 0.2px solid #010101; + border-radius: 2.6px; + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; +} +input[type=range]::-ms-thumb { + box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; + border: 1px solid #000000; + height: 36px; + width: 16px; + border-radius: 3px; + background: #f8ffff; + cursor: pointer; + height: 8.4px; +} +input[type=range]:focus::-ms-fill-lower { + background: #3071a9; +} +input[type=range]:focus::-ms-fill-upper { + background: #367ebd; +} + diff --git a/app/static/images/server.png b/app/static/images/server.png new file mode 100644 index 0000000..f687023 Binary files /dev/null and b/app/static/images/server.png differ diff --git a/app/templates/admin/list_servers.html b/app/templates/admin/list_servers.html index e0f8c42..5040560 100644 --- a/app/templates/admin/list_servers.html +++ b/app/templates/admin/list_servers.html @@ -7,7 +7,7 @@
-
Transactions
+
Servers
@@ -15,7 +15,9 @@ Name - Description + CPU + MEM + HDD Address Region Seller @@ -26,7 +28,9 @@ {% for server in servers %} {{ server.name }} - {{ server.description }} + {{ server.cpu }} + {{ server.mem }} + {{ server.hdd }} {{ server.address }} {{ server.region.name }} {{ server.owner.email }} diff --git a/app/templates/base.html b/app/templates/base.html index 0d177b9..f828435 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -16,6 +16,7 @@ {{ super() }} + {% endblock %} {% block scripts %} diff --git a/app/templates/main/footer_index.html b/app/templates/main/footer_index.html index dd4ddd8..41d6396 100644 --- a/app/templates/main/footer_index.html +++ b/app/templates/main/footer_index.html @@ -8,7 +8,6 @@

Contact

-

52 Volga str.
4002 Plovdiv, Bulgaria

tel: +359 (0) 32 398 295
email: office@datapoint.bg

diff --git a/app/templates/main/index.html b/app/templates/main/index.html index 93d0aaa..67d46e1 100644 --- a/app/templates/main/index.html +++ b/app/templates/main/index.html @@ -86,6 +86,16 @@
+
+

+ +
+
+ Alias: {{ server.name }}
+ Processor: {{ server.cpu }}
+ Memory: {{ server.mem }}
+ Storage: {{ server.hdd }}
+
@@ -108,7 +118,7 @@

Поддръжка

Ще Ви помогнем във всички неприятни ситуации, по всяко време.

- +
diff --git a/app/templates/nav.html b/app/templates/nav.html index 38bd163..ca13908 100644 --- a/app/templates/nav.html +++ b/app/templates/nav.html @@ -11,7 +11,7 @@ {% if not current_user.is_authenticated %} {% else %} - + {% endif %}
@@ -49,7 +49,7 @@