File: //home/arjun/projects/buyercall_forms/buyercall/buyercall/blueprints/partnership/views.py
import os
import csv
import sys
import traceback
import logging as log
import uuid
from buyercall.blueprints.agents import Agent
from buyercall.blueprints.filters import format_phone_number
from buyercall.lib.util_crypto import AESCipher
from flask import (
Blueprint,
make_response,
json,
flash,
render_template,
request,
redirect,
url_for,
current_app as app, jsonify
)
from flask_babel import gettext as _
from flask_babel import ngettext as _n
from flask_login import login_required, current_user, logout_user, login_user
from buyercall.lib.supervisor_manager import current_supervisor_user
from buyercall.lib.supervisor_manager import (
login_user as supervisor_login_user
)
from sqlalchemy.sql.elements import and_
from sqlalchemy import asc, desc, func, extract
from contextlib import closing
from io import StringIO
from buyercall.blueprints.user.decorators import role_required
from buyercall.blueprints.admin.forms import SearchForm, BulkDeleteForm, UserForm, UserCancelSubscriptionForm
from buyercall.blueprints.reports.models import Report, ReportUserTie
from buyercall.extensions import db
from sqlalchemy.sql import text
from buyercall.blueprints.user.models import User
from buyercall.blueprints.leads.models import Lead
from buyercall.blueprints.partnership.models import Partnership, \
PartnershipAccount, PartnershipAccountGroup, PartnershipAccountGroupTie, \
ExternalApiServiceProviders, ExternalApiServiceProvidersPartnershipAccountTie, PartnershipCpaasProviders, \
PartnershipCreditTie, PartnershipAccountCreditTie
from buyercall.blueprints.billing.models.subscription import Subscription
from buyercall.blueprints.user.decorators import anonymous_required
from wtforms import Label
from datetime import date
from datetime import datetime
import math
from buyercall.blueprints.partnership.forms import PartnershipAccountForm, PartnershipForm, \
ExternalApiServiceProvider, PartnershipTwilioApiForm, PartnershipBandwidthApiForm, PartnerFinservPrequalifyForm, \
PartnershipAccountCreateForm
from datatables import DataTables, ColumnDT
import random
import string
partnership = Blueprint('partnership', __name__, template_folder='templates')
log = log.getLogger(__name__)
@partnership.before_request
def before_request():
if request.path.find('partnership/partnership_invite') == -1:
# @login_required
if not current_user.is_authenticated:
return app.login_manager.unauthorized()
# @role_required('partner')
if current_user.role not in ['partner']:
if current_user.role == 'admin':
if not current_user.is_admin_user_with_groups:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
elif current_user.is_admin_user_with_groups and current_user.is_viewing_partnership \
and current_user.get_user_viewing_partnership_account_subscription_plan == 'partnershipsingle':
if request.path.find('company_accounts/switch_back') == -1:
return redirect(url_for('contacts.contact_list'))
elif current_user.is_admin_user_with_groups and current_user.is_viewing_partnership:
if request.path.find('company_accounts/switch_back') == -1:
return redirect(url_for('dashboard.user_dashboard'))
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
# @anonymous_required()
elif current_user.is_authenticated:
return redirect('/settings')
# Account Groups ------------------------------------------------------------------
@role_required('admin')
@partnership.route('/company_accounts/group_act_as', methods=['POST'])
def group_act_as():
if current_user.is_authenticated and current_user.is_admin_user_with_groups:
target_partnership_account = PartnershipAccount.query \
.filter(PartnershipAccount.id == int(request.form.get('account_id'))).first()
if target_partnership_account is None:
flash(_("Such Account does not exist"))
return redirect(url_for('partnership.company_accounts'))
if not User.is_in_same_group(current_user.id, target_partnership_account.id):
flash(_("You don't have access to load this account"))
return redirect(url_for('partnership.company_accounts'))
if User.set_user_viewing_partnership_account(current_user.id, target_partnership_account.id):
if current_user.get_user_viewing_partnership_account_subscription_plan == 'partnershipsingle':
return redirect(url_for('contacts.contact_list'))
else:
return redirect(url_for('dashboard.user_dashboard'))
else:
flash(_("Error loading this account"))
return redirect(url_for('partnership.company_accounts'))
else:
return redirect(url_for('user.login'))
@role_required('admin')
@partnership.route('/company_accounts')
def company_accounts():
search_form = SearchForm()
bulk_form = BulkDeleteForm()
partnership_account_groups_list = None
company_account_name = ''
if current_user.is_admin_user_with_groups and not current_user.is_viewing_partnership:
group_tie = PartnershipAccountGroup.query.filter(
and_(PartnershipAccountGroupTie.partnership_account_id == current_user.partnership_account_id,
PartnershipAccountGroupTie.partnership_account_group_id == PartnershipAccountGroup.id,
PartnershipAccountGroupTie.partnership_account_group_id == current_user.partnership_account_group_id)
).first()
company_account_name = group_tie.name
sort_by = PartnershipAccount.sort_by(request.args.get('sort', 'name'),
request.args.get('direction', 'asc'))
table = 'partnership_accounts'
order_values = '{0}.{1} {2}'.format(table, sort_by[0], sort_by[1])
if request.args.get('sort', 'name') == 'count':
table = 'partnership_accounts'
sort_by = 'count(users.partnership_account_id)', sort_by[1]
order_values = '{1} {2}'.format(table, sort_by[0], sort_by[1])
partnership_account_groups_list = PartnershipAccount \
.query \
.with_entities(PartnershipAccount.active, PartnershipAccount.id, PartnershipAccount.name) \
.filter(PartnershipAccount.search(request.args.get('q', ''))) \
.filter(and_(PartnershipAccountGroupTie.partnership_account_group_id == group_tie.id,
PartnershipAccount.id == PartnershipAccountGroupTie.partnership_account_id)) \
.all()
return render_template('company_accounts/index.jinja2',
form=search_form,
bulk_form=bulk_form,
company_account=company_account_name,
partnership_account_groups=partnership_account_groups_list)
else:
if current_user.role == 'admin':
return redirect(url_for('dashboard.user_dashboard'))
elif current_user.role == 'partner':
return redirect(url_for('partnership.accounts'))
else:
return redirect(url_for('user.settings'))
@partnership.route('/company_accounts/switch_back', methods=['GET'])
@login_required
def switch_back():
if current_user.is_admin_user_with_groups:
User.set_user_viewing_partnership_account(current_user.id, -1)
return redirect(url_for('partnership.company_accounts'))
else:
return redirect(url_for('user.settings'))
# Accounts -----------------------------------------------------------------------
@partnership.route('/accounts', defaults={'page': 1})
@partnership.route('/accounts/page/<int:page>')
@login_required
def accounts(page):
if current_user.role != 'admin':
search_form = SearchForm()
bulk_form = BulkDeleteForm()
sort_by = PartnershipAccount.sort_by(request.args.get('sort', 'name'),
request.args.get('direction', 'asc'))
table = 'partnership_accounts'
order_values = '{0}.{1} {2}'.format(table, sort_by[0], sort_by[1])
if request.args.get('sort', 'name') == 'count':
table = 'partnership_accounts'
sort_by = 'count(users.partnership_account_id)', sort_by[1]
order_values = '{1} {2}'.format(table, sort_by[0], sort_by[1])
order_query = text(order_values)
paginated_accounts = PartnershipAccount.query.with_entities(
PartnershipAccount.active,
PartnershipAccount.id,
PartnershipAccount.name,
func.count(User.partnership_account_id).label('count')
).outerjoin(
User,
and_(
User.partnership_account_id == PartnershipAccount.id,
User.partnership_account_id is not None,
User.partnership_id == current_user.partnership_id,
User.role == 'admin'
)) \
.filter(PartnershipAccount.partnership_id == current_user.partnership_id) \
.filter(PartnershipAccount.search(request.args.get('q', ''))) \
.order_by(order_query) \
.group_by(PartnershipAccount.active, PartnershipAccount.id, PartnershipAccount.name,
User.partnership_account_id) \
.paginate(page, 20, True)
# Create domain section of partner token url
token_domain = current_user.partnership.partner_url
if not token_domain:
token_domain = 'https://buyercall.com'
return render_template('accounts/index.jinja2',
form=search_form, bulk_form=bulk_form,
partnership_accounts=paginated_accounts,
domain=token_domain)
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/accounts/new-partnership-account', methods=['GET', 'POST'])
@login_required
@role_required('partner', 'sysadmin', 'limitsysadmin')
def create_new_account():
form = PartnershipAccountCreateForm()
characters = string.ascii_letters + string.digits + string.punctuation
temp_pass = ''.join(random.choice(characters) for i in range(12))
if form.validate_on_submit():
is_role_valid = False
email_set = set()
for user in form.users.data:
_role = user.get('role')
if _role in ['admin', 'agent']:
if _role == 'admin':
is_role_valid = True
else:
flash(_(f'Invalid user role: {_role}'), 'danger')
return render_template('accounts/create.jinja2', form=form)
user_email = user.get('email')
if user_email in email_set:
flash(_(f"Duplicate email address: {user_email}"), 'danger')
return render_template('accounts/create.jinja2', form=form)
email_set.add(user_email)
if User.query.filter(func.lower(User.email) == user.get('email'), User.is_deactivated == False).first():
flash(_(f"User with email address: {user['email']} already exists."), 'danger')
return render_template('accounts/create.jinja2', form=form)
if not is_role_valid:
flash(_('The account requires at least one admin user.'), 'danger')
return render_template('accounts/create.jinja2', form=form)
credit_service_provider = form.credit_service_provider.data.lower()
if credit_service_provider not in ['', 'offerlogix', '700credit']:
flash(_(f'Invalid credit service provider: {credit_service_provider}'), 'danger')
return render_template('accounts/create.jinja2', form=form)
result_is_active = form.is_active.data
result_name = form.name.data
if form.partner_account_code.data:
result_account_code = form.partner_account_code.data
else:
result_account_code = ''
partnership_account_result = PartnershipAccount.create_partial(
result_name,
current_user.partnership_id,
result_is_active,
result_account_code,
'automotive'
)
if partnership_account_result > 0:
# Create account users
for user in form.users.data:
email = user['email'].lower()
u = User.query.filter(func.lower(User.email) == email).first()
if u:
if u.is_deactivated:
u.partnership_account_id = partnership_account_result
u.partnership_id = current_user.partnership_id
u.company = form.name.data
u.is_deactivated = False
u.deactivated_on = None
db.session.commit()
else:
if 'temp_password' in user:
new_password = user['temp_password']
else:
hex_value = uuid.uuid4().hex
new_password = hex_value
new_user = User(
firstname=user['first_name'],
lastname=user['last_name'],
email=user['email'].lower(),
phonenumber=format_phone_number(str(user['mobile_number'])),
password=new_password,
role=user['role'],
partnership_account_id=partnership_account_result,
partnership_id=current_user.partnership_id,
company=form.name.data,
tos_agreement=False,
active=True,
full_feature_access=True,
inbound_routing_access=True,
outbound_routing_access=True,
forms_access=True,
external_api_access=False,
two_factor_auth=False,
)
db.session.add(new_user)
db.session.flush()
if new_user.id:
agent = Agent(
user_id=new_user.id,
firstname=new_user.firstname,
lastname=new_user.lastname,
email=new_user.email,
title=new_user.title or '',
department=new_user.department or '',
phonenumber=new_user.phonenumber,
mobile='',
extension=new_user.extension or None,
partnership_account_id=new_user.partnership_account_id
)
db.session.add(agent)
db.session.flush()
db.session.commit()
if form.credit_service_provider.data:
result_credit_sp = form.credit_service_provider.data.lower()
new_credit_sp = PartnershipAccountCreditTie(
service_provider=result_credit_sp,
active=True,
partnership_account_id=partnership_account_result,
product_type='prequalify',
equifax_enabled=True,
experian_enabled=False,
transunion_enabled=False,
)
db.session.add(new_credit_sp)
db.session.flush()
db.session.commit()
flash(_('Partnership account created successfully.'), 'success')
return redirect(url_for('partnership.accounts', page=1))
else:
flash(_('Error creating partnership account.'), 'danger')
return render_template('accounts/create.jinja2', form=form, temp_pass=temp_pass)
@partnership.route('/all_admins')
def admins():
if current_user.role != 'admin':
return redirect(url_for('partnership.accounts', page=1))
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/accounts/<int:id>')
def account_admins(id):
if current_user.role != 'admin':
search_form = SearchForm()
bulk_form = BulkDeleteForm()
sort_by = User.sort_by(request.args.get('sort', 'name'),
request.args.get('direction', 'asc'))
table = 'users'
order_values = '{0}.{1} {2}'.format(table, sort_by[0], sort_by[1])
order_query = text(order_values)
if request.args.get('sort', 'name') == 'name':
order_query = asc(User.name.expression) if sort_by[1] == 'asc' else desc(User.name.expression)
partnership_account_var = PartnershipAccount.query.get(id)
paginated_users = User.query \
.join(User.partnership) \
.join(User.partnership_account) \
.filter(User.partnership_account_id == id, User.partnership_id == current_user.partnership_id,
User.role == 'admin') \
.filter(User.search(request.args.get('q', ''))) \
.filter(User.is_deactivated.is_(False)) \
.order_by(order_query) \
.all()
return render_template('admins/index.jinja2',
form=search_form, bulk_form=bulk_form,
users=paginated_users, partnership_account=partnership_account_var)
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/account/<int:id>/edit', methods=['GET', 'POST'])
def account_edit(id):
from ..widgets.models import Widget
if current_user.role == 'partner' or (current_user.is_admin_user_with_groups
and not current_user.is_viewing_partnership):
if current_user.is_admin_user_with_groups:
if not User.is_in_same_group(current_user.id, id):
flash(_("You don't have access to load this account"), 'danger')
return redirect(url_for('partnership.company_accounts'))
# TODO: Confirm that super user can view from other partners.
partnership_account = PartnershipAccount.query.filter(
PartnershipAccount.id == id,
PartnershipAccount.partnership_id == current_user.partnership_id,
).first()
imports_allowed = partnership_account.import_leads
if partnership_account is None:
if current_user.role == 'partner':
flash(_('This account does not exist.'), 'danger')
return redirect(url_for('partnership.accounts', page=1))
else:
flash(_("This account does not exist."), 'danger')
return redirect(url_for('partnership.company_accounts'))
# Get current year, month
now = datetime.now()
year = now.year
month = now.month
previous_month = month - 1
# Total minute usage queries for an account
partnership_account_total_minutes = Lead.query.with_entities(Lead.duration) \
.filter(Lead.partnership_account_id == id).all()
new_total_duration = [i.duration for i in partnership_account_total_minutes]
total_duration_list = list()
for total in new_total_duration:
if not total:
total_zero = float(0)
total_duration_list.append(total_zero)
else:
total_float_duration = math.ceil(float(total) / 60.0)
total_duration_list.append(total_float_duration)
total_minutes = int(sum(total_duration_list))
# Current monthly minute usage queries for an account
partnership_account_month_minutes = Lead.query.with_entities(Lead.duration) \
.filter(Lead.partnership_account_id == id) \
.filter(extract('year', Lead.created_on) == year) \
.filter(extract('month', Lead.created_on) == month).all()
new_call_duration = [i.duration for i in partnership_account_month_minutes]
call_duration_list = list()
for duration in new_call_duration:
if not duration:
duration_zero = float(0)
call_duration_list.append(duration_zero)
else:
float_duration = math.ceil(float(duration) / 60.0)
call_duration_list.append(float_duration)
month_minutes = int(sum(call_duration_list))
# The previous month's minute usage
partnership_account_previous_month_minutes = Lead.query.with_entities(Lead.duration) \
.filter(Lead.partnership_account_id == id) \
.filter(extract('year', Lead.created_on) == year) \
.filter(extract('month', Lead.created_on) == previous_month).all()
previous_new_call_duration = [i.duration for i in partnership_account_previous_month_minutes]
previous_call_duration_list = list()
for previous_duration in previous_new_call_duration:
if not previous_duration:
previous_duration_zero = float(0)
previous_call_duration_list.append(previous_duration_zero)
else:
previous_float_duration = math.ceil(float(previous_duration) / 60.0)
previous_call_duration_list.append(previous_float_duration)
previous_month_minutes = int(sum(previous_call_duration_list))
# Monthly unique call count
monthly_unique_calls = Lead.query.filter(extract('month', Lead.created_on) == month) \
.filter(extract('year', Lead.created_on) == year) \
.filter(Lead.partnership_account_id == id) \
.distinct(Lead.phonenumber).count()
# Total unique call count
total_unique_calls = Lead.query.filter(Lead.partnership_account_id == id) \
.distinct(Lead.phonenumber).count()
# Total call count
total_calls = Lead.query.filter(Lead.partnership_account_id == id).count()
from buyercall.blueprints.phonenumbers.models import Phone
# Total tracking phone numbers
total_tracking_pn = Phone.query.filter(Phone.partnership_account_id == id) \
.filter(Phone.type == 'tracking', Phone.is_deactivated == '0').count()
# Total priority phone numbers
total_priority_pn = Phone.query.filter(Phone.partnership_account_id == id) \
.filter(Phone.type == 'priority', Phone.is_deactivated == '0').count()
from buyercall.blueprints.form_leads.models import FormLead
# Current month's form leads total
monthly_form_leads = FormLead.query.filter(extract('month', FormLead.created_on) == month) \
.filter(extract('year', FormLead.created_on) == year) \
.filter(FormLead.partnership_account_id == id).count()
# Previous month's form leads total
previous_month_form_leads = FormLead.query.filter(extract('month', FormLead.created_on) == previous_month) \
.filter(extract('year', FormLead.created_on) == year) \
.filter(FormLead.partnership_account_id == id).count()
# Total form leads
total_form_leads = FormLead.query.filter(FormLead.partnership_account_id == id).count()
from buyercall.blueprints.form_leads.models import ExternalForm
# Previous month's form leads total
total_forms = ExternalForm.query.filter(ExternalForm.partnership_account_id == id).count()
# Get partnership account group
selected_group = 0
partnership_account_group = PartnershipAccountGroupTie \
.query \
.filter(PartnershipAccountGroupTie.partnership_account_id == partnership_account.id).first()
# if partnership_account_group:
# selected_group = partnership_account_group.partnership_account_group_id
if partnership_account is None:
flash(_('This account does not exist.'), 'danger')
return redirect(url_for('partnership.accounts', page=1))
form = PartnershipAccountForm(obj=partnership_account)
# form.partnership_account_group_id.choices = [(g.id, g.name) for g in PartnershipAccountGroup \
# .query \
# .order_by(PartnershipAccountGroup.name.asc()) \
# .all()]
# form.partnership_account_group_id.choices.insert(0, (0, ''))
# Get external service provider
selected_external_provider_id = 0
partnership_account_provider = ExternalApiServiceProvidersPartnershipAccountTie \
.query \
.filter(ExternalApiServiceProvidersPartnershipAccountTie.partnership_account_id == partnership_account.id) \
.join(ExternalApiServiceProviders) \
.filter(ExternalApiServiceProviders.name == 'AMS 2000') \
.first()
if partnership_account_provider is not None:
encrypt_key = app.config['CRYPTO_SECRET_KEY']
cipher = AESCipher(encrypt_key)
if partnership_account_provider.username is not None and partnership_account_provider.username is not '':
decrypted_username = cipher.decrypt(partnership_account_provider.username)
if partnership_account_provider.password is not None and partnership_account_provider.password is not '':
decrypted_password = cipher.decrypt(partnership_account_provider.password)
if partnership_account_provider.secret is not None and partnership_account_provider.secret is not '':
decrypted_secret = cipher.decrypt(partnership_account_provider.secret)
external_service_provider_form = ExternalApiServiceProvider(
external_api_service_provider_id=partnership_account_provider.external_api_service_provider_id,
username=decrypted_username,
password=decrypted_password,
url=partnership_account_provider.url,
token_url=partnership_account_provider.token_url,
client_id=partnership_account_provider.client_id,
source=partnership_account_provider.source,
app_source=partnership_account_provider.app_source,
secret=decrypted_secret)
else:
external_service_provider_form = ExternalApiServiceProvider()
external_service_provider_form.external_api_service_provider_id.choices = [
(g.id, g.name) for g in ExternalApiServiceProviders.query.filter(
ExternalApiServiceProviders.name == 'AMS 2000'
).order_by(ExternalApiServiceProviders.name.asc()).all()
]
external_service_provider_form.external_api_service_provider_id.choices.insert(0, (0, ''))
if partnership_account_provider:
selected_external_provider_id = partnership_account_provider.external_api_service_provider_id
del form.billing_type
from buyercall.blueprints.form_leads.models import ExternalForm, ExternalFormField as FormField, \
ExternalFieldFieldTemplate
external_forms = ExternalForm.query.filter(ExternalForm.partnership_account_id == partnership_account.id,
ExternalForm.is_deactivated == False).all()
templates = ExternalFieldFieldTemplate.query.filter(
ExternalFieldFieldTemplate.partnership_id == current_user.partnership_id).all()
add_external_forms = request.form.get('add_external_forms', 'false')
edit_external_tab = request.form.get('edit_external_tab', 'false')
# add_external_forms = request.args.get('add_external_forms', 'false')
routings = Widget.query.filter(
Widget.partnership_account_id == id,
Widget.enabled == True # noqa
).all()
if add_external_forms == "false" and edit_external_tab == "false":
if form.validate_on_submit():
# form.populate_obj(partnership_account)
partnership_account.name = request.form.get('name')
partnership_account.partner_account_code = request.form.get('partner_account_code')
partnership_account.business_type = request.form.get('business_type')
credit_provider = request.form.get('credit_sp')
# Set the partnership account group id in the db
# form_partnership_account_group_id = request.form.get('partnership_account_group_id')
# PartnershipAccountGroupTie.update(form_partnership_account_group_id, partnership_account.id)
partnership_account.save()
if credit_provider:
credit_profile = (PartnershipAccountCreditTie.query
.filter(and_(PartnershipAccountCreditTie
.partnership_account_id == partnership_account.id,
PartnershipAccountCreditTie.service_provider == credit_provider))
.first())
if not credit_profile:
new_credit_sp = PartnershipAccountCreditTie(
service_provider=credit_provider,
active=True,
partnership_account_id=partnership_account.id,
product_type='prequalify',
equifax_enabled=True
)
db.session.add(new_credit_sp)
db.session.flush()
db.session.commit()
flash(_('Account has been saved successfully.'), 'success')
if current_user.is_admin_user_with_groups:
return redirect(url_for('partnership.company_accounts'))
else:
return redirect(url_for('partnership.accounts', page=1))
else:
pass
if edit_external_tab == "true":
external_forms_id = request.form.get('external_forms_id')
external_edit_forms = ExternalForm.query.get(external_forms_id)
else:
external_edit_forms = []
fields = FormField.query.filter(
FormField.form_id == 2
).order_by(FormField.position).all()
import re
account_name = re.sub('[^A-Za-z0-9]+', '', partnership_account.name).lower() + '@buyercall.com'
auto_email_subject = '#COMPANY# - Thank you for your submission'
body_string = '\n\nThank you for your submission\n---\n{0}\n---\n' \
.format('We are in the process of reviewing your submission for the #FORM#. '
'Once we will be in contact as soon as possible')
auto_email_body = _('Hi #NAME#,%(body)s Thanks,\n#COMPANY# support team'
'\n\n Please note this is an automated email notification. Do not reply to this email.',
body=body_string)
# This section will handle some pre-stuff for the auto sms template
from ..phonenumbers.models import Phone
phone_numbers = Phone.query \
.filter(Phone.partnership_account_id == id) \
.filter(Phone.is_deactivated == '0').all()
if phone_numbers:
active_numbers = True
else:
active_numbers = False
# Count how many active phone numbers there are for the user and update the total in total_numbers above
# Also declare the phone numbers and the friendly name for the user and add them to a list above
numbers = []
for no in phone_numbers:
number = no.phonenumber
name = no.friendly_name
inbound_id = no.id
display_name = '{} - {}'.format(name, number)
phone_info = [inbound_id, display_name]
numbers.append(phone_info)
# Look through the phone numbers for the current user and create a dictionary
phone_dict = {}
for number in numbers:
phone_dict[number[0]] = number[1]
auto_sms_body = _('#COMPANY#: Hi #NAME#, thanks for your form submission. We will review it and get back '
'to you asap.')
return render_template('accounts/edit.jinja2',
form=form,
api_form=external_service_provider_form,
account=partnership_account,
imports_allowed=imports_allowed,
selected_external_service_provider_id=selected_external_provider_id,
# selected_group_id=selected_group,
total_minutes=total_minutes,
month_minutes=month_minutes,
total_unique_calls=total_unique_calls,
monthly_unique_calls=monthly_unique_calls,
total_calls=total_calls,
total_tracking_pn=total_tracking_pn,
total_priority_pn=total_priority_pn,
monthly_form_leads=monthly_form_leads,
previous_month_form_leads=previous_month_form_leads,
total_form_leads=total_form_leads,
total_forms=total_forms,
previous_month_minutes=previous_month_minutes,
external_forms=external_forms,
add_external_forms=add_external_forms,
routings=routings,
external_edit_forms=external_edit_forms,
fields=fields,
account_name=account_name,
subject=auto_email_subject,
body=auto_email_body,
phone_options=phone_dict,
active_numbers=active_numbers,
auto_sms_body=auto_sms_body,
edit_external_tab=edit_external_tab,
templates_list=templates)
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
# This is a csv containing all partner account data
@login_required
@partnership.route('/accounts/csv', methods=['GET'])
def partner_accounts_csv():
if current_user.role != 'admin':
header = [
'#', 'id', 'name', 'active', 'created_on', 'partnership_id', 'partner_account_code', 'issues.issue_count',
'total_min_usage', 'current_month_min_usage', 'previous_month_minutes', 'total_calls', 'total_unique_calls',
'current_month_unique_calls', 'previous_month_unique_calls', 'total_active_phonenumbers',
'total_tracking_phonenumbers', 'total_priority_phonenumbers', 'total_forms', 'total_form_leads',
'current_month_form_leads', 'previous_month_form_leads'
]
params = {'partnership_id': current_user.partnership_id}
query = text("""SELECT result.id
,result.name
,result.is_active
,result.created_on
,result.partnership_id
,result.partner_account_code
,issue_count
FROM (
SELECT partnership_accounts.id
,partnership_accounts.name
,partnership_accounts.is_active
,partnership_accounts.created_on
,partnership_accounts.partnership_id
,partnership_accounts.partner_account_code
,COUNT(issues.id) AS issue_count
FROM partnership_accounts
LEFT OUTER JOIN issues ON issues.partnership_account_id = partnership_accounts.id
WHERE partnership_accounts.partnership_id = :partnership_id
GROUP BY partnership_accounts.id
) result""")
connection = db.engine.connect()
partnership_accounts = connection.execute(query, params)
# Build the CSV
row_no = 0
with closing(StringIO()) as out:
writer = csv.writer(out)
writer.writerow(header)
for account in partnership_accounts:
# Get current year, month
now = datetime.now()
year = now.year
month = now.month
previous_month = month - 1
# Get total minutes for an account
partnership_account_total_minutes = Lead.query.with_entities(Lead.duration) \
.filter(Lead.partnership_account_id == account.id).all()
# If there's more than 0 minutes round the seconds up
# to nearest minute and add them together
new_call_duration = [i.duration for i in partnership_account_total_minutes]
call_duration_list = list()
for duration in new_call_duration:
if not duration:
duration_zero = float(0)
call_duration_list.append(duration_zero)
else:
float_duration = math.ceil(float(duration) / 60.0)
call_duration_list.append(float_duration)
total_minutes = int(sum(call_duration_list))
# Get Current month minute usage for account
partnership_account_month_minutes = Lead.query.with_entities(Lead.duration) \
.filter(Lead.partnership_account_id == account.id) \
.filter(extract('year', Lead.created_on) == year) \
.filter(extract('month', Lead.created_on) == month).all()
# If there's more than 0 minutes round the seconds up
# to nearest minute and add them together
new_call_duration = [i.duration for i in partnership_account_month_minutes]
call_duration_list = list()
for duration in new_call_duration:
if not duration:
duration_zero = float(0)
call_duration_list.append(duration_zero)
else:
float_duration = math.ceil(float(duration) / 60.0)
call_duration_list.append(float_duration)
month_minutes = int(sum(call_duration_list))
# The previous month's minute usage
partnership_account_previous_month_minutes = Lead.query.with_entities(Lead.duration) \
.filter(Lead.partnership_account_id == account.id) \
.filter(extract('year', Lead.created_on) == year) \
.filter(extract('month', Lead.created_on) == previous_month).all()
previous_new_call_duration = [i.duration for i in partnership_account_previous_month_minutes]
previous_call_duration_list = list()
for previous_duration in previous_new_call_duration:
if not previous_duration:
previous_duration_zero = float(0)
previous_call_duration_list.append(previous_duration_zero)
else:
previous_float_duration = math.ceil(float(previous_duration) / 60.0)
previous_call_duration_list.append(previous_float_duration)
previous_month_minutes = int(sum(previous_call_duration_list))
# Monthly unique call count
monthly_unique_calls = Lead.query.filter(extract('month', Lead.created_on) == month) \
.filter(extract('year', Lead.created_on) == year) \
.filter(Lead.partnership_account_id == account.id) \
.distinct(Lead.phonenumber).count()
# Total unique call count
total_unique_calls = Lead.query.filter(Lead.partnership_account_id == account.id) \
.distinct(Lead.phonenumber).count()
# Total previous unique call count
previous_month_unique_calls = Lead.query.filter(Lead.partnership_account_id == account.id) \
.filter(extract('month', Lead.created_on) == previous_month) \
.filter(extract('year', Lead.created_on) == year) \
.distinct(Lead.phonenumber).count()
# Total call count
total_calls = Lead.query.filter(Lead.partnership_account_id == account.id).count()
from buyercall.blueprints.phonenumbers.models import Phone
# Total tracking phone numbers
total_tracking_pn = Phone.query.filter(Phone.partnership_account_id == account.id) \
.filter(Phone.type == 'tracking', Phone.is_deactivated == '0').count()
# Total priority phone numbers
total_priority_pn = Phone.query.filter(Phone.partnership_account_id == account.id) \
.filter(Phone.type == 'priority', Phone.is_deactivated == '0').count()
# Total active phonenumbers
total_active_pn = total_tracking_pn + total_priority_pn
from buyercall.blueprints.form_leads.models import FormLead
# Current month's form leads total
monthly_form_leads = FormLead.query.filter(extract('month', FormLead.created_on) == month) \
.filter(extract('year', FormLead.created_on) == year) \
.filter(FormLead.partnership_account_id == account.id).count()
# Previous month's form leads total
previous_month_form_leads = FormLead.query.filter(
extract('month', FormLead.created_on) == previous_month) \
.filter(extract('year', FormLead.created_on) == year) \
.filter(FormLead.partnership_account_id == account.id).count()
# Total form leads
total_form_leads = FormLead.query.filter(FormLead.partnership_account_id == account.id).count()
from buyercall.blueprints.form_leads.models import ExternalForm
# Previous month's form leads total
total_forms = ExternalForm.query.filter(ExternalForm.partnership_account_id == account.id).count()
row_no += 1
csv_row = [
row_no, account.id, account.name, account.is_active,
account.created_on, account.partnership_id, account.partner_account_code, account['issue_count'],
total_minutes, month_minutes, previous_month_minutes, total_calls, total_unique_calls,
monthly_unique_calls, previous_month_unique_calls, total_active_pn, total_tracking_pn,
total_priority_pn, total_forms, total_form_leads, monthly_form_leads, previous_month_form_leads
]
writer.writerow(csv_row)
filename = 'Partnership Accounts - Usage Report - {}.csv'.format(
date.today().strftime('%Y-%m-%d')
)
resp = make_response(out.getvalue())
resp.headers['Content-Type'] = 'text/csv'
resp.headers['Content-Disposition'] = \
'attachment; filename="{}"'.format(filename)
return resp
else:
return ''
@partnership.route('/account/<int:id>/edit/api_access', methods=['POST'])
def account_edit_api_access(id):
encrypt_key = app.config['CRYPTO_SECRET_KEY']
partnership_account = PartnershipAccount \
.query \
.filter(PartnershipAccount.id == id,
PartnershipAccount.partnership_id == current_user.partnership_id
) \
.first()
if partnership_account is not None:
api_url = request.form.get('url')
api_token_url = request.form.get('token_url')
api_client_id = request.form.get('client_id')
api_username = request.form.get('username')
api_password = request.form.get('password')
api_secret = request.form.get('secret')
api_source = request.form.get('source')
api_app_source = request.form.get('app_source')
api_external_api_service_provider_id = request.form.get('external_api_service_provider_id')
if api_username is not None and api_username is not '':
cipher = AESCipher(encrypt_key)
api_username = cipher.encrypt(api_username)
if api_password is not None and api_password is not '':
cipher = AESCipher(encrypt_key)
api_password = cipher.encrypt(api_password)
if api_secret is not None and api_secret is not '':
cipher = AESCipher(encrypt_key)
api_secret = cipher.encrypt(api_secret)
if api_external_api_service_provider_id is None or \
api_external_api_service_provider_id == '' or \
int(api_external_api_service_provider_id) <= 0:
flash(_('Error updating partnership account API details.'), 'danger')
return redirect(url_for('partnership.accounts', page=1))
try:
# api_record_exists = ExternalApiServiceProvidersPartnershipAccountTie.exists(
# partnership_account.id, api_external_api_service_provider_id)
# if int(api_record_exists) > 0 and (api_external_api_service_provider_id is None or int(
# api_external_api_service_provider_id) == 0):
# result = ExternalApiServiceProvidersPartnershipAccountTie.delete(
# api_record_exists, partnership_account.id)
#
# if result:
# flash(_('Account has been changed successfully.'), 'success')
# else:
# flash(_('Error updating partnership account API details.'), 'danger')
# return redirect(url_for('partnership.accounts', page=1))
if api_external_api_service_provider_id is not None and int(api_external_api_service_provider_id) > 0:
ExternalApiServiceProvidersPartnershipAccountTie.update(
api_external_api_service_provider_id,
partnership_account.id,
api_client_id,
api_username,
api_password,
api_url,
api_token_url,
api_source,
api_app_source,
api_secret
)
flash(_('Account has been changed successfully.'), 'success')
return redirect(url_for('partnership.accounts', page=1))
except Exception as e:
log.error('Error updating partnership account API details: {}'.format(sys.exc_info()[0]))
flash(_('Error updating partnership account API details.'), 'danger')
return redirect(url_for('partnership.accounts', page=1))
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/account/<int:id>/edit/login_access', methods=['POST'])
def account_edit_login_access(id):
if current_user.role != 'admin':
partnership_account = PartnershipAccount.query.filter(
PartnershipAccount.id == id,
PartnershipAccount.partnership_id == current_user.partnership_id
).first()
status = request.form.get('status', 'off')
if partnership_account is None:
flash(_('This account does not exist.'), 'danger')
return redirect(url_for('partnership.accounts', page=1))
status = not (True if status == 'on' else False)
db.session.query(PartnershipAccount) \
.filter(PartnershipAccount.id == id) \
.update({"active": status}, synchronize_session='fetch')
db.session.query(User) \
.filter(User.partnership_account_id == id, User.role.in_(['admin', 'agent'])) \
.update({"active": status}, synchronize_session='fetch')
db.session.commit()
flash(_('Account has been changed successfully.'), 'success')
return redirect(url_for('partnership.accounts', page=1))
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/account/<int:id>/edit/lead_import_access', methods=['POST'])
def account_edit_lead_import_access(id):
if current_user.role != 'admin':
partnership_account = PartnershipAccount.query.filter(PartnershipAccount.id == id,
PartnershipAccount.partnership_id == current_user.partnership_id,
).first()
status = request.form.get('status', 'false')
if partnership_account is None:
flash(_('This account does not exist.'), 'danger')
return redirect(url_for('partnership.accounts', page=1))
status = (True if status == 'true' else False)
db.session.query(PartnershipAccount) \
.filter(PartnershipAccount.id == id) \
.update({"import_leads": status}, synchronize_session='fetch')
db.session.commit()
flash(_('Account has been changed successfully.'), 'success')
return redirect(url_for('partnership.accounts', page=1))
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/account/<int:id>/edit/edit_twillio', methods=['POST'])
def account_edit_twillio(id):
if current_user.role != 'admin':
partnership_account = PartnershipAccount.query.filter(
PartnershipAccount.id == id,
PartnershipAccount.partnership_id == current_user.partnership_id,
).first()
status = request.form.get('status', 'off')
if partnership_account is None or partnership_account.subscription is None:
flash(_('This account does not exist.'), 'danger')
return redirect(url_for('partnership.accounts', page=1))
status = not (True if status == 'on' else False)
if status:
partnership_account.subscription.activate_twilio_account()
else:
partnership_account.subscription.suspend_twilio_account()
flash(_('Account has been changed successfully.'), 'success')
return redirect(url_for('partnership.accounts', page=1))
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/account/<int:id>/edit/close_subscription', methods=['POST'])
def account_close_subscription(id):
if current_user.role != 'admin':
partnership_account = PartnershipAccount.query.filter(
PartnershipAccount.id == id,
PartnershipAccount.partnership_id == current_user.partnership_id,
).first()
if partnership_account is None or partnership_account.subscription is None:
flash(_('This account does not exist.'), 'danger')
return redirect(url_for('partnership.accounts', page=1))
partnership_account.subscription.close_twilio_account()
flash(_('Account has been changed successfully.'), 'success')
return redirect(url_for('partnership.accounts', page=1))
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
# TODO: needs review
@partnership.route('/admins/<int:id>/edit', methods=['GET', 'POST'])
def admins_edit(id):
if current_user.role != 'admin':
user = User.query.filter(User.id == id, User.partnership_id == current_user.partnership_id,
User.role == 'admin', User.is_deactivated.is_(False)).first()
if user is None:
flash(_('This user does not exist.'), 'danger')
return redirect(url_for('partnership.admins'))
form = UserForm(obj=user)
form.role = Label('lbl_role', _('%s' % user.role))
form.role.label = {'text': 'Privileges'}
form.reports_list.choices = []
rework_reports = [(report.id, report.name) for report in Report.query.all()]
for r in rework_reports:
if r != (3, 'Partner Channel Account Report'):
form.reports_list.choices.append(r)
if form.validate_on_submit():
if User.is_last_admin(user,
'admin',
request.form.get('active')):
flash(_('This is the last admin within the account, you cannot do that.'),
'danger')
return redirect(url_for('partnership.admins_edit', id=id))
del form.role
form.populate_obj(user)
if user.username == '':
user.username = None
user.save()
user.reports = list()
# re-adding reports
for id in form.reports_list.data:
link = ReportUserTie()
link.report_id = id
link.user_id = user.id
db.session.add(link)
db.session.commit()
flash(_('User has been saved successfully.'), 'success')
return redirect(url_for('partnership.account_admins', id=user.partnership_account_id))
else:
form.reports_list.process_data([link.report.id for link in user.reports])
return render_template('admins/edit.jinja2', form=form, user=user)
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
# TODO: DISCUSS PARTNERSHIP REMOVAL LOGIC
# TODO: needs review
@partnership.route('/accounts/bulk_delete', methods=['POST'])
def accounts_bulk_delete():
if current_user.role != 'admin':
form = BulkDeleteForm()
# db.session.query(User) \
# .filter(User.partnership_id.in_(ids)) \
# .update({"active": False}, synchronize_session='fetch')
#
# # TODO: cancel subscription for all admin users
#
# db.session.query(PartnershipAccount) \
# .filter(PartnershipAccount.partnership_id.in_(ids)) \
# .update({"active": False}, synchronize_session='fetch')
if form.validate_on_submit():
ids = User.get_bulk_action_ids(request.form.get('scope'),
request.form.getlist('bulk_ids'),
omit_ids=[current_user.id],
query=request.args.get('q', ''))
# Prevent circular imports.
from buyercall.blueprints.billing.tasks import delete_users
delete_users.delay(ids)
flash(_n('%(num)d user was scheduled to be deleted.',
'%(num)d users were scheduled to be deleted.',
num=len(ids)), 'success')
else:
flash(_('No users were deleted, something went wrong.'), 'danger')
return redirect(url_for('partnership.accounts'))
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
# TODO: DISCUSS PARTNERSHIP SUBSCRIPTION LOGIC
# TODO: needs review
@partnership.route('/accounts/cancel_subscription', methods=['POST'])
def accounts_cancel_subscription():
if current_user.role != 'admin':
form = UserCancelSubscriptionForm()
if form.validate_on_submit():
user = User.query.get(request.form.get('id'))
if user:
subscription = Subscription()
if subscription.cancel(user):
flash(_('Subscription has been cancelled for %(user)s.',
user=user.name), 'success')
else:
flash(_('No subscription was cancelled, something went wrong.'),
'danger')
return redirect(url_for('partnership.accounts'))
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/accounts/act_as', methods=['POST'])
def act_as():
if current_user.role != 'admin':
s = current_supervisor_user
u = current_user
target_user = User.query.get(request.form.get('account_id'))
if target_user is None:
flash(_('Such Account does not exist'))
return redirect(url_for('partnership.accounts'))
if target_user.partnership_id != current_user.partnership_id:
flash(_("You don't have access to load this account"))
return redirect(url_for('partnership.accounts'))
if not current_supervisor_user.is_authenticated:
supervisor_login_user(u, remember=False, force=True)
logout_user()
login_user(target_user, remember=False, force=True)
return redirect(url_for('user.settings'))
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/partnership/partnership_invite', methods=['GET', 'POST'])
@anonymous_required()
def partnership_invite(reset_token=None):
from buyercall.blueprints.user.models import User
from buyercall.blueprints.partnership.forms import PartnershipSignupForm
form = PartnershipSignupForm(reset_token=request.args.get('reset_token'))
u = User.deserialize_token(form.reset_token.data)
if u is None:
flash(_('Your reset token has expired or was tampered with.'),
'danger')
return redirect(url_for('user.login'))
if form.validate_on_submit():
form.populate_obj(u)
u.password = User.encrypt_password(request.form.get('password', None))
u.save()
# save password updated date
u.save_password_updated_date()
flash(_('Successfully signed up. Please login to continue.'), 'success')
return redirect(url_for('user.login'))
partner = Partnership.query.filter(Partnership.id == u.partnership_id).first()
if partner is None:
partner_name = ''
else:
partner_name = partner.name
return render_template('partnership/signup.jinja2', form=form, user=u, partner_name=partner_name)
@partnership.route('/partnership/settings', methods=['GET', 'POST'])
def settings():
if current_user.role != 'admin':
pship = current_user.partnership
form = PartnershipForm(obj=pship)
form.logo.label.text = 'Change Logo'
del form.default_billing_type
if form.validate_on_submit():
with db.session.no_autoflush:
try:
del form.logo
form.populate_obj(pship)
if len(request.files) > 0:
file = request.files['logo']
file.seek(0, os.SEEK_END)
file_length = file.tell()
if file_length == 0:
pass
elif file_length > 1 * 1024 * 1024:
flash('Logo is too big and was not saved. Max size is 1MB', 'danger')
return render_template('partnership/settings.jinja2', form=form)
else:
file.seek(0)
folder_name = '%s_%s' % (pship.id, pship.name)
file_name = file.filename
from buyercall.blueprints.partnership.tasks import upload_partnership_logo
upload_partnership_logo(folder_name, file)
pship.logo = '%s/%s' % (folder_name, file_name)
db.session.add(pship)
db.session.flush()
db.session.commit()
return redirect(url_for('user.settings'))
except Exception as e:
form.logo = PartnershipForm(obj=pship).logo
flash(_("{}".format(e)), 'danger')
db.session.rollback()
return render_template('partnership/settings.jinja2', form=form, partnership=pship)
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/partnership/twilio_credentials', methods=['GET', 'POST'])
def twilio_credentials():
encrypt_key = app.config['CRYPTO_SECRET_KEY']
if current_user.role == 'partner':
partner = current_user.partnership
# Check and Get the twilio record for a specific partner account thats active
cpaas = PartnershipCpaasProviders.query.filter(
PartnershipCpaasProviders.partnership_id == partner.id,
PartnershipCpaasProviders.active.is_(True),
PartnershipCpaasProviders.cpaas_provider_name == 'twilio'
).first()
if cpaas is not None:
cipher = AESCipher(encrypt_key)
# Decrypt the credentials before pushing it through to the form
if cpaas.cpaas_account_id is not None and cpaas.cpaas_account_id is not '':
decrypted_username = cipher.decrypt(cpaas.cpaas_account_id)
else:
decrypted_username = ''
if cpaas.cpaas_api_token is not None and cpaas.cpaas_api_token is not '':
decrypted_token = cipher.decrypt(cpaas.cpaas_api_token)
else:
decrypted_token = ''
# Pass the descrypted and other cpaas values to the form
form = PartnershipTwilioApiForm(cpaas_account_id=decrypted_username,
cpaas_api_token=decrypted_token,
cpaas_caller_id=cpaas.cpaas_caller_id)
if form.validate_on_submit():
cipher = AESCipher(encrypt_key)
try:
# On gathering the data from the form encrypt the twilio credentials
if form.cpaas_account_id.data:
cpaas.cpaas_account_id = cipher.encrypt(form.cpaas_account_id.data)
if form.cpaas_api_token.data:
cpaas.cpaas_api_token = cipher.encrypt(form.cpaas_api_token.data)
cpaas.cpaas_caller_id = form.cpaas_caller_id.data
cpaas.save()
db.session.commit()
flash(_('The Twilio API Credentials have been updated successfully.'), 'success')
return redirect(url_for('admin.integrations'))
except Exception as e:
log.error(traceback.format_exc())
db.session.rollback()
flash(_("An error occurred while saving the Twilio API Credentials. Please contact support "
"for assistance."), 'danger')
else:
cpaas = PartnershipCpaasProviders()
form = PartnershipTwilioApiForm(obj=cpaas)
if form.validate_on_submit():
cipher = AESCipher(encrypt_key)
try:
cpaas.cpaas_provider_name = 'twilio'
cpaas.partnership_id = partner.id
if form.cpaas_account_id.data is not None and form.cpaas_account_id.data is not '':
cpaas.cpaas_account_id = cipher.encrypt(form.cpaas_account_id.data)
if form.cpaas_api_token.data is not None and form.cpaas_api_token.data is not '':
cpaas.cpaas_api_token = cipher.encrypt(form.cpaas_api_token.data)
cpaas.cpaas_caller_id = form.cpaas_caller_id.data
cpaas.save()
db.session.commit()
flash(_('The Twilio API Credentials have been updated successfully.'), 'success')
return redirect(url_for('admin.integrations'))
except Exception as e:
log.error(traceback.format_exc())
db.session.rollback()
flash(_("An error occurred while saving the Twilio API Credentials. Please contact support "
"for assistance."), 'danger')
return render_template('partnership/twilio_credentials.jinja2', form=form)
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/partnership/bandwidth_credentials', methods=['GET', 'POST'])
def bandwidth_credentials():
encrypt_key = app.config['CRYPTO_SECRET_KEY']
if current_user.role == 'partner':
partner = current_user.partnership
# Check and Get the Bandwidth record for a specific partner account thats active
cpaas = PartnershipCpaasProviders.query \
.filter(PartnershipCpaasProviders.partnership_id == partner.id,
PartnershipCpaasProviders.active.is_(True),
PartnershipCpaasProviders.cpaas_provider_name == 'bandwidth').first()
if cpaas is not None:
cipher = AESCipher(encrypt_key)
# Decrypt the credentials before pushing it through to the form
if cpaas.cpaas_user_id is not None and cpaas.cpaas_user_id is not '':
decrypted_username = cipher.decrypt(cpaas.cpaas_user_id)
else:
decrypted_username = ''
if cpaas.cpaas_api_token is not None and cpaas.cpaas_api_token is not '':
decrypted_token = cipher.decrypt(cpaas.cpaas_api_token)
else:
decrypted_token = ''
if cpaas.cpaas_api_secret is not None and cpaas.cpaas_api_secret is not '':
decrypted_secret = cipher.decrypt(cpaas.cpaas_api_secret)
else:
decrypted_secret = ''
if cpaas.cpaas_account_id is not None and cpaas.cpaas_account_id is not '':
decrypted_account = cipher.decrypt(cpaas.cpaas_account_id)
else:
decrypted_account = ''
if cpaas.cpaas_api_username is not None and cpaas.cpaas_api_username is not '':
decrypted_api_username = cipher.decrypt(cpaas.cpaas_api_username)
else:
decrypted_api_username = ''
if cpaas.cpaas_api_password is not None and cpaas.cpaas_api_password is not '':
decrypted_api_password = cipher.decrypt(cpaas.cpaas_api_password)
else:
decrypted_api_password = ''
if cpaas.cpaas_cnam_password is not None and cpaas.cpaas_cnam_password is not '':
decrypted_cnam_password = cipher.decrypt(cpaas.cpaas_cnam_password)
else:
decrypted_cnam_password = ''
# Pass the descrypted and other cpaas values to the form
form = PartnershipBandwidthApiForm(cpaas_user_id=decrypted_username,
cpaas_api_token=decrypted_token,
cpaas_api_secret=decrypted_secret,
cpaas_caller_id=cpaas.cpaas_caller_id,
cpaas_account_id=decrypted_account,
cpaas_api_username=decrypted_api_username,
cpaas_api_password=decrypted_api_password,
cpaas_site_id=cpaas.cpaas_site_id,
cpaas_location_id=cpaas.cpaas_location_id,
cpaas_sms_application_id=cpaas.cpaas_sms_application_id,
cpaas_voice_application_id=cpaas.cpaas_voice_application_id,
cpaas_cnam_password=decrypted_cnam_password)
if form.validate_on_submit():
cipher = AESCipher(encrypt_key)
try:
# On gathering the data from the form encrypt the Bandwidth credentials
if form.cpaas_user_id.data is not None and form.cpaas_user_id.data is not '':
cpaas.cpaas_user_id = cipher.encrypt(form.cpaas_user_id.data)
if form.cpaas_api_token.data is not None and form.cpaas_api_token.data is not '':
cpaas.cpaas_api_token = cipher.encrypt(form.cpaas_api_token.data)
if form.cpaas_api_secret.data is not None and form.cpaas_api_secret.data is not '':
cpaas.cpaas_api_secret = cipher.encrypt(form.cpaas_api_secret.data)
if form.cpaas_account_id.data is not None and form.cpaas_account_id.data is not '':
cpaas.cpaas_account_id = cipher.encrypt(form.cpaas_account_id.data)
if form.cpaas_api_username.data is not None and form.cpaas_api_username.data is not '':
cpaas.cpaas_api_username = cipher.encrypt(form.cpaas_api_username.data)
if form.cpaas_api_password.data is not None and form.cpaas_api_password.data is not '':
cpaas.cpaas_api_password = cipher.encrypt(form.cpaas_api_password.data)
cpaas.cpaas_site_id = form.cpaas_site_id.data
cpaas.cpaas_location_id = form.cpaas_location_id.data
cpaas.cpaas_sms_application_id = form.cpaas_sms_application_id.data
cpaas.cpaas_voice_application_id = form.cpaas_voice_application_id.data
cpaas.cpaas_caller_id = form.cpaas_caller_id.data
if form.cpaas_cnam_password.data is not None and form.cpaas_cnam_password.data is not '':
cpaas.cpaas_cnam_password = cipher.encrypt(form.cpaas_cnam_password.data)
cpaas.save()
db.session.commit()
flash(_('The Bandwidth API Credentials have been updated successfully.'), 'success')
return redirect(url_for('admin.integrations'))
except:
log.error(traceback.format_exc())
db.session.rollback()
flash(_("An error occurred while saving the Bandwidth API Credentials. Please contact support "
"for assistance."), 'danger')
else:
cpaas = PartnershipCpaasProviders()
form = PartnershipBandwidthApiForm(obj=cpaas)
if form.validate_on_submit():
cipher = AESCipher(encrypt_key)
try:
cpaas.cpaas_provider_name = 'bandwidth'
cpaas.partnership_id = partner.id
if form.cpaas_user_id.data is not None and form.cpaas_user_id.data is not '':
cpaas.cpaas_user_id = cipher.encrypt(form.cpaas_user_id.data)
if form.cpaas_api_token.data is not None and form.cpaas_api_token.data is not '':
cpaas.cpaas_api_token = cipher.encrypt(form.cpaas_api_token.data)
if form.cpaas_api_secret.data is not None and form.cpaas_api_secret.data is not '':
cpaas.cpaas_api_secret = cipher.encrypt(form.cpaas_api_secret.data)
if form.cpaas_account_id.data is not None and form.cpaas_account_id.data is not '':
cpaas.cpaas_account_id = cipher.encrypt(form.cpaas_account_id.data)
if form.cpaas_api_username.data is not None and form.cpaas_api_username.data is not '':
cpaas.cpaas_api_username = cipher.encrypt(form.cpaas_api_username.data)
if form.cpaas_api_password.data is not None and form.cpaas_api_password.data is not '':
cpaas.cpaas_api_password = cipher.encrypt(form.cpaas_api_password.data)
cpaas.cpaas_site_id = form.cpaas_site_id.data
cpaas.cpaas_location_id = form.cpaas_location_id.data
cpaas.cpaas_sms_application_id = form.cpaas_sms_application_id.data
cpaas.cpaas_voice_application_id = form.cpaas_voice_application_id.data
cpaas.cpaas_caller_id = form.cpaas_caller_id.data
if form.cpaas_cnam_password.data is not None and form.cpaas_cnam_password.data is not '':
cpaas.cpaas_cnam_password = cipher.encrypt(form.cpaas_cnam_password.data)
cpaas.save()
db.session.commit()
flash(_('The Bandwidth API Credentials have been updated successfully.'), 'success')
return redirect(url_for('admin.integrations'))
except Exception as e:
log.error(traceback.format_exc())
db.session.rollback()
flash(_("An error occurred while saving the Bandwidth API Credentials. Please contact support"
"for assistance."), 'danger')
return render_template('partnership/bandwidth_credentials.jinja2', form=form)
else:
flash(_('You do not have permission to do that.'), 'danger')
return redirect('/')
@partnership.route('/partnership/<int:pid>/finserv_prequalify_credit', methods=['POST', 'GET'])
@role_required('partner', 'sysadmin')
def partner_finserv_prequalify_credit(pid):
credit_object = PartnershipCreditTie()
form = PartnerFinservPrequalifyForm(obj=credit_object)
partner_id = pid
provider = 'Finserv'
product = 'prequalify'
credit_profile = PartnershipCreditTie.query \
.filter(and_(PartnershipCreditTie.service_provider ==
provider, PartnershipCreditTie.product_type == product,
PartnershipCreditTie.partnership_id == partner_id)).first()
if credit_profile is not None and credit_profile.product_type == 'prequalify':
encrypt_key = app.config['CRYPTO_SECRET_KEY']
cipher = AESCipher(encrypt_key)
# Decrypt the credentials before pushing it through to the form
if credit_profile.api_username is not None and credit_profile.api_username is not '':
decrypted_username = cipher.decrypt(credit_profile.api_username)
else:
decrypted_username = ''
if credit_profile.api_password is not None and credit_profile.api_password is not '':
decrypted_password = cipher.decrypt(credit_profile.api_password)
else:
decrypted_password = ''
if credit_profile.api_account is not None and credit_profile.api_account is not '':
decrypted_account = cipher.decrypt(credit_profile.api_account)
else:
decrypted_account = ''
# Pass the decrypted and other credit values to the form
form = PartnerFinservPrequalifyForm(active=credit_profile.active,
api_username=decrypted_username,
api_password=decrypted_password,
api_account=decrypted_account)
if form.validate_on_submit():
cipher = AESCipher(encrypt_key)
try:
# On gathering the data from the form encrypt the Bandwidth credentials
credit_profile.active = form.active.data
if form.api_username.data is not None and form.api_username.data is not '':
credit_profile.api_username = cipher.encrypt(form.api_username.data)
if form.api_password.data is not None and form.api_password.data is not '':
credit_profile.api_password = cipher.encrypt(form.api_password.data)
if form.api_account.data is not None and form.api_account.data is not '':
credit_profile.api_account = cipher.encrypt(form.api_account.data)
credit_profile.experian_enabled = True
credit_profile.save()
db.session.commit()
flash(_('The Finserv API Credentials have been updated successfully.'), 'success')
return redirect(url_for('admin.integrations'))
except:
log.error(traceback.format_exc())
db.session.rollback()
flash(_("An error occurred while saving the Finserv API Credentials. Please contact support "
"for assistance."), 'danger')
else:
new_partner_credit_credentials_set(credit_object, provider, product, partner_id)
return render_template('partnership/partner_finserv_prequalify_credit.jinja2', form=form)
def new_partner_credit_credentials_set(credit_object, provider, product_type, pid):
encrypt_key = app.config['CRYPTO_SECRET_KEY']
if product_type.lower() == 'prequalify' and provider == 'Finserv':
form = PartnerFinservPrequalifyForm(obj=credit_object)
else:
flash(_('The product type and credit provider mapping is not available.'), 'danger')
return redirect(url_for('admin.integrations'))
if provider == 'Finserv':
try:
if form.validate_on_submit():
cipher = AESCipher(encrypt_key)
credit_object.service_provider = provider
credit_object.active = form.active.data
credit_object.partnership_id = pid
credit_object.product_type = product_type
if form.api_username.data is not None and form.api_username.data is not '':
credit_object.api_username = cipher.encrypt(form.api_username.data)
if form.api_password.data is not None and form.api_password.data is not '':
credit_object.api_password = cipher.encrypt(form.api_password.data)
if form.api_account.data is not None and form.api_account.data is not '':
credit_object.api_account = cipher.encrypt(form.api_account.data)
credit_object.experian_enabled = True
credit_object.save()
db.session.commit()
flash(_('The Finserv API Credentials have been updated successfully.'), 'success')
return redirect(url_for('admin.integrations'))
except Exception as e:
log.error(traceback.format_exc())
log.error(e)
db.session.rollback()
flash(_("An error occurred while saving the Finserv Credentials. Please contact support"
"for assistance."), 'danger')
else:
flash(_('A service provider was not found. Please contact support for assistance.'), 'success')
return redirect(url_for('admin.integrations'))
@partnership.route('/forms-data')
@role_required('partner', 'sysadmin', 'limitsysadmin')
def forms_data():
from buyercall.blueprints.form_leads.models import ExternalForm
"""Return server side data."""
# defining columns
columns = [
ColumnDT(ExternalForm.display_name),
ColumnDT(ExternalForm.created_on),
ColumnDT(ExternalForm.updated_on)
]
filter_by = (ExternalForm.is_deactivated == True)
log.error('every: {}'.format(filter_by))
# defining the initial query depending on your purpose
query = db.session.query().select_from(ExternalForm).filter(filter_by)
# instantiating a DataTable for the query and table needed
row_table = DataTables(request.args, query, columns)
# returns what is needed by DataTable
return jsonify(row_table.output_result())
@partnership.route('/add-forms', methods=['POST'])
@role_required('partner', 'sysadmin', 'limitsysadmin')
def add_account_form():
from buyercall.blueprints.form_leads.models import ExternalForm, ExternalFormFieldDefinition, ExternalFormField, \
template_field_association
from ..widgets.models import Widget
if request.method == 'POST':
display_name = request.form.get('display_name', '')
web_form = request.form.get('web_form')
# Check the value of the web_form checkbox
if web_form == 'on':
web_form = True
public_id = request.form.get('public_id')
field_template = request.form.get('field_template')
else:
web_form = False
partnership_account_id = request.form.get('partnership_account_id')
routing = Widget.query.filter(
Widget.partnership_account_id == partnership_account_id,
Widget.id == (request.form.get('routing') or None)
).first()
conditional_notification = request.form.get('is_conditional', '')
conditions = request.form.get('condition_criteria', '')
if conditional_notification in ['true', 'True'] and conditions:
is_conditional_notification = True
else:
is_conditional_notification = False
partial_data_email = request.form.get('partial_data_email', '')
if partial_data_email == 'on':
partial_data_email = True
else:
partial_data_email = False
full_submit_email = request.form.get('full_submit_email', '')
if full_submit_email == 'on':
full_submit_email = True
else:
full_submit_email = False
send_auto_email = int(request.form.get('send_auto_email') == 'on')
send_auto_sms = int(request.form.get('send_auto_sms') == 'on')
# Create a new ExternalForm instance
form = ExternalForm(
display_name=display_name,
public_id=public_id if web_form == True else "None",
template_id=field_template if web_form == True else None,
routing=routing,
is_external_api_auto=False,
auto_prequalify_credit=False,
partnership_account_id=partnership_account_id,
is_conditional_notification=is_conditional_notification,
email_addresses={"emails": request.form.get('recipient_emails', '')},
adf_email_addresses={"emails": request.form.get('form_adf_emails', '')},
email_subject=request.form.get('email_subject', ''),
partial_data_email=partial_data_email,
full_submit_email=full_submit_email,
conditional_criteria=json.loads(conditions),
send_auto_email=send_auto_email,
send_auto_email_subject=request.form.get('auto_email_subject', ''),
send_auto_email_msg=request.form.get('auto_email_body', ''),
send_auto_sms=send_auto_sms,
send_auto_sms_inbound_id=request.form.get('phoneOptions', ''),
send_auto_sms_msg=request.form.get('auto_sms_body', ''),
)
db.session.add(form)
db.session.commit()
if web_form == True:
field_definition_ids = (
db.select([template_field_association.c.field_definition_id])
.where(template_field_association.c.external_form_field_template_id == field_template)
)
field_definition_ids = db.engine.execute(field_definition_ids).fetchall()
field_definition_ids = [result[0] for result in field_definition_ids]
for field_definition_id in field_definition_ids:
# Fetch data from the field_definition_id table
field_definition = ExternalFormFieldDefinition.query.filter_by(field_id=field_definition_id).first()
print(field_definition)
if field_definition:
# Create a new ExternalFormField instance
new_field = ExternalFormField(
form_id=form.id,
position=field_definition.position,
field_id=field_definition.old_field_id, # Assuming 'old_field_id' is what you need
display_name=field_definition.display_name,
show_in_table=field_definition.show_in_table
)
# Add the new_field instance to the session
db.session.add(new_field)
db.session.commit()
flash(_('The form has been created successfully.'), 'success')
return redirect(url_for('partnership.account_edit', id=partnership_account_id))
@partnership.route('/account/<int:id>/forms/<int:pid>/delete')
@role_required('partner', 'sysadmin', 'limitsysadmin')
def delete_account_form(id, pid):
from buyercall.blueprints.form_leads.models import ExternalForm
deactivated = ExternalForm.api_deactivate(pid, id)
if deactivated:
flash(_('The form has been deactivated successfully.'), 'success')
return redirect(url_for('partnership.account_edit', id=id))
else:
flash(_('Form deactivation failed.'), 'danger')
return redirect(url_for('partnership.account_edit', id=id))
@partnership.route('/update-forms', methods=['POST'])
@role_required('partner', 'sysadmin', 'limitsysadmin')
def update_account_form():
from buyercall.blueprints.form_leads.models import ExternalForm, ExternalFormFieldDefinition, ExternalFormField, \
template_field_association
from ..widgets.models import Widget
if request.method == 'POST':
partnership_account_id = request.form.get('partnership_account_id')
form_id = request.form.get('form_id')
form = ExternalForm.query.filter(
ExternalForm.partnership_account_id == partnership_account_id,
ExternalForm.id == form_id
).one()
web_form = request.form.get('web_form')
if web_form == 'on':
web_form = True
public_id = request.form.get('public_id')
field_template = request.form.get('field_template')
else:
web_form = False
conditional_notification = request.form.get('is_conditional', '')
conditions = request.form.get('condition_criteria', '')
auto_email_respond = request.form.get('send_auto_email', '')
if auto_email_respond == 'on':
auto_email_respond = True
else:
auto_email_respond = False
full_submit_email = request.form.get('full_submit_email', '')
if full_submit_email == 'on':
full_submit_email = True
else:
full_submit_email = False
auto_sms_respond = request.form.get('send_auto_sms', '')
if auto_sms_respond == 'on':
auto_sms_respond = True
else:
auto_sms_respond = False
partial_data_email = request.form.get('partial_data_email', '')
if partial_data_email == 'on':
partial_data_email = True
else:
partial_data_email = False
if conditional_notification in ['true', 'True'] and conditions:
form.is_conditional_notification = True
else:
form.is_conditional_notification = False
form.conditional_criteria = json.loads(conditions)
routing = Widget.query.filter(
Widget.partnership_account_id == partnership_account_id,
Widget.id == (request.form.get('routing') or None)
).first()
# Save the form to the database
form.display_name = request.form.get('display_name', '')
form.routing = routing
form.public_id = public_id if web_form == True else "None",
form.template_id = field_template if web_form == True else None,
form.email_addresses = {'emails': request.form.get('recipient_emails', '')}
form.adf_email_addresses = {'emails': request.form.get('form_adf_emails', '')}
form.email_subject = request.form.get('email_subject', '')
form.partial_data_email = partial_data_email
form.full_submit_email = full_submit_email
form.send_auto_email = auto_email_respond
form.send_auto_sms = auto_sms_respond
form.send_auto_email_subject = request.form.get('auto_email_subject', '')
form.send_auto_email_msg = request.form.get('auto_email_body', '')
form.send_auto_sms_inbound_id = request.form.get('phoneOptions', '')
form.send_auto_sms_msg = request.form.get('auto_sms_body', '')
old_fields_to_delete = ExternalFormField.query.filter_by(form_id=form.id)
if old_fields_to_delete:
for old_field in old_fields_to_delete:
db.session.delete(old_field)
db.session.commit()
if web_form == True:
field_definition_ids = (
db.select([template_field_association.c.field_definition_id])
.where(template_field_association.c.external_form_field_template_id == field_template)
)
field_definition_ids = db.engine.execute(field_definition_ids).fetchall()
field_definition_ids = [result[0] for result in field_definition_ids]
for field_definition_id in field_definition_ids:
# Fetch data from the field_definition_id table
field_definition = ExternalFormFieldDefinition.query.filter_by(field_id=field_definition_id).first()
print(field_definition)
if field_definition:
# Create a new ExternalFormField instance
new_field = ExternalFormField(
form_id=form.id,
position=field_definition.position,
field_id=field_definition.old_field_id, # Assuming 'old_field_id' is what you need
display_name=field_definition.display_name,
show_in_table=field_definition.show_in_table
)
# Add the new_field instance to the session
db.session.add(new_field)
db.session.commit()
flash(_('The form has been updated successfully.'), 'success')
return redirect(url_for('partnership.account_edit', id=partnership_account_id))