separate settings

This commit is contained in:
deflax 2017-03-13 15:36:21 +02:00
parent bfb76658d1
commit 3261c0a96d
11 changed files with 249 additions and 126 deletions

View file

@ -37,6 +37,9 @@ app.register_blueprint(vmanager_blueprint)
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix='/auth')
from .settings import settings as settings_blueprint
app.register_blueprint(settings_blueprint, url_prefix='/settings')
from .uinvoice import uinvoice as uinvoice_blueprint
app.register_blueprint(uinvoice_blueprint, url_prefix='/uinvoice')
@ -57,7 +60,7 @@ app.json_encoder = CustomJSONEncoder
if not app.debug:
import logging
from logging.handlers import RotatingFileHandler
file_handler = RotatingFileHandler('/home/proxadmin/appserver/proxadmin/app/log/proxadmin.log', 'a', 1 * 1024 * 1024, 10)
file_handler = RotatingFileHandler('/home/proxadmin/appserver/proxadmin/log/proxadmin.log', 'a', 1 * 1024 * 1024, 10)
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'))
app.logger.addHandler(file_handler)

View file

@ -56,6 +56,43 @@ def login():
return render_template('auth/login.html', page=page, form=form)
#PROFILE
@auth.route('/profile', methods=['GET', 'POST'])
@login_required
def profile():
page = { 'title': 'Edit Profile' }
currentmail = current_user.email
ouruser = User.query.filter_by(email=currentmail).first()
db.session.commit()
wallet = "%.2f" % round(ouruser.wallet, 3)
print(wallet)
form = EditProfileForm()
if form.validate_on_submit():
current_user.name = form.name.data
current_user.address = form.address.data
current_user.city = form.city.data
current_user.postcode = form.postcode.data
current_user.country = form.country.data
current_user.phone = form.phone.data
current_user.org_responsible = form.org_responsible.data
current_user.org_bulstat = form.org_bulstat.data
current_user.twofactor = form.twofactor.data
db.session.add(current_user)
db.session.commit()
flash('Info Updated!')
form.twofactor.data = current_user.twofactor
form.name.data = current_user.name
form.address.data = current_user.address
form.city.data = current_user.city
form.postcode.data = current_user.postcode
form.country.data = current_user.country
form.phone.data = current_user.phone
form.org_responsible.data = current_user.org_responsible
form.org_bulstat.data = current_user.org_bulstat
return render_template('auth/profile.html', page=page, form=form)
@auth.route('/twofactor', methods=['GET', 'POST'])
def twofactor():

View file

