expand admin page
This commit is contained in:
parent
16f73f33c2
commit
a29ffc0133
12 changed files with 202 additions and 36 deletions
|
@ -8,6 +8,6 @@ from wtforms import validators, ValidationError
|
|||
from wtforms.fields.html5 import EmailField
|
||||
|
||||
class ChargeForm(FlaskForm):
|
||||
amount = DecimalField('Стойност:', [validators.DataRequired(), validators.NumberRange(min=0, max=6)])
|
||||
amount = DecimalField('Стойност:', [validators.DataRequired(), validators.NumberRange(min=1, max=500)])
|
||||
submit = SubmitField('Зареди')
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ from .forms import ChargeForm
|
|||
|
||||
from .. import db
|
||||
from ..email import send_email
|
||||
from ..models import User, Role, Deployment, Service, Region, Address, Domain, contact_proxmaster
|
||||
from ..models import User, Deployment, Service, Region, Address, Domain, contact_proxmaster
|
||||
from ..decorators import admin_required, permission_required
|
||||
|
||||
import base64
|
||||
|
@ -31,6 +31,16 @@ def after_request(response):
|
|||
@admin.route("/", methods=['GET'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def index():
|
||||
alldeployments = Deployment.query.order_by(Deployment.date_created.desc()).all()
|
||||
alldomains = Domain.query.order_by(Domain.date_created.desc()).all()
|
||||
allservices = Service.query.order_by(Service.date_created.desc()).all()
|
||||
alladdresses = Address.query.order_by(Address.date_assigned.desc()).all()
|
||||
return render_template('admin/index.html', deployments=alldeployments, domains=alldomains, services=allservices, addresses=alladdresses)
|
||||
|
||||
@admin.route("/users", methods=['GET'])
|
||||
@login_required
|
||||
@admin_required
|
||||
def users():
|
||||
allusers = User.query.order_by(User.pid.asc()).all()
|
||||
return render_template('admin/users.html', users=allusers)
|
||||
|
@ -42,7 +52,7 @@ def charge(user_pid=0):
|
|||
cuser = User.query.filter_by(pid=user_pid).first()
|
||||
form = ChargeForm()
|
||||
if form.validate_on_submit():
|
||||
cuser.wallet += form.amount.data
|
||||
cuser.wallet += float(form.amount.data)
|
||||
db.session.add(cuser)
|
||||
db.session.commit()
|
||||
return redirect(url_for('admin.users'))
|
||||
|
|
|
@ -160,7 +160,10 @@ class User(db.Model, UserMixin):
|
|||
return self.role is not None and (self.role.permissions & permissions) == permissions
|
||||
|
||||
def is_administrator(self):
|
||||
return self.can(Permission.ADMINISTER)
|
||||
if self.can(Permission.ADMINISTER):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def ping(self):
|
||||
self.last_seen = datetime.utcnow()
|
||||
|
@ -288,6 +291,7 @@ class Address(db.Model):
|
|||
ip = db.Column(db.String(64))
|
||||
rdns = db.Column(db.String(256))
|
||||
macaddr = db.Column(db.String(128))
|
||||
reserved = db.Column(db.Boolean, default=False)
|
||||
|
||||
class Domain(db.Model):
|
||||
__tablename__ = 'domains'
|
||||
|
|
10
app/templates/admin/admin_tasks.html
Normal file
10
app/templates/admin/admin_tasks.html
Normal file
|
@ -0,0 +1,10 @@
|
|||
<div class="col-md-12">
|
||||
<div class="panel panel-warning" id="prxadmin">
|
||||
<div class="panel-heading">Admin Pages</div>
|
||||
<div class="panel-body">
|
||||
<button class="btn btn-default" onclick="window.open('{{ url_for('admin.index') }}','_self')"><span class="glyphicon glyphicon-list" aria-hidden="true"></span> Item Index</button>
|
||||
<button class="btn btn-default" onclick="window.open('{{ url_for('admin.users') }}','_self')"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> List All Users</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -4,21 +4,18 @@
|
|||
|
||||
{% block page_content %}
|
||||
<div class="container-fluid">
|
||||
<br />
|
||||
<div class="row">
|
||||
{% include "admin/admin_tasks.html" %}
|
||||
|
||||
{% block sidebar %}
|
||||
{% include "/settings/acc_avatar.html" %}
|
||||
{% endblock %}
|
||||
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-info">
|
||||
<div class="panel-heading">Зареждане на сметка</div>
|
||||
<div class="panel-body">
|
||||
<form method="POST" action="{{ url_for('admin.charge', user_pid=usr.pid) }}">
|
||||
<p>
|
||||
{{ form.charge_amount.label }} {{ form.charge_amount }}<br />
|
||||
{% for error in form.charge_amount.errors %}
|
||||
Current Value: {{ usr.wallet }}<br />
|
||||
{{ form.amount.label }} {{ form.amount }}<br />
|
||||
{% for error in form.amount.errors %}
|
||||
{{ error }}<br />
|
||||
{% endfor %}
|
||||
</p>
|
||||
|
@ -35,7 +32,6 @@
|
|||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ addEventListener("DOMContentLoaded", function() {
|
|||
request.open("GET", "/vmanager/" + command + "/" + vmid, true);
|
||||
// and then we send it off
|
||||
request.send();
|
||||
//alert("command " + command + " executed.");
|
||||
alert("command " + command + " executed.");
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
|
@ -118,8 +118,7 @@ addEventListener("DOMContentLoaded", function() {
|
|||
<div class="container-fluid">
|
||||
<br />
|
||||
<div class="row">
|
||||
|
||||
<a href="{{ url_for('admin.users') }}">Return to user list</a><br />
|
||||
{% include "admin/admin_tasks.html" %}
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-danger" id="deployments">
|
||||
|
@ -241,13 +240,10 @@ addEventListener("DOMContentLoaded", function() {
|
|||
</tbody>
|
||||
</table>
|
||||
<button class="btn btn-default" onclick="window.open('{{ url_for('main.index') }}')"><span class="glyphicon glyphicon-plus" aria-hiddent="true"></span> Order</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="{{ url_for('admin.users') }}">Return to user list</a><br />
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
|
132
app/templates/admin/index.html
Normal file
132
app/templates/admin/index.html
Normal file
|
@ -0,0 +1,132 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block styles %}
|
||||
{{ super() }}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container-fluid">
|
||||
<br />
|
||||
<div class="row">
|
||||
{% include "admin/admin_tasks.html" %}
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-danger" id="deployments">
|
||||
<div class="panel-heading">Deployments</div>
|
||||
<div class="panel-body"><p>
|
||||
<table class="table table-hover table-striped table-condensed cf">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Cube ID</th>
|
||||
<th>Alias</th>
|
||||
<th>CPU</th>
|
||||
<th>Mem</th>
|
||||
<th>HDD</th>
|
||||
<th>Owner</th>
|
||||
</tr>
|
||||
<tbody>
|
||||
{% for deploy in deployments %}
|
||||
<tr>
|
||||
<td>{% if deploy.enabled == True %}<font color="green">{% else %}<font color="red">{% endif %}{{ deploy.machine_id }}</td>
|
||||
<td>{{ deploy.machine_alias }}</font></td>
|
||||
<td>{{ deploy.machine_cpu }} Cores</td>
|
||||
<td>{{ deploy.machine_mem }} MB</td>
|
||||
<td>{{ deploy.machine_hdd }} GB</td>
|
||||
<td><a href="{{ url_for('admin.dashboard', user_pid=deploy.user_id) }}">{{ deploy.owner.email }}</a></td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-danger" id="domains">
|
||||
<div class="panel-heading">Domains</div>
|
||||
<div class="panel-body"><p>
|
||||
<table class="table table-hover table-striped table-condensed cf">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Expiry Date</th>
|
||||
<th>Owner</th>
|
||||
</tr>
|
||||
<tbody>
|
||||
{% for domain in domains %}
|
||||
<tr>
|
||||
<td><b><a href="http://{{ domain.fqdn }}">{{ domain.fqdn }}</a></b></td>
|
||||
<td>{{ domain.date_expire }}</td>
|
||||
<td><a href="{{ url_for('admin.dashboard', user_pid=domain.user_id) }}">{{ domain.owner.email }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-danger" id="addresses">
|
||||
<div class="panel-heading">Addresses</div>
|
||||
<div class="panel-body"><p>
|
||||
<table class="table table-hover table-striped table-condensed cf">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>IP</th>
|
||||
<th>Reverse DNS</th>
|
||||
<th>MAC Addr.</th>
|
||||
<th>Owner</th>
|
||||
</tr>
|
||||
<tbody>
|
||||
{% for address in addresses %}
|
||||
<tr>
|
||||
<td>{{ address.ip }}</td>
|
||||
<td>{{ address.rdns }}</td>
|
||||
<td>{{ address.macaddr }}</td>
|
||||
<td><a href="{{ url_for('admin.dashboard', user_pid=address.user_id) }}">{{ address.owner.email }}</a></td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-danger" id="services">
|
||||
<div class="panel-heading">Services</div>
|
||||
<div class="panel-body"><p>
|
||||
<table class="table table-hover table-striped table-condensed cf">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Unit</th>
|
||||
<th>Price</th>
|
||||
</tr>
|
||||
<tbody>
|
||||
{% for service in services %}
|
||||
<tr>
|
||||
<td>{{ service.name }}</td>
|
||||
<td>{{ service.description }}</td>
|
||||
<td>{{ service.unit }}</td>
|
||||
<td>{{ service.unitprice }}</td>
|
||||
<td><a href="{{ url_for('admin.dashboard', user_pid=service.user_id) }}">{{ service.owner.email }}</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
{% block page_content %}
|
||||
<div class="row">
|
||||
{% include "admin/admin_tasks.html" %}
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="panel panel-danger" id="users">
|
||||
|
@ -30,11 +31,14 @@
|
|||
</td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<table>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
{% endif %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
<li><a href="#"><span class="glyphicon glyphicon-send"></span> Deploy Application</a></li>
|
||||
<!-- <li class="dropdown">
|
||||
<!-- <li><a href="#"><span class="glyphicon glyphicon-send"></span> Deploy Application</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="glyphicon glyphicon-send"></span> Deploy Application</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="/market/1"><span class="glyphicon glyphicon-send"></span> Business</a></li>
|
||||
|
@ -43,6 +43,9 @@
|
|||
<li><a href="{{ url_for('auth.register') }}">Register</a></li>
|
||||
<li><a href="{{ url_for('auth.login') }}">Login</a></li>
|
||||
{% else %}
|
||||
{% if current_user.is_administrator() %}
|
||||
<li><a href="{{ url_for('admin.index') }}"><span class="glyphicon glyphicon-wrench"></span> Admin Panel</a></li>
|
||||
{% endif %}
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><img class="avatar" src="{{ current_user.gravatar(20) }}"> {{ current_user.email }} <span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<b>Member Since:</b> {{ moment(current_user.member_since).fromNow() }}<br />
|
||||
<b>Group:</b> {{ current_user.group }}<br />
|
||||
<b>2-Factor:</b> {{ current_user.twofactor }}<br />
|
||||
<a href="/auth/change-password">Change Password</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -105,7 +105,7 @@ addEventListener("DOMContentLoaded", function() {
|
|||
request.open("GET", "/vmanager/" + command + "/" + vmid, true);
|
||||
// and then we send it off
|
||||
request.send();
|
||||
//alert("command " + command + " executed.");
|
||||
alert("command " + command + " executed.");
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ from . import vmanager
|
|||
from .forms import DeployForm
|
||||
from .. import db
|
||||
from ..email import send_email
|
||||
from ..models import User, Role, Deployment, Service, Region, Address, Domain, contact_proxmaster
|
||||
from ..models import User, Permission, Deployment, Service, Region, Address, Domain, contact_proxmaster
|
||||
from ..decorators import admin_required, permission_required
|
||||
|
||||
import base64
|
||||
|
@ -66,7 +66,7 @@ def deploy(product_id=None):
|
|||
try:
|
||||
product = Product.get_products()[product_id]
|
||||
except:
|
||||
print('unknown product {}'.format(product_id))
|
||||
current_app.logger.error('unknown product {}'.format(product_id))
|
||||
abort(404)
|
||||
product_pic = '..' + product['img']
|
||||
product_name = product['name']
|
||||
|
@ -169,7 +169,7 @@ def dashboard():
|
|||
status = { cubeid : query['status'] }
|
||||
statuses.update(status)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
current_app.logger.error(e)
|
||||
flash('Deploy #{} unreachable. Support is notified'.format(str(cubeid)))
|
||||
send_email(current_app.config['MAIL_USERNAME'], 'Cube {} is unreachable'.format(cubeid),
|
||||
'vmanager/email/adm_unreachable', user=current_user, cubeid=cubeid )
|
||||
|
@ -188,14 +188,19 @@ def vnc(vmid=0):
|
|||
|
||||
#checks if current user owns this vmid
|
||||
if not vmid in inventory:
|
||||
print('WARNING: user does not own vmid: ' + str(vmid))
|
||||
current_app.logger.warning('User does not own cube id: {}'.format(str(vmid)))
|
||||
#TODO: log ips
|
||||
else:
|
||||
data = {}
|
||||
db_result = contact_proxmaster(data, 'vmvnc', vmid)
|
||||
db_result = contact_proxmaster({}, 'vmvnc', vmid)
|
||||
#return render_template('vmanager/vnc.html', url=db_result['url'])
|
||||
|
||||
return redirect(db_result['url'])
|
||||
|
||||
#admin override
|
||||
if current_user.is_administrator():
|
||||
current_app.logger.warning('Admin override for cube id: {}'.format(str(vmid)))
|
||||
db_result = contact_proxmaster({}, 'vmvnc', vmid)
|
||||
return redirect(db_result['url'])
|
||||
|
||||
abort(404)
|
||||
|
||||
valid_commands = ['vmstatus', 'vmstart', 'vmshutdown', 'vmstop']
|
||||
|
@ -205,9 +210,8 @@ valid_commands = ['vmstatus', 'vmstart', 'vmshutdown', 'vmstop']
|
|||
def command(cmd=None, vmid=0):
|
||||
#checks whether this is a valid command
|
||||
if not cmd in valid_commands:
|
||||
print('WARNING: ' + cmd + ' is not a valid command!')
|
||||
current_app.logger.warning(cmd + ' is not a valid command!')
|
||||
abort(404)
|
||||
|
||||
#if cmd == 'vmstart' and current_user.wallet < 3.0:
|
||||
# flash('Недостатъчно средства в сметката за тази операция')
|
||||
# return redirect(url_for('uinvoice.addfunds'))
|
||||
|
@ -218,13 +222,19 @@ def command(cmd=None, vmid=0):
|
|||
if invcls.enabled == True:
|
||||
inventory.extend([invcls.machine_id])
|
||||
|
||||
|
||||
#checks if current user owns this vmid
|
||||
if not vmid in inventory:
|
||||
print('WARNING: user id:{} does not own cube id:{}'.format(current_user.pid, vmid))
|
||||
current_app.logger.warning('user id: {} does not own cube id:{}'.format(current_user.pid, vmid))
|
||||
#TODO: log ips
|
||||
else:
|
||||
data = {}
|
||||
db_result = contact_proxmaster(data, cmd, vmid)
|
||||
db_result = contact_proxmaster({}, cmd, vmid)
|
||||
#print(db_result)
|
||||
#TODO: log ips
|
||||
|
||||
#admin override
|
||||
if current_user.is_administrator():
|
||||
current_app.logger.warning('Admin override for cube id:{}'.format(vmid))
|
||||
db_result = contact_proxmaster({}, cmd, vmid)
|
||||
|
||||
abort(404)
|
||||
|
||||
|
|
Loading…
Reference in a new issue