diff --git a/app/__init__.py b/app/__init__.py index d8c7e6d..f8a56ee 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -68,9 +68,6 @@ app.register_blueprint(smanager_blueprint, url_prefix='/smanager') from .dmanager import dmanager as dmanager_blueprint app.register_blueprint(dmanager_blueprint, url_prefix='/dmanager') -from .livesupport import livesupport as livesupport_blueprint -app.register_blueprint(livesupport_blueprint, url_prefix='/support') - from .uinvoice import uinvoice as uinvoice_blueprint app.register_blueprint(uinvoice_blueprint, url_prefix='/uinvoice') diff --git a/app/livesupport/__init__.py b/app/livesupport/__init__.py deleted file mode 100644 index e991060..0000000 --- a/app/livesupport/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from flask import Blueprint -livesupport = Blueprint('livesupport', __name__) -from . import routes diff --git a/app/livesupport/forms.py b/app/livesupport/forms.py deleted file mode 100644 index ee6f96f..0000000 --- a/app/livesupport/forms.py +++ /dev/null @@ -1,27 +0,0 @@ -from flask_wtf import FlaskForm -from wtforms import StringField, PasswordField, BooleanField, SubmitField, SelectField, DecimalField -from flask_pagedown.fields import PageDownField -from wtforms import validators, ValidationError -from wtforms.fields.html5 import EmailField, DecimalRangeField - -from .. import db - -class OrderForm(FlaskForm): - region_choices = [(1, 'Plovdiv, Bulgaria'), (2, 'International Space Station')] - region = SelectField('Region:', choices=region_choices, coerce=int) - - recipe_choices = [(1, 'RootVPS')] - recipe = SelectField('Type:', choices=recipe_choices, coerce=int) - - cpu = DecimalRangeField('Processor Cores', default=2) - memory = DecimalRangeField('Memory', default=2048) - storage = DecimalRangeField('Storage', default=20) - - alias = StringField('Name:', [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('DEPLOY') - -class MessageForm(FlaskForm): - line = PageDownField('Enter your message...', validators=[validators.DataRequired()]) - submit = SubmitField('Submit') - diff --git a/app/livesupport/routes.py b/app/livesupport/routes.py deleted file mode 100644 index 5f5c0e2..0000000 --- a/app/livesupport/routes.py +++ /dev/null @@ -1,83 +0,0 @@ -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 livesupport -from .forms import MessageForm -from .. import db -from ..email import send_email -from ..models import User, Permission, SupportTopic, SupportLine, contact_proxmaster - -import base64 -from datetime import date, time, datetime -from dateutil.relativedelta import relativedelta - -@livesupport.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 - -#SUPPORT -@livesupport.route("/support", methods=['GET']) -@login_required -def support_list(): - """ general enquiry and list all open support tasks """ - cuser = current_user - form = MessageForm() - - alltopics = cuser.inv_topics.all() - return render_template('livesupport/support_list.html', form=form, inv_topics=alltopics) - -@livesupport.route("/support//", methods=['GET', 'POST']) -@login_required -def support(topic): - """ block item for support chatbox. invoked from vdc_pool or supportlist """ - cuser = current_user - form = MessageForm() - - if request.method == "GET": - support_topic = SupportTopic.query.filter_by(hashtag=str(topic)).first() - if support_topic == None: - class EmptySupport(): - hashtag=str(topic) - timestamp=datetime.utcnow() - support_topic = EmptySupport() - return render_template('livesupport/support_item.html', form=form, support=support_topic) - else: - if support_topic.user_id != cuser.pid: - abort(403) #TODO: hidden 403. there is a topic like that but its not yours! - else: - #topic is yours. show it. - return render_template('livesupport/support_item.html', form=form, support=support_topic) - - if request.method == "POST" and form.validate_on_submit(): - support_topic = SupportTopic.query.filter_by(hashtag=str(topic)).first() - if support_topic == None: - #no topic. create one? - if cuser.inv_topics.all() != []: - #check if other topics exist, and ratelimit - last_topic = cuser.inv_topics.order_by(SupportTopic.timestamp.desc()).first() - now = datetime.utcnow() - time_last_topic = last_topic.timestamp - expiry = time_last_topic + relativedelta(time_last_topic, minutes=+5) - if now < expiry: - flash('ratelimit. try again later') - return redirect(url_for('livesupport.support_list')) - #create new topic - new_topic = SupportTopic(user_id=cuser.pid, hashtag=str(topic)) - db.session.add(new_topic) - new_line = SupportLine(topic_id=new_topic.pid, line=str(form.line.data)) - db.session.add(new_line) - - else: - if support_topic.user_id == cuser.pid: - new_line = SupportLine(topic_id=support_topic.pid, line=form.line.data) - db.session.add(new_line) - else: - abort(403) #TODO: hidden 404 - - db.session.commit() - return redirect(url_for('livesupport.support_list')) - diff --git a/app/models.py b/app/models.py index d731759..ce37d63 100644 --- a/app/models.py +++ b/app/models.py @@ -88,7 +88,6 @@ class User(db.Model, UserMixin): currency = db.Column(db.String, default='BGN') inv_transactions = db.relationship('Transaction', backref='owner', lazy='dynamic') inv_orders = db.relationship('Order', backref='owner', lazy='dynamic') - inv_topics = db.relationship('SupportTopic', backref='owner', lazy='dynamic') inv_servers = db.relationship('Server', backref='owner', lazy='dynamic') inv_deployments = db.relationship('Deployment', backref='owner', lazy='dynamic') @@ -99,6 +98,7 @@ class User(db.Model, UserMixin): def __init__(self, **kwargs): super(User, self).__init__(**kwargs) + if self.role is None: if self.email == current_app.config['ADMIN_EMAIL']: #if email match config admin name create admin user @@ -110,6 +110,7 @@ class User(db.Model, UserMixin): if self.avatar_hash is None and self.email is not None: self.avatar_hash = hashlib.md5(self.email.encode('utf-8')).hexdigest() + if self.otp_secret is None: # generate a random secret self.otp_secret = base64.b32encode(os.urandom(10)).decode('utf-8') @@ -283,6 +284,7 @@ class Deployment(db.Model): pid = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.ForeignKey('users.pid')) #FK server_id = db.Column(db.ForeignKey('servers.pid')) #FK + topic_id = db.Column(db.ForeignKey('support_topic.pid')) #FK date_created = db.Column(db.DateTime, default=datetime.utcnow) deleted = db.Column(db.Boolean, default=False) @@ -302,6 +304,16 @@ class Deployment(db.Model): inv_pubvlans = db.relationship('PubVLAN', backref='deploy', lazy='dynamic') + def __init__(self, **kwargs): + super(Deployment, self).__init__(**kwargs) + + if self.topic_id is None: + #create new topic + new_topic = SupportTopic(hashtag='deploy-' + query['unit_id']) + db.session.add(new_topic) + db.session.commit() + self.topic_id = new_topic.pid + class PubVLAN(db.Model): __tablename__ = 'pubvlans' pid = db.Column(db.Integer, primary_key=True) @@ -433,14 +445,15 @@ class InvoiceItem(db.Model): class SupportTopic(db.Model): __tablename__ = 'support_topic' pid = db.Column(db.Integer, primary_key=True) - user_id = db.Column(db.ForeignKey('users.pid')) #fk hashtag = db.Column(db.String) #topic timestamp = db.Column(db.DateTime(), default=datetime.utcnow) inv_lines = db.relationship('SupportLine', backref='topic', lazy='dynamic') + inv_deployments = db.relationship('Deployment', backref='topic', lazy='dynamic') class SupportLine(db.Model): __tablename__ = 'support_line' pid = db.Column(db.Integer, primary_key=True) + user_id = db.Column(db.ForeignKey('users.pid')) #FK topic_id = db.Column(db.ForeignKey('support_topic.pid')) #FK line = db.Column(db.Unicode) timestamp = db.Column(db.DateTime(), default=datetime.utcnow) diff --git a/app/panel/forms.py b/app/panel/forms.py index 56ab715..ee6f96f 100644 --- a/app/panel/forms.py +++ b/app/panel/forms.py @@ -21,4 +21,7 @@ class OrderForm(FlaskForm): submit = SubmitField('DEPLOY') +class MessageForm(FlaskForm): + line = PageDownField('Enter your message...', validators=[validators.DataRequired()]) + submit = SubmitField('Submit') diff --git a/app/panel/routes.py b/app/panel/routes.py index d8d2f57..8b5f738 100644 --- a/app/panel/routes.py +++ b/app/panel/routes.py @@ -3,10 +3,10 @@ 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 .forms import OrderForm, MessageForm from .. import db from ..email import send_email -from ..models import User, Permission, Recipe, Order, Server, Deployment, Service, Region, Address, Domain, contact_proxmaster +from ..models import User, Permission, Recipe, Order, Server, Deployment, Service, Region, Address, Domain, SupportTopic, SupportLine, contact_proxmaster import base64 from datetime import date, time, datetime @@ -99,3 +99,66 @@ def dashboard(user_pid): continue 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, warnflag=warnflag, regions=regions) + +#SUPPORT +@panel.route("/list", methods=['GET']) +@login_required +def support_list(): + """ general enquiry and list all open support tasks """ + cuser = current_user + form = MessageForm() + + alltopics = cuser.inv_topics.all() + return render_template('panel/support_list.html', form=form, inv_topics=alltopics) + +@panel.route("/topic//", methods=['GET', 'POST']) +@login_required +def support(topic): + """ block item for support chatbox. invoked from vdc_pool or supportlist """ + cuser = current_user + form = MessageForm() + + if request.method == "GET": + support_topic = SupportTopic.query.filter_by(hashtag=str(topic)).first() + if support_topic == None: + class EmptySupport(): + hashtag=str(topic) + timestamp=datetime.utcnow() + support_topic = EmptySupport() + return render_template('panel/support_item.html', form=form, support=support_topic) + else: + if support_topic.user_id != cuser.pid: + abort(403) #TODO: hidden 403. there is a topic like that but its not yours! + else: + #topic is yours. show it. + return render_template('panel/support_item.html', form=form, support=support_topic) + + if request.method == "POST" and form.validate_on_submit(): + support_topic = SupportTopic.query.filter_by(hashtag=str(topic)).first() + if support_topic == None: + #no topic. create one? + if cuser.inv_topics.all() != []: + #check if other topics exist, and ratelimit + last_topic = cuser.inv_topics.order_by(SupportTopic.timestamp.desc()).first() + now = datetime.utcnow() + time_last_topic = last_topic.timestamp + expiry = time_last_topic + relativedelta(time_last_topic, minutes=+5) + if now < expiry: + flash('ratelimit. try again later') + return redirect(url_for('panel.support_list')) + #create new topic + new_topic = SupportTopic(user_id=cuser.pid, hashtag=str(topic)) + db.session.add(new_topic) + new_line = SupportLine(topic_id=new_topic.pid, line=str(form.line.data)) + db.session.add(new_line) + + else: + if support_topic.user_id == cuser.pid: + new_line = SupportLine(topic_id=support_topic.pid, line=form.line.data) + db.session.add(new_line) + else: + abort(403) #TODO: hidden 404 + + db.session.commit() + return redirect(url_for('panel.support_list')) + diff --git a/app/templates/nav.html b/app/templates/nav.html index 93c137c..a2c2d61 100644 --- a/app/templates/nav.html +++ b/app/templates/nav.html @@ -52,7 +52,7 @@
  • Transactions
  • Profile
  • -
  • Support
  • +
  • Support
  • Logout
  • diff --git a/app/templates/livesupport/support_item.html b/app/templates/panel/support_item.html similarity index 61% rename from app/templates/livesupport/support_item.html rename to app/templates/panel/support_item.html index 391df26..e3a94f7 100644 --- a/app/templates/livesupport/support_item.html +++ b/app/templates/panel/support_item.html @@ -1,16 +1,5 @@ {% block support_item %} -{% if support.inv_lines != [] %} -
    -
      -
      -
      -
      - -
      -
      - -
      -
      +{% if support != None %}
      diff --git a/app/templates/panel/vdc_pool.html b/app/templates/panel/vdc_pool.html index 1bd19a2..9539bf0 100644 --- a/app/templates/panel/vdc_pool.html +++ b/app/templates/panel/vdc_pool.html @@ -22,6 +22,7 @@ @@ -92,7 +93,20 @@

      - +
      +

      +

      +
      +
      +

      + {% with support=deploy.discussion %} + {% include "panel/support_item.html" %} + {% endwith %} +

      +
      +
      +

      +