@ -1,4 +1,3 @@
import hashlib
from werkzeug.security import generate_password_hash, check_password_hash
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
@ -9,12 +8,13 @@ from . import db, lm
import os
import base64
import hashlib
from decimal import Decimal
from datetime import date, time, datetime, timedelta
import json
from sortedcontainers import SortedDict
import requests
import onetimepass
from datetime import date, datetime, time, timedelta
from sortedcontainers import SortedDict
class Permission:
DEPLOY = 0x01
@ -57,6 +57,7 @@ class User(db.Model, UserMixin):
password_hash = db.Column(db.String(128))
confirmed = db.Column(db.Boolean, default=False)
active = db.Column(db.Boolean, default=True)
member_since = db.Column(db.DateTime(), default=datetime.utcnow)
last_seen = db.Column(db.DateTime(), default=datetime.utcnow)
last_ip = db.Column(db.String(128))
@ -70,15 +71,24 @@ class User(db.Model, UserMixin):
postcode = db.Column(db.String(10))
country = db.Column(db.String(64))
phone = db.Column(db.String(64))
org_companyname = db.Column(db.Unicode(64))
org_regaddress = db.Column(db.Unicode(128))
org_responsible = db.Column(db.Unicode(128))
org_bulstat = db.Column(db.String(16))
org_vat = db.Column(db.Boolean, default=False)
org_vatnum = db.Column(db.String(16))
wallet = db.Column(db.Float)
credit = db.Column(db.Float)
creditlimit = db.Column(db.Float, default=20.0)
currency = db.Column(db.String(3), default='BGN')
language = db.Column(db.String(2), default='BG')
inv_deployments = db.relationship('Deployment', backref='owner', lazy='dynamic')
inv_contracts = db.relationship('Contract', backref='owner', lazy='dynamic')
inv_domains = db.relationship('Domain', backref='owner', lazy='dynamic')
currency = db.Column(db.String(3), default='BGN')
def __init__(self, **kwargs):
super(User, self).__init__(**kwargs)
if self.role is None:
@ -271,7 +281,7 @@ class Service(db.Model):
pid = db.Column(db.Integer, primary_key=True) #PK
name = db.Column(db.String(64))
image = db.Column(db.String(128))
description = db.Column(db.String(128))
description = db.Column(db.Unicode(128))
unitprice = db.Column(db.Float)
enabled = db.Column(db.Boolean)
@ -305,17 +315,57 @@ class Service(db.Model):
}
return services
class Order(db.Model):
__tablename__ = 'orders'
#TRANSACTIONS
class Transaction(db.Model):
__tablename__ = 'transaction'
pid = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.pid')) #FK
date_created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
units = db.Column(db.Integer, default=1)
unitvalue = db.Column(db.Float)
currency = db.Column(db.String, default='BGN')
paid = db.Column(db.Boolean, default=False)
#class Invoice(db.Model)
#PROFORMA INVOICE CLASS
class Invoice(db.Model):
__tablename__ = 'invoice'
pid = db.Column(db.Integer, primary_key=True)
invoice_number = db.Column(db.Integer, unique=True)
user_id = db.Column(db.Integer, db.ForeignKey('users.pid')) #FK
date_created = db.Column(db.DateTime, index=True, default=datetime.utcnow)
currency = db.Column(db.String, default='BGN')
tax = db.Column(db.Float) #VAT
description = db.Column(db.Unicode(255))
def sub_total(self):
items = self.items
sub_total = 0
for item in items:
sub_total += item.total()
return sub_total
def tax_amount(self):
if not self.tax:
return 0
return self.sub_total() * self.tax / 100.0
def grand_total(self):
amount_str = str(self.sub_total() + self.tax_amount())
amount = Decimal(amount_str)
rounder = Decimal("0.05") # precision for rounding
return amount - amount.remainder_near(rounder)
class InvoiceItem(db.Model):
__tablename__ = 'invoice_item'
pid = db.Column(db.Integer, primary_key=True)
item_number = db.Column(db.Integer)
invoice_id = db.Column(db.Integer, db.ForeignKey('invoice.pid')) #FK
item_title = db.Column(db.Unicode(255))
item_quantity = db.Column(db.Float)
item_price = db.Column(db.Float)
amount = db.Column(db.Float)
invoice = db.relationship(Invoice, backref=backref('items', order_by=item_number, cascade="delete"))
def total(self):
return self.item_quantity * self.item_price
#INVENTORY CLASSES
class Deployment(db.Model):
@ -328,35 +378,34 @@ class Deployment(db.Model):
enabled = db.Column(db.Boolean)
machine_id = db.Column(db.BigInteger) #cubeid
machine_alias = db.Column(db.String) #dns name for easy managing
machine_alias = db.Column(db.String) #dns name
machine_cpu = db.Column(db.Integer)
machine_mem = db.Column(db.Integer)
machine_hdd = db.Column(db.Integer)
credit = db.Column(db.Float)
def charge():
result = Deployment.query.all()
for deploy in result:
managed_user = User.query.get(deploy.user_id)
db.session.add(deploy)
if datetime.utcnow.date() > (deploy.date_expire - timedelta(days=10)):
if deploy.credit > 0:
print('{} Deployment {} will expire in 10 days at {}. Creating new order...'.format(managed_user.email, deploy.machine_alias, deploy.date_expire))
current_product = Product.query.get(int(deploy.product_id))
order = Order(user_id=managed_user.pid, unitvalue=deploy.credit, description='Cloud server {} - {}'.format(current_product.name, deploy.machine_alias))
db.session.add(order)
deploy.credit = 0
deploy.data_expire = datetime.utcnow.date() + timedelta(days=30)
else:
if deploy.enabled == True:
managed_user = User.query.get(deploy.user_id)
db.session.add(managed_user)
current_product = Product.query.get(int(deploy.product_id))
cpu_cost = deploy.machine_cpu * current_app.config['CPU_RATIO']
mem_cost = ( deploy.machine_mem / 1024 ) * current_app.config['MEM_RATIO']
hdd_cost = deploy.machine_hdd * current_app.config['HDD_RATIO']
total = cpu_cost + mem_cost + hdd_cost
if deploy.enabled == True:
print('{}> Charging deployment #{} with {} ({} monthly)'.format(managed_user.email, deploy.pid, total))
deploy.credit += total
db.session.commit()
return True
if managed_user.wallet - managed_user.credit > managed_user.creditlimit:
print('{}> Deployment #{} costs {} today. Credit is now {}'.format(managed_user.email, deploy.machine_id, total, managed_user.credit))
managed_user.credit += total
else:
print('{}> Deployment #{} costs {} today. Credit now is {} and its lower than the credit limit {}.'.format(managed_user.email, deploy.machine_id, total, managed_user.credit, managed_user.creditlimit)
print('')
if datetime.utcnow.date() ==
db.session.commit()
if deploy.
class Contract(db.Model):
__tablename__ = 'contracts'
@ -367,7 +416,7 @@ class Contract(db.Model):
date_expire = db.Column(db.DateTime)
enabled = db.Column(db.Boolean)
description = db.Column(db.String)
description = db.Column(db.Unicode)
units = db.Column(db.Integer)
discount = db.Column(db.Integer) #percent
credit = db.Column(db.Float)

3
app/settings/__init__.py Normal file
View file

@ -0,0 +1,3 @@
from flask import Blueprint
uinvoice = Blueprint('settings', __name__)
from . import routes

60
app/settings/forms.py Normal file
View file

@ -0,0 +1,60 @@
from iso3166 import countries
import string
import random
from ..models import User, Role
from flask_wtf import FlaskForm, RecaptchaField
from wtforms import StringField, PasswordField, BooleanField, SubmitField, SelectField, DecimalField
from wtforms import validators, ValidationError
from wtforms.fields.html5 import EmailField
class EditProfileForm(FlaskForm):
name = StringField('Лице за контакт:', [validators.DataRequired(), validators.Length(3, 60)])
address = StringField('Адрес:', [validators.DataRequired(), validators.Length(2, 50)])
city = StringField('Град:', [validators.DataRequired(), validators.Length(2,40)])
postcode = StringField('Пощенски Код:')
clist = []
for c in countries:
clist.append((c.alpha2, c.name))
country = SelectField('Държава:', choices=clist, default='BG')
phone = StringField('Телефон:')
org_responsible = StringField('Отговорно Лице:')
org_bulstat = StringField('БУЛСТАТ:')
twofactor = BooleanField('2-factor authentication')
submit = SubmitField('Обнови')
class EditProfileAdminForm(FlaskForm):
email = StringField('Електроннa поща (логин):', [validators.DataRequired(), validators.Length(1, 64), validators.Email()])
confirmed = BooleanField('Активиран')
role = SelectField('Роля', coerce=int)
name = StringField('Лице за контакт:', [validators.DataRequired(), validators.Length(3, 60)])
address = StringField('Адрес:', [validators.DataRequired(), validators.Length(2, 50)])
city = StringField('Град:', [validators.DataRequired(), validators.Length(2,40)])
postcode = DecimalField('Пощенски Код:')
clist = []
for c in countries:
clist.append((c.alpha2, c.name))
country = SelectField('Държава:', choices=clist)
phone = DecimalField('Телефон:', [validators.DataRequired()])
org_responsible = StringField('Отговорно Лице:')
org_bulstat = StringField('БУЛСТАТ:')
submit = SubmitField('Обнови')
def __init__(self, user, *args, **kwargs):
super(EditProfileAdminForm, self).__init__(*args, **kwargs)
self.role.choices = [(role.pid, role.name)
for role in Role.query.order_by(Role.name).all()]
self.user = user
def validate_email(self, field):
if field.data != self.user.email and User.query.filter_by(email=field.data).first():
raise ValidationError('Email-а е вече регистриран.')

51
app/settings/routes.py Normal file
View file

@ -0,0 +1,51 @@
from flask import render_template, redirect, request, url_for, flash, session, abort, current_app
from flask_login import login_required, login_user, logout_user, current_user
from sqlalchemy import desc
from . import settings
from .forms import EditProfileForm, EditProfileAdminForm, ChargeForm, PaymentForm
from ..email import send_email
from .. import db
from ..models import User, Order
#PROFILE
@settings.route('/profile', methods=['GET', 'POST'])
@login_required
def profile():
page = { 'title': 'Edit Profile' }
currentmail = current_user.email
ouruser = User.query.filter_by(email=currentmail).first()
db.session.commit()
#wallet = "%.2f" % round(ouruser.wallet, 3)
#print(wallet)
form = EditProfileForm()
if form.validate_on_submit():
current_user.name = form.name.data
current_user.address = form.address.data
current_user.city = form.city.data
current_user.postcode = form.postcode.data
current_user.country = form.country.data
current_user.phone = form.phone.data
current_user.org_responsible = form.org_responsible.data
current_user.org_bulstat = form.org_bulstat.data
current_user.twofactor = form.twofactor.data
db.session.add(current_user)
db.session.commit()
flash('Info Updated!')
form.twofactor.data = current_user.twofactor
form.name.data = current_user.name
form.address.data = current_user.address
form.city.data = current_user.city
form.postcode.data = current_user.postcode
form.country.data = current_user.country
form.phone.data = current_user.phone
form.org_responsible.data = current_user.org_responsible
form.org_bulstat.data = current_user.org_bulstat
return render_template('settings/profile.html', page=page, form=form)

View file

@ -47,7 +47,7 @@
<li><a href="{{ url_for('vmanager.dashboard') }}"><span class="glyphicon glyphicon-eye-open"></span> Dashboard</a></li>
<li><a href="{{ url_for('uinvoice.documents') }}"><span class="glyphicon glyphicon-list-alt"></span> Orders</a></li>
<li role="separator" class="divider"></li>
<li><a href="{{ url_for('uinvoice.profile') }}"><span class="glyphicon glyphicon-user"></span> Profile</a></li>
<li><a href="{{ url_for('settings.profile') }}"><span class="glyphicon glyphicon-user"></span> Profile</a></li>
<li><a href="{{ url_for('auth.logout') }}"><span class="glyphicon glyphicon-off"></span> Logout</a></li>
</ul>
</li>

View file

@ -0,0 +1,10 @@
<div class="col-md-4">
<div class="panel panel-info">
<div class="panel-heading">{{ current_user.name }}</div>
<div class="panel-body">
<a href="https://en.gravatar.com/site/signup/"><img class="roundavatar" src="{{ current_user.gravatar(128) }}"></img></a><br />
2-Factor: {{ current_user.twofactor }}<br />
</div>
</div>
</div>

View file

@ -12,14 +12,14 @@
<div class="row">
{% block sidebar %}
{% include "uinvoice/_sidebar.html" %}
{% include "settings/_sidebar.html" %}
{% endblock %}
<div class="col-md-8">
<div class="panel panel-default">
<div class="panel-heading">Данни на профила</div>
<div class="panel-body">
<form method="POST" action="{{ url_for('uinvoice.profile') }}">
<form method="POST" action="{{ url_for('settings.profile') }}">
<p>
{{ form.name.label }}<br />{{ form.name(size=42) }}<br />
{% for error in form.name.errors %}

View file

@ -1,4 +1,3 @@
from iso3166 import countries
import string
import random
from ..models import User, Role
@ -8,55 +7,6 @@ from wtforms import StringField, PasswordField, BooleanField, SubmitField, Selec
from wtforms import validators, ValidationError
from wtforms.fields.html5 import EmailField
class EditProfileForm(FlaskForm):
name = StringField('Лице за контакт:', [validators.DataRequired(), validators.Length(3, 60)])
address = StringField('Адрес:', [validators.DataRequired(), validators.Length(2, 50)])
city = StringField('Град:', [validators.DataRequired(), validators.Length(2,40)])
postcode = StringField('Пощенски Код:')
clist = []
for c in countries:
clist.append((c.alpha2, c.name))
country = SelectField('Държава:', choices=clist, default='BG')
phone = StringField('Телефон:')
org_responsible = StringField('Отговорно Лице:')
org_bulstat = StringField('БУЛСТАТ:')
twofactor = BooleanField('2-factor authentication')
submit = SubmitField('Обнови')
class EditProfileAdminForm(FlaskForm):
email = StringField('Електроннa поща (логин):', [validators.DataRequired(), validators.Length(1, 64), validators.Email()])
confirmed = BooleanField('Активиран')
role = SelectField('Роля', coerce=int)
name = StringField('Лице за контакт:', [validators.DataRequired(), validators.Length(3, 60)])
address = StringField('Адрес:', [validators.DataRequired(), validators.Length(2, 50)])
city = StringField('Град:', [validators.DataRequired(), validators.Length(2,40)])
postcode = DecimalField('Пощенски Код:')
clist = []
for c in countries:
clist.append((c.alpha2, c.name))
country = SelectField('Държава:', choices=clist)
phone = DecimalField('Телефон:', [validators.DataRequired()])
org_responsible = StringField('Отговорно Лице:')
org_bulstat = StringField('БУЛСТАТ:')
submit = SubmitField('Обнови')
def __init__(self, user, *args, **kwargs):
super(EditProfileAdminForm, self).__init__(*args, **kwargs)
self.role.choices = [(role.pid, role.name)
for role in Role.query.order_by(Role.name).all()]
self.user = user
def validate_email(self, field):
if field.data != self.user.email and User.query.filter_by(email=field.data).first():
raise ValidationError('Email-а е вече регистриран.')
class ChargeForm(FlaskForm):
invoice_amount = DecimalField('Стойност:', [validators.DataRequired(), validators.NumberRange(min=0, max=6)])
submit = SubmitField('Зареди')

View file

@ -9,46 +9,6 @@ from ..email import send_email
from .. import db
from ..models import User, Order
#PROFILE
@uinvoice.route('/profile', methods=['GET', 'POST'])
@login_required
def profile():
page = { 'title': 'Edit Profile' }
currentmail = current_user.email
ouruser = User.query.filter_by(email=currentmail).first()
db.session.commit()
#wallet = "%.2f" % round(ouruser.wallet, 3)
#print(wallet)
form = EditProfileForm()
if form.validate_on_submit():
current_user.name = form.name.data
current_user.address = form.address.data
current_user.city = form.city.data
current_user.postcode = form.postcode.data
current_user.country = form.country.data
current_user.phone = form.phone.data
current_user.org_responsible = form.org_responsible.data
current_user.org_bulstat = form.org_bulstat.data
current_user.twofactor = form.twofactor.data
db.session.add(current_user)
db.session.commit()
flash('Info Updated!')
form.twofactor.data = current_user.twofactor
form.name.data = current_user.name
form.address.data = current_user.address
form.city.data = current_user.city
form.postcode.data = current_user.postcode
form.country.data = current_user.country
form.phone.data = current_user.phone
form.org_responsible.data = current_user.org_responsible
form.org_bulstat.data = current_user.org_bulstat
return render_template('uinvoice/profile.html', page=page, form=form)
#INVOICES
#@uinvoice.route('/charge', methods=['GET', 'POST'])
#@login_required