Best Python code snippet using playwright-python
pbx.py
Source:pbx.py  
1"""2    This Source Code Form is subject to the terms of the Mozilla Public3    License, v. 2.0. If a copy of the MPL was not distributed with this4    file, You can obtain one at http://mozilla.org/MPL/2.0/.5    Software distributed under the License is distributed on an "AS IS"6    basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the7    License for the specific language governing rights and limitations8    under the License.9    The Original Code is FreePyBX/VoiceWARE.10    The Initial Developer of the Original Code is Noel Morgan,11    Copyright (c) 2011-2012 VoiceWARE Communications, Inc. All Rights Reserved.12    http://www.vwci.com/13    You may not remove or alter the substance of any license notices (including14    copyright notices, patent notices, disclaimers of warranty, or limitations15    of liability) contained within the Source Code Form of the Covered Software,16    except that You may alter any license notices to the extent required to17    remedy known factual inaccuracies.18"""19import logging20import datetime21from datetime import datetime22from pylons import request, response, session, tmpl_context as c, url23from pylons import config24from pylons.controllers.util import abort, redirect25from freepybx.lib.base import BaseController, render26from freepybx.model import meta27from freepybx.model.meta import *28from freepybx.model.meta import Session as db29from genshi import HTML30from pylons.decorators.rest import restrict31import formencode32from formencode import validators33from freepybx.lib.pymap.imap import Pymap34from freepybx.lib.auth import *35from freepybx.lib.forms import *36from freepybx.lib.util import *37from freepybx.lib.validators import *38from decorator import decorator39from pylons.decorators import jsonify40import formencode41from formencode import validators42from pylons.decorators import validate43from simplejson import loads, dumps44import simplejson as json45import os, sys46from subprocess import call47from stat import *48import simplejson as json49from simplejson import loads, dumps50import urllib51from sqlalchemy import Date, cast, desc, asc52from sqlalchemy.orm import join53import time54import shutil55import cgi56import cgitb; cgitb.enable()57from ESL import *58import re59import csv60logged_in = IsLoggedIn()61credential = HasCredential62log = logging.getLogger(__name__)63DEBUG=False64fs_vm_dir = config['app_conf']['fs_vm_dir']65fs_dir = config['app_conf']['fs_dir']66ESL_HOST = config['app_conf']['esl_host']67ESL_PORT = config['app_conf']['esl_port']68ESL_PASS = config['app_conf']['esl_pass']69class PbxController(BaseController):70    """ This is the main controller for the config of the pbx. FreeSWITCH71        makes requests from the curl xml interface when the configuration72        is requested from FreeSWITCH."""73    def index(self):74        return "<Nothing/>"75    def sofiaconf(self):76        c.domains = []77        c.odbc_credentials = config['app_conf']['odbc_credentials']78        c.pbx_profiles = PbxProfile.query.all()79        c.pbx_gateways = PbxGateway.query.all()80        c.pbx_acl_blacklist = PbxAclBlacklist.query.all()81        for domain in PbxContext.query.filter_by(profile=c.pbx_profiles[0].name).all():82            c.domains.append(domain.domain)83        return render('xml/sofia.conf.xml')84    def switchconf(self):85        c.odbc_credentials = config['app_conf']['odbc_credentials']86        return render('xml/switch.conf.xml')87    def aclconf(self):88        c.pbx_gateways = PbxGateway.query.all()89        c.pbx_acl_blacklist = PbxAclBlacklist.query.all()90        c.odbc_credentials = config['app_conf']['odbc_credentials']91        return render('xml/switch.conf.xml')92    def callcenterconf(self):93        c.odbc_credentials = config['app_conf']['odbc_credentials']94        c.domains = []95        c.call_center_queues = []96        c.call_center_agents = []97        c.call_center_tiers = []98        try:99            for domain in PbxContext.query.distinct(PbxContext.domain).all():100                c.domains.append(domain.domain)101            for context in PbxContext.query.distinct(PbxContext.context):102                for queue in CallCenterQueue.query.filter_by(context=context.context).all():103                    c.call_center_queues.append(104                            {'name': queue.name, 'domain': queue.domain, 'moh_sound': queue.moh_sound.split(",")[1],105                             'time_base_score': queue.time_base_score,106                             'max_wait_time': queue.max_wait_time,107                             'max_wait_time_with_no_agent': queue.max_wait_time_with_no_agent,108                             'max_wait_time_with_no_agent_reached': queue.max_wait_time_with_no_agent_reached,109                             'tier_rules_apply': queue.tier_rules_apply,110                             'tier_rule_wait_second': queue.tier_rule_wait_second,111                             'tier_rule_wait_multiply_level': queue.tier_rule_wait_multiply_level,112                             'record_calls': queue.record_calls,113                             'tier_rule_agent_no_wait': queue.tier_rule_agent_no_wait,114                             'discard_abandoned_after': queue.discard_abandoned_after,115                             'abandoned_resume_allowed': queue.abandoned_resume_allowed, 'strategy': queue.strategy,116                             'announce_sound': queue.announce_sound,117                             'announce_frequency': queue.announce_frequency})118                    for agent in CallCenterAgent.query.filter_by(context=context.context).all():119                        c.call_center_agents.append({'name': agent.name, 'domain': queue.domain, 'type': agent.type,120                                                     'max_no_answer': agent.max_no_answer, 'extension': agent.extension,121                                                     'wrap_up_time': agent.wrap_up_time,122                                                     'reject_delay_time': agent.reject_delay_time,123                                                     'busy_delay_time': agent.busy_delay_time,124                                                     'timeout': agent.timeout})125                    for tier in CallCenterTier.query.all():126                        c.call_center_tiers.append({'agent': tier.agent, 'domain': queue.domain, 'queue': tier.queue,127                                                    'level': tier.level, 'position': tier.position})128        except:129            return render('xml/notfound.xml')130        return render('xml/callcenter.conf.xml')131    def cdr_pg_csvconf(self):132        return render('xml/cdr_pg_csv.conf.xml')133    def dbconf(self):134        c.odbc_credentials = config['app_conf']['odbc_credentials']135        return render('xml/db.conf.xml')136    def faxconf(self):137        return render('xml/fax.conf.xml')138    def fifoconf(self):139        c.domains=[]140        for domain in PbxContext.query.distinct(PbxContext.domain).all():141            c.domains.append(domain.domain)142        c.odbc_credentials = config['app_conf']['odbc_credentials']143        return render('xml/fifo.conf.xml')144    def presence_mapconf(self):145        c.domains = []146        for domain in PbxContext.query.filter_by(profile=c.pbx_profiles[0].name).all():147            c.domains.append(domain.domain)148        return render('xml/presence_map.conf.xml')149    def voicemailconf(self):150        c.odbc_credentials = config['app_conf']['odbc_credentials']151        c.pbx_profiles = PbxProfile.query.all()152        return render('xml/voicemail.conf.xml')153    def lcrconf(self):154        c.odbc_credentials = config['app_conf']['odbc_credentials']155        c.pbx_profiles = PbxProfile.query.all()156        return render('xml/lcr.conf.xml')157    def configuration(self, **kw):158        conf = re.sub('[^A-Za-z0-9]+', '', request.params.get('key_value', "Nothing"))159        if has_method(self, conf):160            return getattr(self, conf)()161        else:162            return render('xml/notfound.xml')163    def directory(self, **kw):164        """ The directory method is called when FreeSWITCH needs information165            about the users endpoints and for things like gateways for the 166            profile, group pointers, as well as our custom stuff like virtual167            mailbox extensions. All specific to XML. Needed for registrations 168            and XML. """169        try:170            if request.params.has_key('purpose'):171                if request.params["purpose"] == "gateways":172                    gateway = db.execute("SELECT pbx_gateways.* FROM pbx_gateways "173                                         "INNER JOIN pbx_profiles "174                                         "ON pbx_profiles.id = pbx_gateways.pbx_profile_id "175                                         "WHERE pbx_profiles.name = :profile_name",176                                         {'profile_name': str(request.params["profile"])})177                    c.gateway = {'name': str(request.params["profile"]), 'gateway': gateway}178                    db.remove()179                    return render('xml/gateways.xml')180            domain = request.params.get('domain', None)181            if not db.query(Customer.active).join(PbxContext).filter(PbxContext.domain==domain).filter(Customer.active==True).first():182                return render('xml/notfound.xml')183            c.groups = []184            c.voicemailboxes = []185            for group in PbxGroup.query.filter_by(context=domain).all():186                exts = []187                for ext in PbxGroupMember.query.filter_by(pbx_group_id=group.id).all():188                    exts.append({'ext': ext.extension})189                c.groups.append({'name': group.name, 'extensions': exts})190            for vmext in PbxVirtualMailbox.query.filter_by(context=domain).all():191                c.voicemailboxes.append({'extension': vmext.extension, 'vm_password': vmext.vm_password,192                                         'vm_attach_email': vmext.vm_attach_email, 'vm_save': vmext.vm_save,193                                         'vm_notify_email': vmext.vm_notify_email, 'vm_email': vmext.vm_email})194            if not request.params.has_key('user'):195                c.endpoints = []196                c.domain = domain197                c.endpoints = PbxEndpoint.query.filter_by(user_context = domain).all()198                return render('xml/directory.xml')199            else:200                user = request.params.get('user')201                c.domain = domain202                c.endpoints = PbxEndpoint.query.filter_by(user_context = domain).filter_by(auth_id=user).all()203                if not len(c.endpoints):204                    for vmext in PbxVirtualMailbox.query.filter_by(context=domain).all():205                        c.voicemailboxes.append({'extension': vmext.extension, 'vm_password': vmext.vm_password,206                                                 'vm_attach_email': vmext.vm_attach_email, 'vm_save': vmext.vm_save,207                                                 'vm_notify_email': vmext.vm_notify_email, 'vm_email': vmext.vm_email})208                    if c.voicemailboxes:209                        return render('xml/virtual_mailboxes.xml')210                    else:211                        return render('xml/notfound.xml')212                return render('xml/directory.xml')213        except:214            return render('xml/notfound.xml')215        finally:216            db.remove()217    def dialplan(self, **kw):218        """ This is a recursion engine that creates several objects of nested219            dictionaries and arrays and that are subsequently passed into the220            template context of pylons and interpolated into the xml template221            stream by genshi to create XML dynamically for FreeSWITCH.222            We create this for call control as well as use lua for setting223            inbound routes by context from the default context, since we are224            using only one profile for all sip traffic. Both the XML and lua225            call control are needed. It helps you be lazy and hardcode trash226            into the dialplan that you will eventually forget about.227            :param c.profile: request parameter posted from FreeSWITCH228            :type c.profile: type description229            :returns context object230            :rtype: serialized Dict231            :returns dids object232            :rtype: serialized Dict233            Renders:  ``xml/dialplan.xml``234            I'll highlight the important stuff.235            Pull all of the dids from the db to setup call control for lua236            from the default context on incoming calls from outside the switch.237            Iterate over the contexts and create objects for the xml stream engine.238            These objects are passed to dialplan.xml in the templates/xml directory.239            Retrieve all of the routes.240            Only concerned with what is needed for transfers to the xml context.241            More to do in xml with virtual extensions for things like continue on fail242            timeouts to local voicemail boxes.243            After we check and make sure that our route object is iterable,244            we grab the conditions and actions for the route. We have a template245            meta class and default set of conditions/actions for orphaned routes.246            Not really needed, but it will help you when you make mistakes your247            users will still get dialplan.248            Retrieve the route conditions and actions for the conditions.249            Serialize into context template and pass objects to xml rendering stream.250        """251        c.contexts = []252        routes =  []253        conditions = []254        actions = []255        c.profile = request.params.get('variable_sofia_profile_name','default')256        try:257            c.dids = PbxDid.query.join(Customer).filter(Customer.active==True).filter(PbxDid.active==True).all()258            for context in PbxContext.query.join(Customer).filter(Customer.active==True).distinct(PbxContext.context):259                conference_bridges = PbxConferenceBridge.query.filter_by(context=context.context).all()260                voicemailboxes = PbxVirtualMailbox.query.filter_by(context=context.context).all()261                faxes = PbxFax.query.filter_by(context=context.context).all()262                gateway = PbxGateway.query.join(PbxProfile).filter(PbxProfile.name==c.profile).first()263                for route in PbxRoute.query.filter_by(context=context.context).all():264                    ep = None265                    if route.pbx_route_type_id not in range(1,3):266                        continue267                    if route.pbx_route_type_id == 2:268                        continue269                    route_conditions = is_iter_obj(PbxCondition.query.filter_by(pbx_route_id=route.id).all())270                    if route.pbx_route_type_id == 1:271                        ep = PbxEndpoint.query.filter_by(id=route.pbx_to_id).first()272                        user = User.query.filter_by(id=ep.user_id).first()273                        rec = ep.record_inbound_calls274                    else:275                        rec = None276                    if route_conditions is not None:277                        for condition in route_conditions:278                            for action in PbxAction.query.filter_by(pbx_condition_id=condition.id).order_by(PbxAction.precedence).all():279                                actions.append({'application': action.application, 'data': action.data})280                            ds = get_findme(route.name, context.context)281                            if len(ds):282                                actions.append({'application': "set", 'data': "ignore_early_media=true"})283                            for d in ds:284                                actions.append({'application': "set", 'data': "call_timeout="+str(ep.call_timeout)})285                                actions.append({'application': "bridge", 'data': d})286                            conditions.append({'field': condition.field, 'expression': condition.expression, 'actions': actions})287                            actions  = []288                    else:289                        for action in PbxActionTmpl.query.join(PbxConditionTmpl).filter(PbxConditionTmpl.pbx_route_type_id==route.pbx_route_type_id).order_by(PbxActionTmpl.precedence).all():290                            actions.append({'application': action.application, 'data': action.data})291                        actions.append({'application': "bridge", 'data': "sofia/"+str(get_profile())+"/$1"+"%"+context.context})292                        conditions.append({'field': "destination_number", 'expression': "^("+route.name+")", 'actions': actions})293                        actions  = []294                    routes.append({'name': route.name, 'continue_route': str(route.continue_route).lower(), 'conditions': conditions, 'user_id': user.id, 'customer_id': user.customer_id,295                                   'voicemail_enabled': str(route.voicemail_enabled).lower(), 'voicemail_ext': route.voicemail_ext, 'record_inbound_calls': rec})296                    conditions = []297                c.contexts.append({'domain': context.domain, 'context': context.context, 'routes': routes, 'effective_caller_id_name': context.caller_id_name,298                                   'effective_caller_id_number': context.caller_id_number, 'origination_caller_id_name': context.caller_id_name,299                                   'origination_caller_id_number': context.caller_id_number, 'gateway': gateway.name, 'conference_bridges': conference_bridges,300                                   'voicemailboxes': voicemailboxes, 'faxes': faxes, 'recordings_dir': fs_vm_dir+context.domain+"/recordings/"})301                routes = []302            db.remove()303            return render('xml/dialplan.xml')304        except Exception, e:305            return render('xml/notfound.xml')306        finally:307            db.remove()308    def doc_pbx_json(self):309        """ Below is the JSON data called for the pbx by dojo and/or the template310            context. The json decorators do not work because postgres scary date311            objects are not serializable, so they have to be string formatted or312            worse, passed to the json encoder class and serialized by type313            reference. The encoder is imported from the lib.util.314            Lots of work needs to be done like meta class init functions for315            inserts, but as I rollout subsequent versions, stored procedures316            will eventually replace much of the way sqlalchemy handles the data317            and I prefer not to do it more than once ;p"""318    @authorize(logged_in)319    def users(self):320        items=[]321        exts = []322        for row in User.query.filter(User.customer_id==session['customer_id']).order_by(asc(User.id)).all():323            for ext in PbxEndpoint.query.filter(PbxEndpoint.user_id==row.id).filter_by(user_context=session['context']).all():324                exts.append(ext.auth_id)325            if not len(exts) > 0:326                extension = "No Extension"327            else:328                extension = ",".join(exts)329            items.append({'id': row.id, 'extension': extension, 'username': row.username, 'password': row.password, 'first_name': row.first_name, 'name': row.first_name +' '+row.last_name,330                          'last_name': row.last_name, 'address': row.address, 'address_2': row.address_2, 'city': row.city, 'state': row.state, 'zip': row.zip,331                          'tel': row.tel, 'mobile': row.mobile, 'notes': row.notes, 'created': row.created.strftime("%m/%d/%Y %I:%M:%S %p"), 'updated': row.updated.strftime("%m/%d/%Y %I:%M:%S %p"), 'active': row.active,332                          'group_id': row.group_id, 'last_login': row.last_login.strftime("%m/%d/%Y %I:%M:%S %p"), 'remote_addr': row.remote_addr, 'session_id': row.session_id, 'customer_id': row.customer_id})333            exts = []334        db.remove()335        out = dict({'identifier': 'id', 'label': 'name', 'items': items})336        response = make_response(out)337        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]338        return response(request.environ, self.start_response)339    @authorize(logged_in)340    def user_by_id(self, id, **kw):341        items=[]342        exts = []343        for row in User.query.filter(User.customer_id==session['customer_id']).filter(User.id==id).order_by(asc(User.id)).all():344            for ext in PbxEndpoint.query.filter(PbxEndpoint.user_id==row.id).all():345                exts.append(ext.auth_id)346            if not len(exts) > 0:347                extension = "No Extension"348            else:349                extension = ",".join(exts)350            items.append({'id': row.id, 'extension': extension, 'username': row.username, 'password': row.password, 'first_name': row.first_name, 'portal_extension': row.portal_extension,351                          'last_name': row.last_name, 'address': row.address, 'address_2': row.address_2, 'city': row.city, 'state': row.state, 'zip': row.zip,352                          'tel': row.tel, 'mobile': row.mobile, 'notes': row.notes, 'created': row.created.strftime("%m/%d/%Y %I:%M:%S %p"), 'updated': row.updated.strftime("%m/%d/%Y %I:%M:%S %p"), 'active': row.active,353                          'group_id': row.group_id, 'last_login': row.last_login.strftime("%m/%d/%Y %I:%M:%S %p"), 'remote_addr': row.remote_addr, 'session_id': row.session_id, 'customer_id': row.customer_id})354            exts = []355        db.remove()356        out = dict({'identifier': 'id', 'label': 'name', 'items': items})357        response = make_response(out)358        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]359        return response(request.environ, self.start_response)360    @restrict("POST")361    @authorize(logged_in)362    def add_user(self, **kw):363        schema = UserForm()364        try:365            form_result = schema.to_python(request.params)366            u = User()367            u.username = form_result.get("username")368            u.password = form_result.get("password")369            u.first_name = form_result.get("first_name")370            u.last_name = form_result.get("last_name")371            u.address = form_result.get("address")372            u.address_2 = form_result.get("address_2")373            u.city = form_result.get("city")374            u.state = form_result.get("state")375            u.zip = form_result.get("zip")376            u.tel = form_result.get("tel")377            u.mobile = form_result.get("mobile")378            u.active = form_result.get("active")379            u.customer_id = session["customer_id"]380            u.notes = form_result.get("notes")381            u.portal_extension = form_result.get("extension")382            g = Group.query.filter(Group.id==form_result.get("group_id",2)).first()383            g.users.append(u)384            db.add(g)385            db.commit(); db.flush()386            context = PbxContext.query.filter(PbxContext.customer_id==session['customer_id']).first()387            em = EmailAccount()388            e = PbxEndpoint()389            r = PbxRoute()390            c = PbxCondition()391            s = PbxAction()392            if(session['has_crm']):393                if len(form_result.get("email"))>0 and len(form_result.get("email_password"))>0 and len(form_result.get("email_server"))>0:394                    em = EmailAccount()395                    em.user_id = u.id396                    em.customer_id = session['customer_id']397                    em.email = form_result.get("email")398                    em.password = form_result.get("email_password")399                    em.mail_server = form_result.get("email_server")400                    email = form_result.get("email", None)401                    db.add(em)402                    db.commit()403                    db.flush()404            else:405                email = ""406            if request.params.has_key('extension'):407                ext = form_result.get("extension").strip()408                if ext.isdigit():409                    if (len(get_extensions(ext))>0):410                        raise Exception("Extension already exists!")411                        ext_failed = True412                    else:413                        ext_failed = False414                else:415                    ext_failed = True416            else:417                ext_failed = True418            if not ext_failed:419                e = PbxEndpoint()420                e.auth_id = form_result.get("extension")421                e.password = form_result.get("extension_password")422                e.outbound_caller_id_name = context.caller_id_name423                e.outbound_caller_id_number = context.caller_id_number424                e.internal_caller_id_name = u.first_name + ' ' + u.last_name425                e.internal_caller_id_number = form_result.get("extension")426                e.user_context = context.context427                e.force_transfer_context = context.context428                e.user_originated = u'true'429                e.toll_allow = u'domestic'430                e.call_timeout = form_result.get("call_timeout", 20)431                e.accountcode = context.caller_id_number432                e.pbx_force_contact =  form_result.get("pbx_force_contact", u'nat-connectile-dysfunction')433                e.vm_email = form_result.get("vm_email")434                e.vm_password = form_result.get("vm_password")435                e.vm_attach_email = True if form_result.get("vm_email", None) is not None else False436                e.vm_delete = False437                e.user_id = u.id438                db.add(e)439                db.commit(); db.flush()440                r = PbxRoute()441                r.context = context.context442                r.domain = context.context443                r.name = form_result.get("extension")444                r.continue_route = True445                r.voicemail_enable = True446                r.voicemail_ext = form_result.get("extension")447                r.pbx_route_type_id = 1448                r.pbx_to_id = e.id449                db.add(r)450                db.commit(); db.flush()451                con = PbxCondition()452                con.context = context.context453                con.domain = context.context454                con.field = u'destination_number'455                con.expression = u'^('+form_result.get("extension")+')$'456                con.pbx_route_id = r.id457                db.add(c)458                db.commit(); db.flush()459                s = PbxAction()460                s.pbx_condition_id = con.id461                s.context = context.context462                s.domain = context.context463                s.precedence = 1464                s.application = u'set'465                s.data = u'hangup_after_bridge=true'466                db.add(s)467                db.commit(); db.flush()468                s = PbxAction()469                s.pbx_condition_id = con.id470                s.context = context.context471                s.domain = context.context472                s.precedence = 2473                s.application = u'set'474                s.data = u'call_timeout=20'475                db.add(s)476                db.commit(); db.flush()477                s = PbxAction()478                s.pbx_condition_id = con.id479                s.context = context.context480                s.domain = context.context481                s.precedence = 3482                s.application = u'bridge'483                s.data = u'{force_transfer_context='+context.context+'}sofia/'+str(get_profile())+'/'+form_result.get("extension")+'%'+context.context484                db.add(s)485                db.commit(); db.flush()486        except validators.Invalid, error:487            db.remove()488            return 'Validation Error: %s' % error489        db.remove()490        return "Sucessfully added user."491    @restrict("POST")492    @authorize(logged_in)493    def edit_user(self, **kw):494        schema = UserEditForm()495        try:496            form_result = schema.to_python(request.params)497            u = User.query.filter(User.id==form_result.get("id")).filter(User.customer_id==session['customer_id']).first()498            if form_result.get("username") != u.username:499                if not get_usernames(str(form_result.get("username", None))):500                    u.username = form_result.get("username")501            u.password = form_result.get("password")502            u.first_name = form_result.get("first_name")503            u.last_name = form_result.get("last_name")504            u.address = form_result.get("address")505            u.address_2 = form_result.get("address_2")506            u.city = form_result.get("city")507            u.state = form_result.get("state")508            u.zip = form_result.get("zip")509            u.tel = form_result.get("tel")510            u.mobile = form_result.get("mobile")511            u.portal_extension = form_result.get('extension', 0)512            u.active = True if form_result.get("active", None) is not None else False513            u.customer_id = session["customer_id"]514            u.notes = form_result.get("notes")515            db.commit(); db.flush()516            db.execute("UPDATE user_groups SET group_id = :group_id where user_id = :user_id",\517                    {'group_id': form_result.get('group_id', 3) , 'user_id': u.id})518            db.commit(); db.flush()519            db.remove()520        except validators.Invalid, error:521            return 'Error updating user. Please contact support.'522        return "User successfully updated."523    @authorize(logged_in)524    def update_users_grid(self, **kw):525        w = loads(urllib.unquote_plus(request.params.get("data")))526        for i in w['modified']:527            u = User.query.filter_by(customer_id=session['customer_id']).filter_by(id=i['id']).first()528            u.first_name = i['first_name']529            u.last_name = i['last_name']530            u.username = i['username']531            u.password = i['password']532            db.commit(); db.flush()533            db.remove()534        return "Successfully updated users."535    @restrict("GET")536    @authorize(logged_in)537    def del_user(self, **kw):538        u = User.query.filter(User.id==request.params['id']).filter(User.customer_id==session['customer_id']).first()539        delete_extension_by_user_id(u.id)540        try:541            id = request.params['id']542            if not id.isdigit():543                raise Exception("YOUR IP: "+str(request.params["HTTP_REMOTE_DUDE"])+" INFO WAS SENT TO THE ADMIN FOR BLOCKING.")544            User.query.filter(User.id==id).filter(User.customer_id==session['customer_id']).delete()545            db.commit(); db.flush()546        except:547            db.remove()548            return "Error deleting user."549        db.remove()550        return  "Successfully deleted user."551    @authorize(logged_in)552    def extensions(self):553        items=[]554        ep_stats = []555        for endpoint in PbxEndpoint.query.filter(PbxEndpoint.user_context==session['context']).all():556            for pbx_reg in PbxRegistration.query.filter(PbxRegistration.sip_realm==session['context']).filter(PbxRegistration.sip_user==endpoint.auth_id).all():557                ep_stats.append({'ip': pbx_reg.network_ip, 'port': pbx_reg.network_port})558            is_online = True if len(ep_stats) > 0 else False559            if is_online:560                ip = ep_stats[0]["ip"]561                port = ep_stats[0]["port"]562            else:563                ip = "Unregistered"564                port = "N/A"565            for user in User.query.filter_by(id=endpoint.user_id).all():566                items.append({'id': endpoint.id, 'name': str(user.first_name)+' '+str(user.last_name), 'extension': endpoint.auth_id, 'password': endpoint.password,567                              'outbound_caller_id_name': endpoint.outbound_caller_id_name, 'outbound_caller_id_number': endpoint.outbound_caller_id_number,568                              'internal_caller_id_name': endpoint.internal_caller_id_name, 'internal_caller_id_number': endpoint.internal_caller_id_number,569                              'vm_email': endpoint.vm_email, 'vm_password': endpoint.vm_password, 'vm_save': endpoint.vm_save,'vm_attach_email': endpoint.vm_attach_email,570                              'vm_notify_email': endpoint.vm_notify_email, 'mac': endpoint.mac, 'device_type_id': endpoint.device_type_id,571                              'transfer_fallback_extension': endpoint.transfer_fallback_extension, 'is_online': is_online, 'ip': ip, 'port': port,572                              'auto_provision': endpoint.auto_provision})573            ep_stats = []574        db.remove()575        out = dict({'identifier': 'extension', 'label': 'name', 'items': items})576        response = make_response(out)577        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]578        return response(request.environ, self.start_response)579    @authorize(logged_in)580    def extension_by_id(self, id, **kw):581        items=[]582        for endpoint in PbxEndpoint.query.filter(PbxEndpoint.user_context==session['context']).filter(PbxEndpoint.id==id).all():583            for user in User.query.filter_by(id=endpoint.user_id).all():584                items.append({'id': endpoint.id, 'name': str(user.first_name)+' '+str(user.last_name), 'extension': endpoint.auth_id, 'password': endpoint.password,585                              'outbound_caller_id_name': endpoint.outbound_caller_id_name, 'outbound_caller_id_number': endpoint.outbound_caller_id_number,586                              'internal_caller_id_name': endpoint.internal_caller_id_name, 'internal_caller_id_number': endpoint.internal_caller_id_number,587                              'vm_email': endpoint.vm_email, 'vm_password': endpoint.vm_password, 'vm_attach_email': endpoint.vm_attach_email, 'vm_save': endpoint.vm_save,588                              'vm_notify_email': endpoint.vm_notify_email, 'calling_rule_id': endpoint.calling_rule_id,589                              'transfer_fallback_extension': endpoint.transfer_fallback_extension, 'find_me': endpoint.find_me, 'follow_me_1': endpoint.follow_me_1,590                              'follow_me_2': endpoint.follow_me_2, 'follow_me_3': endpoint.follow_me_3, 'follow_me_4': endpoint.follow_me_4, 'call_timeout': endpoint.call_timeout,591                              'timeout_destination': endpoint.timeout_destination, 'record_inbound_calls': endpoint.record_inbound_calls, 'record_outbound_calls': endpoint.record_outbound_calls,592                              'mac': endpoint.mac, 'device_type_id': endpoint.device_type_id, 'auto_provision': endpoint.auto_provision, 'include_xml_directory': endpoint.include_xml_directory})593        db.remove()594        out = dict({'identifier': 'extension', 'label': 'name', 'items': items})595        response = make_response(out)596        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]597        return response(request.environ, self.start_response)598    @authorize(logged_in)599    def add_extension(self):600        schema = ExtensionForm()601        msg=""602        co = Customer.query.filter(Customer.id==session['customer_id']).first()603        try:604            form_result = schema.to_python(request.params)605            e = PbxEndpoint()606            e.auth_id = form_result.get('extension')607            e.password = form_result.get('password')608            e.outbound_caller_id_name = form_result.get('outbound_caller_id_name')609            e.outbound_caller_id_number = form_result.get('outbound_caller_id_number')610            e.internal_caller_id_name = form_result.get('internal_caller_id_name')611            e.internal_caller_id_number = form_result.get('internal_caller_id_number')612            e.vm_email = form_result.get('vm_email')613            e.vm_password = form_result.get('vm_password')614            e.vm_attach_email = form_result.get('vm_attach_email')615            e.vm_notify_email = form_result.get('vm_notify_email')616            e.vm_save = form_result.get('vm_save')617            e.transfer_fallback_extension = form_result.get('transfer_fallback_extension')618            e.accountcode = co.tel619            e.follow_me_1 = form_result.get('follow_me_1')620            e.follow_me_2 = form_result.get('follow_me_2')621            e.follow_me_3 = form_result.get('follow_me_3')622            e.follow_me_4 = form_result.get('follow_me_4')623            e.call_timeout = form_result.get('call_timeout', 20)624            time_dest = form_result.get('timeout_destination')625            e.timeout_destination = time_dest if time_dest.isdigit() else None626            e.record_inbound_calls = form_result.get('record_inbound_calls', False)627            e.record_outbound_calls = form_result.get('record_outbound_calls', False)628            e.user_id = int(session['user_id'])629            e.user_context = session['context']630            e.force_transfer_context = session['context']631            e.user_originated = u'true'632            e.toll_allow = u'domestic'633            e.accountcode = co.tel634            e.calling_rule_id = form_result.get('calling_rule_id')635            e.find_me = True if form_result.get('find_me')=="true" else False636            e.auto_provision = True if form_result.get('auto_provision')=="true" else False637            e.device_type_id = form_result.get('device_type_id') if form_result.get('device_type_id') else 0638            e.include_xml_directory = True if form_result.get('include_xml_directory')=="true" else False639            e.mac = form_result.get('mac', None)640            db.add(e)641            db.commit(); db.flush()642            r = PbxRoute()643            r.context = session['context']644            r.domain = session['context']645            r.name = form_result.get("extension")646            r.continue_route = True647            r.voicemail_enable = True648            r.voicemail_ext = form_result.get("extension")649            r.pbx_route_type_id = 1650            r.pbx_to_id = e.id651            db.add(r)652            db.commit(); db.flush()653            con = PbxCondition()654            con.context = session['context']655            con.domain = session['context']656            con.field = u'destination_number'657            con.expression = u'^('+form_result.get("extension")+')$'658            con.pbx_route_id = r.id659            db.add(con)660            db.commit(); db.flush()661            s = PbxAction()662            s.pbx_condition_id = con.id663            s.context = session['context']664            s.domain = session['context']665            s.precedence = 1666            s.application = u'set'667            s.data = u'hangup_after_bridge=true'668            db.add(s)669            db.commit(); db.flush()670            s = PbxAction()671            s.pbx_condition_id = con.id672            s.context = session['context']673            s.domain = session['context']674            s.precedence = 1675            s.application = u'set'676            s.data = u'continue_on_fail=true'677            db.add(s)678            db.commit(); db.flush()679            s = PbxAction()680            s.pbx_condition_id = con.id681            s.context = session['context']682            s.domain = session['context']683            s.precedence = 2684            s.application = u'set'685            s.data = u'call_timeout='+form_result.get('call_timeout', 20)686            db.add(s)687            db.commit(); db.flush()688            s = PbxAction()689            s.pbx_condition_id = con.id690            s.context = session['context']691            s.domain = session['context']692            s.precedence = 3693            s.application = u'bridge'694            s.data = u'{force_transfer_context='+session['context']+'}sofia/'\695                     +str(get_profile())+'/'+form_result.get("extension")+'%'+session['context']696            db.add(s)697            db.commit(); db.flush()698        except validators.Invalid, error:699            db.remove()700            return 'Validation Error: %s' % error701        return "Successfully added extension %s" % form_result.get('extension')702    @restrict("POST")703    @authorize(logged_in)704    def edit_extension(self, **kw):705        schema = ExtEditForm()706        msg=""707        try:708            form_result = schema.to_python(request.params)709            e = PbxEndpoint.query.filter(PbxEndpoint.id==form_result.get('extension_id')).filter(PbxEndpoint.user_context==session['context']).first()710            e.password = form_result.get('password')711            e.outbound_caller_id_name = form_result.get('outbound_caller_id_name')712            e.outbound_caller_id_number = form_result.get('outbound_caller_id_number')713            e.internal_caller_id_name = form_result.get('internal_caller_id_name')714            e.internal_caller_id_number = form_result.get('internal_caller_id_number')715            e.vm_email = form_result.get('vm_email')716            e.vm_password = form_result.get('vm_password')717            e.vm_attach_email = True if form_result.get('vm_attach_email')=="true" else False718            e.vm_notify_email = True if form_result.get('vm_notify_email')=="true" else False719            e.vm_save = True if form_result.get('vm_save')=="true" else False720            e.transfer_fallback_extension = form_result.get('transfer_fallback_extension')721            e.follow_me_1 = form_result.get('follow_me_1')722            e.follow_me_2 = form_result.get('follow_me_2')723            e.follow_me_3 = form_result.get('follow_me_3')724            e.follow_me_4 = form_result.get('follow_me_4')725            e.call_timeout = form_result.get('call_timeout')726            time_dest = form_result.get('timeout_destination')727            e.find_me = True if form_result.get('find_me')=="true" else False728            e.timeout_destination = time_dest if time_dest.isdigit() else None729            e.record_inbound_calls = form_result.get('record_inbound_calls', False)730            e.record_outbound_calls = form_result.get('record_outbound_calls', False)731            e.auto_provision = True if form_result.get('auto_provision')=="true" else False732            e.device_type_id = form_result.get('device_type_id') if form_result.get('device_type_id') else 0733            e.include_xml_directory = True if form_result.get('include_xml_directory')=="true" else False734            e.mac = form_result.get('mac', None)735            e.calling_rule_id = form_result.get('calling_rule_id')736            db.add(e)737            db.commit(); db.flush()738            r = PbxRoute.query.filter(PbxRoute.pbx_route_type_id==1).\739            filter(PbxRoute.name==e.auth_id).filter(PbxRoute.context==session['context']).first()740            delete_conditions(r.id)741            con = PbxCondition()742            con.context = session['context']743            con.domain = session['context']744            con.field = u'destination_number'745            con.expression = u'^('+e.auth_id+')$'746            con.pbx_route_id = r.id747            db.add(con)748            db.commit(); db.flush()749            s = PbxAction()750            s.pbx_condition_id = con.id751            s.context = session['context']752            s.domain = session['context']753            s.precedence = 1754            s.application = u'set'755            s.data = u'hangup_after_bridge=true'756            db.add(s)757            db.commit(); db.flush()758            s = PbxAction()759            s.pbx_condition_id = con.id760            s.context = session['context']761            s.domain = session['context']762            s.precedence = 1763            s.application = u'set'764            s.data = u'continue_on_fail=true'765            db.add(s)766            db.commit(); db.flush()767            s = PbxAction()768            s.pbx_condition_id = con.id769            s.context = session['context']770            s.domain = session['context']771            s.precedence = 2772            s.application = u'set'773            s.data = u'call_timeout='+form_result.get('call_timeout', 20)774            db.add(s)775            db.commit(); db.flush()776            s = PbxAction()777            s.pbx_condition_id = con.id778            s.context = session['context']779            s.domain = session['context']780            s.precedence = 3781            s.application = u'bridge'782            s.data = u'{force_transfer_context='+session['context']+'}sofia/'+str(get_profile())+'/'+e.auth_id+'%'+session['context']783            db.add(s)784            db.commit(); db.flush()785            db.remove()786        except validators.Invalid, error:787            msg='Validation Error: %s' % error788        finally:789            if len(msg)>0:790                return msg791            else:792                return "Successfully edited extension %s" % e.auth_id793            db.remove()794    @authorize(logged_in)795    def update_ext_grid(self, **kw):796        w = loads(urllib.unquote_plus(request.params.get("data")))797        e = None798        for i in w['modified']:799            if i['name'].isdigit():800                id = i['name']801                u = User.query.filter(User.id==int(id)).filter_by(customer_id=session['customer_id']).first()802                e = PbxEndpoint.query.filter(PbxEndpoint.auth_id==i['extension']).filter_by(user_context=session['context']).first()803                e.user_id = u.id804            else:805                e = PbxEndpoint.query.filter(PbxEndpoint.auth_id==i['extension']).filter_by(user_context=session['context']).first()806            e.password = i['password']807            db.commit(); db.flush()808            db.remove()809        return "Successfully updated extension."810    @restrict("GET")811    @authorize(logged_in)812    def del_ext(self, **kw):813        try:814            delete_extension_by_ext(request.params['extension'])815        except:816            return "Error deleting extension."817        return  "Successfully deleted extension."818    @authorize(logged_in)819    def vextensions(self):820        items=[]821        for extension in PbxVirtualExtension.query.filter_by(context=session['context']).all():822            items.append({'id': extension.id, 'extension': extension.extension, 'did': extension.did,823                          'timeout': extension.timeout, 'pbx_route_id': extension.pbx_route_id})824        db.remove()825        out = dict({'identifier': 'id', 'label': 'extension', 'items': items})826        response = make_response(out)827        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]828        return response(request.environ, self.start_response)829    @authorize(logged_in)830    def vextension_add(self, **kw):831        schema = VirtualExtensionForm()832        try:833            form_result = schema.to_python(request.params)834            sve = PbxVirtualExtension()835            sve.extension = form_result.get('vextension_number')836            sve.did = form_result.get('vextension_did')837            sve.context = session['context']838            sve.timeout = form_result.get('timeout')839            sve.pbx_route_id = form_result.get('no_answer_destination')840            db.add(sve)841            db.commit(); db.flush()842            r = PbxRoute()843            r.context = session['context']844            r.domain = session['context']845            r.name = form_result.get('vextension_number')846            r.continue_route = True847            r.voicemail_enable = True848            r.voicemail_ext = form_result.get('vextension_number')849            r.pbx_route_type_id = 2850            r.pbx_to_id = sve.id851            db.add(r)852            db.commit(); db.flush()853        except validators.Invalid, error:854            return 'Validation Error: %s' % error855        db.remove()856        return "Successfully created virtual extension."857    @restrict("GET")858    @authorize(logged_in)859    def del_vext(self, **kw):860        try:861            delete_virtual_extension(request.params['extension'])862        except:863            return "Error deleting virtual extension."864        return  "Successfully deleted virtual extension."865    @authorize(logged_in)866    def update_vext_grid(self, **kw):867        try:868            w = loads(urllib.unquote_plus(request.params.get("data")))869            for i in w['modified']:870                if not len(i['did']) == 10 or not str(i['did']).strip().isdigit():871                    return "A virtual extension needs to be exactly 10 digits."872                ve = PbxVirtualExtension.query.filter_by(id=i['id']).filter_by(context=session['context']).first()873                ve.did = i['did']874                ve.timeout = i['timeout']875                ve.pbx_route_id = i['pbx_route_id']876                db.commit(); db.flush()877        except DataInputError, error:878            db.remove()879            return 'Error: %s' % error880        return "Successfully updated virtual extension."881    @authorize(logged_in)882    def vmboxes(self):883        items=[]884        for extension in PbxVirtualMailbox.query.filter_by(context=session['context']).all():885            items.append({'id': extension.id, 'extension': extension.extension, 'vm_password': extension.vm_password})886        db.remove()887        out = dict({'identifier': 'id', 'label': 'extension', 'items': items})888        response = make_response(out)889        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]890        return response(request.environ, self.start_response)891    @authorize(logged_in)892    def calling_rules(self):893        items=[]894        for rule in PbxCallingRule.query.all():895            items.append({'id': rule.id, 'name': rule.name})896        db.remove()897        out = dict({'identifier': 'id', 'label': 'name', 'items': items})898        response = make_response(out)899        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]900        return response(request.environ, self.start_response)901    @authorize(logged_in)902    def vmbox_by_id(self, id, **kw):903        items=[]904        extension = PbxVirtualMailbox.query.filter_by(context=session['context']).filter_by(id=id).first()905        items.append({'id': extension.id, 'extension': extension.extension, 'vm_password': extension.vm_password,906                      'skip_greeting': extension.skip_greeting, 'audio_file': extension.audio_file,907                      'vm_email': extension.vm_email, 'vm_attach_email': extension.vm_attach_email,908                      'vm_notify_email': extension.vm_notify_email, 'vm_save': extension.vm_save})909        db.remove()910        out = dict({'identifier': 'id', 'label': 'extension', 'items': items})911        response = make_response(out)912        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]913        return response(request.environ, self.start_response)914    @authorize(logged_in)915    def vmbox_edit(self, **kw):916        schema = VirtualMailboxEditForm()917        try:918            form_result = schema.to_python(request.params)919            vm = PbxVirtualMailbox.query.filter_by(id=form_result.get('vmbox_id'))\920                .filter_by(context=session['context']).first()921            vm.vm_password = form_result.get('vm_password')922            vm.context = session['context']923            vm.skip_greeting =  True if form_result.get('skip_greeting')=="true" else False924            vm.audio_file = form_result.get('audio_file', None)925            vm.vm_email = form_result.get('vm_email', None)926            vm.vm_password = form_result.get('vm_password', u'9999')927            vm.vm_attach_email = True if form_result.get('vm_attach_email')=="true" else False928            vm.vm_notify_email = True if form_result.get('vm_notify_email')=="true" else False929            vm.vm_save = True if form_result.get('vm_save')=="true" else False930            PbxRoute.query.filter_by(pbx_route_type_id=3).filter_by(pbx_to_id=vm.id).delete()931            db.commit(); db.flush()932            r = PbxRoute()933            r.context = session['context']934            r.domain = session['context']935            r.name = vm.extension936            r.continue_route = True937            r.voicemail_enable = True938            r.voicemail_ext = vm.extension939            r.pbx_route_type_id = 3940            r.pbx_to_id = vm.id941            db.add(r)942            db.commit(); db.flush()943        except validators.Invalid, error:944            return 'Validation Error: %s' % error945            db.remove()946            return "Successfully added virtual voicemail box."947    @authorize(logged_in)948    def vmbox_add(self, **kw):949        schema = VirtualMailboxForm()950        try:951            form_result = schema.to_python(request.params)952            vm = PbxVirtualMailbox()953            vm.extension = form_result.get('vmbox_number')954            vm.vm_password = form_result.get('vm_password')955            vm.context = session['context']956            vm.skip_greeting =  True if form_result.get('skip_greeting')=="true" else False957            vm.audio_file = form_result.get('audio_file', None)958            vm.vm_email = form_result.get('vm_email', None)959            vm.vm_password = form_result.get('vm_password', u'9999')960            vm.vm_attach_email = True if form_result.get('vm_attach_email')=="true" else False961            vm.vm_notify_email = True if form_result.get('vm_notify_email')=="true" else False962            vm.vm_save = True if form_result.get('vm_save')=="true" else False963            db.add(vm)964            db.commit(); db.flush()965            r = PbxRoute()966            r.context = session['context']967            r.domain = session['context']968            r.name = form_result.get('vmbox_number')969            r.continue_route = True970            r.voicemail_enable = True971            r.voicemail_ext = form_result.get('vmbox_number')972            r.pbx_route_type_id = 3973            r.pbx_to_id = vm.id974            db.add(r)975            db.commit(); db.flush()976        except validators.Invalid, error:977            return 'Validation Error: %s' % error978            db.remove()979            return "Successfully added virtual voicemail box."980    @authorize(logged_in)981    def update_vmbox_grid(self, **kw):982        try:983            w = loads(urllib.unquote_plus(request.params.get("data")))984            for i in w['modified']:985                if not str(i['extension']).strip().isdigit() or not str(i['pin']).strip().isdigit():986                    return "A virtual mailbox and pin needs to be exactly 3 or 4 numbers."987                vm = PbxVirtualMailbox.query.filter_by(id=i['id']).filter_by(context=session['context']).first()988                vm.vm_password = i['vm_password'].strip()989                db.commit(); db.flush()990                db.remove()991        except DataInputError, error:992            db.remove()993            return 'Error: %s' % error994        return "Successfully updated virtual mailbox."995    @restrict("GET")996    @authorize(logged_in)997    def del_vmbox(self, **kw):998        try:999            delete_virtual_mailbox(request.params['extension'])1000        except:1001            return "Error deleting virtual mailbox."1002        return  "Successfully deleted virtual mailbox."1003    @authorize(logged_in)1004    def groups(self):1005        items=[]; members = []1006        for group in PbxGroup.query.filter_by(context=session['context']).all():1007            for extension in PbxGroupMember.query.filter_by(pbx_group_id=group.id).all():1008                members.append(extension.extension)1009            items.append({'id': group.id, 'name': group.name, 'ring_strategy': group.ring_strategy,1010                          'no_answer_destination': group.no_answer_destination, 'members': ",".join(members),1011                          'timeout': group.timeout})1012            members = []1013        db.remove()1014        out = dict({'identifier': 'id', 'label': 'name', 'items': items})1015        response = make_response(out)1016        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1017        return response(request.environ, self.start_response)1018    @authorize(logged_in)1019    def group_by_id(self, id, **kw):1020        items=[]; members=[]1021        group = PbxGroup.query.filter_by(context=session['context']).filter_by(id=id).first()1022        for extension in PbxGroupMember.query.filter_by(pbx_group_id=group.id).all():1023            members.append(extension.extension)1024        items.append({'id': group.id, 'name': group.name, 'ring_strategy': group.ring_strategy,1025                      'no_answer_destination': group.no_answer_destination, 'members': ",".join(members),1026                      'timeout': group.timeout})1027        db.remove()1028        out = dict({'identifier': 'id', 'label': 'name', 'items': items})1029        response = make_response(out)1030        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1031        return response(request.environ, self.start_response)1032    @authorize(logged_in)1033    def group_add(self, **kw):1034        schema = GroupForm()1035        try:1036            form_result = schema.to_python(request.params)1037            if len(form_result.get('group_extensions').split(","))==1:1038                return "Error: You need to have at least two extensions to make a group."1039            sg = PbxGroup()1040            sg.name = form_result.get('group_name')1041            sg.context = session['context']1042            sg.ring_strategy = form_result.get('group_ring_strategy', 'sim')1043            sg.no_answer_destination = form_result.get('no_answer_destination', None)1044            sg.timeout = form_result.get('timeout', 13)1045            db.add(sg)1046            db.commit(); db.flush()1047            if not form_result.get('group_extensions').split(","):1048                if not form_result.get('group_extensions').isdigit():1049                    return "You need to have at least one extension to make a group."1050                else:1051                    db.add(PbxGroupMember(sg.id, form_result.get('group_extensions')))1052                    db.commit(); db.flush()1053            else:1054                for ext in form_result.get('group_extensions').split(","):1055                    if not ext.isdigit():1056                        continue1057                    db.add(PbxGroupMember(sg.id, ext))1058                    db.commit(); db.flush()1059        except validators.Invalid, error:1060            db.remove()1061            return 'Validation Error: %s' % error1062        r = PbxRoute()1063        r.context = session['context']1064        r.domain = session['context']1065        r.name = form_result.get('group_name')1066        r.continue_route = True1067        r.voicemail_enable = True1068        r.voicemail_ext = form_result.get('group_name')1069        r.pbx_route_type_id = 41070        r.pbx_to_id = sg.id1071        db.add(r)1072        db.commit(); db.flush()1073        db.remove()1074        return "Successfully added group "+str(form_result.get('group_name'))+"."1075    @authorize(logged_in)1076    def group_edit(self, **kw):1077        schema = GroupEditForm()1078        try:1079            form_result = schema.to_python(request.params)1080            if len(form_result.get('group_extensions').split(","))==1:1081                return "Error: You need to have at least two extensions to make a group."1082            db.delete(PbxGroup.query.filter_by(id=form_result.get('group_id')).first())1083            for member in PbxGroupMember.query.filter_by(pbx_group_id=form_result.get('group_id')).all():1084                db.delete(member)1085            db.delete(PbxRoute.query.filter_by(pbx_route_type_id=4).filter_by(pbx_to_id=form_result.get('group_id')).first())1086            db.commit(); db.flush()1087            sg = PbxGroup()1088            sg.name = form_result.get('group_name')1089            sg.context = session['context']1090            sg.ring_strategy = form_result.get('group_ring_strategy', 'sim')1091            sg.no_answer_destination = form_result.get('no_answer_destination', None)1092            sg.timeout = form_result.get('timeout', 13)1093            db.add(sg)1094            db.commit(); db.flush()1095            if not form_result.get('group_extensions').split(","):1096                if not form_result.get('group_extensions').isdigit():1097                    return "You need to have at least one extension to make a group."1098                else:1099                    db.add(PbxGroupMember(sg.id, form_result.get('group_extensions')))1100                    db.commit()1101                    db.flush()1102            else:1103                for ext in form_result.get('group_extensions').split(","):1104                    if not ext.isdigit():1105                        continue1106                    db.add(PbxGroupMember(sg.id, ext))1107                    db.commit()1108                    db.flush()1109        except validators.Invalid, error:1110            db.remove()1111            return 'Validation Error: %s' % error1112        r = PbxRoute()1113        r.context = session['context']1114        r.domain = session['context']1115        r.name = form_result.get('group_name')1116        r.continue_route = True1117        r.voicemail_enable = True1118        r.voicemail_ext = form_result.get('group_name')1119        r.pbx_route_type_id = 41120        r.pbx_to_id = sg.id1121        db.add(r)1122        db.commit(); db.flush()1123        db.remove()1124        return "Successfully added group "+str(form_result.get('group_name'))+"."1125    @authorize(logged_in)1126    def update_group_grid(self, **kw):1127        w = loads(urllib.unquote_plus(request.params.get("data")))1128        try:1129            for i in w['modified']:1130                g = PbxGroup.query.filter_by(id=i['id']).first()1131                g.no_answer_destination = i['no_answer_destination']1132                g.ring_strategy = i['ring_strategy']1133                db.commit(); db.flush()1134                PbxGroupMember.query.filter(PbxGroupMember.pbx_group_id==i['id']).delete()1135                for gm in i['members'].split(","):1136                    if not gm.strip().isdigit():1137                        continue1138                    db.add(PbxGroupMember(i['id'], gm.strip()))1139                    db.commit()1140                    db.flush()1141        except:1142            db.remove()1143            return "Error updating group."1144        return "Successfully updated group."1145    @restrict("GET")1146    @authorize(logged_in)1147    def del_group(self, **kw):1148        try:1149            delete_group(request.params['name'])1150        except:1151            return "Error"1152        return  "Successfully deleted group."1153    @authorize(logged_in)1154    def dids(self):1155        items=[]1156        for did in PbxDid.query.filter_by(context=session['context']).all():1157            route = db.query(PbxRoute.id, PbxRouteType.name, PbxRoute.name)\1158            .join(PbxRouteType).filter(PbxRoute.context==session['context']).filter(PbxRoute.id==did.pbx_route_id).first()1159            if route:1160                items.append({'id': did.id, 'did': did.did, 'route_name': route[1]+': '+route[2], 'pbx_route_id': route.id})1161            else:1162                items.append({'id': did.id, 'did': did.did, 'route_name': "Broken Route!", 'pbx_route_id': 0})1163        lbid = get_route_labels_ids()1164        db.remove()1165        out = dict({'identifier': 'id', 'label': 'name', 'items': items,'did_labels': lbid[0], 'did_ids': lbid[1]})1166        response = make_response(out)1167        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1168        return response(request.environ, self.start_response)1169    @authorize(logged_in)1170    def update_did_grid(self, **kw):1171        w = loads(urllib.unquote_plus(request.params.get("data")))1172        try:1173            for i in w['modified']:1174                sd = PbxDid.query.filter_by(id=i['id']).filter_by(context=session['context']).first()1175                sd.pbx_route_id = i['route_name']1176                db.commit()1177                db.commit(); db.flush()1178        except:1179            db.remove()1180            return "Error updating DID."1181        return "Successfully updated DID."1182    @authorize(logged_in)1183    def faxes(self):1184        files = []1185        dir = fs_vm_dir+session['context']+"/faxes"1186        try:1187            for i in os.listdir(dir):1188                if not i.endswith(".png"):1189                    continue1190                path = dir+"/"+i1191                uuid = i.split("_")[0].strip()1192                name = i.split("_")[1].strip().split(".")[0]1193                if name.find("-") == -1:1194                    page_num = "Single Page"1195                else:1196                    page_num = name.split("-")[1].split(".")[0].strip()1197                    name = name.split("-")[0].strip()1198                    page_num = int(page_num)+11199                tpath = "/vm/" +session['context']+"/faxes/"+i1200                received = str(modification_date(path)).strip("\"")1201                fsize = str(os.path.getsize(path))1202                row = PbxCdr.query.filter(PbxCdr.uuid==uuid).first()1203                if row:1204                    caller = row.caller_id_number[len(row.caller_id_number)-10:]1205                else:1206                    caller = "Unknown"1207                files.append({'uuid': uuid, 'name': name, 'caller_id': caller, 'path': tpath, 'received': received, 'size': fsize, 'page_num': page_num})1208        except:1209            os.makedirs(dir)1210        db.remove()1211        out = dict({'identifier': 'path', 'label': 'name', 'items': files})1212        response = make_response(out)1213        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1214        return response(request.environ, self.start_response)1215    @authorize(logged_in)1216    def fax_add(self, **kw):1217        schema = FaxForm()1218        try:1219            form_result = schema.to_python(request.params)1220            sf = PbxFax()1221            sf.extension = form_result.get('fax_name')1222            sf.context = session['context']1223            db.add(sf)1224            db.commit(); db.flush()1225            r = PbxRoute()1226            r.context = session['context']1227            r.domain = session['context']1228            r.name = form_result.get('fax_name')1229            r.continue_route = False1230            r.voicemail_enable = False1231            r.voicemail_ext = form_result.get('fax_name')1232            r.pbx_route_type_id = 121233            r.pbx_to_id = sf.id1234            db.add(r)1235            db.commit(); db.flush()1236        except validators.Invalid, error:1237            db.remove()1238            return 'Validation Error: Please correct form inputs and resubmit.'1239    @authorize(logged_in)1240    def fax_ext(self):1241        items=[]1242        for ext in PbxFax.query.filter_by(context=session['context']).all():1243            items.append({'id': ext.id, 'extension': ext.extension})1244        db.remove()1245        out = dict({'identifier': 'id', 'label': 'extension', 'items': items})1246        response = make_response(out)1247        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1248        return response(request.environ, self.start_response)1249    @authorize(logged_in)1250    def fax_send(self, **kw):1251        form = cgi.FieldStorage()1252        user = User.query.filter_by(session_id=session.id).first()1253        if not user:1254            return1255        ep = db.execute("SELECT pbx_dids.did FROM pbx_dids "1256                        "INNER JOIN pbx_routes on pbx_dids.pbx_route_id = pbx_routes.id "1257                        "WHERE pbx_routes.pbx_route_type_id=12").fetchone()1258        if ep:1259            if len(ep[0])==10:1260                origination_caller_id_number = ep[0]1261            else:1262                origination_caller_id_number = ep[1]1263        else:1264            origination_caller_id_number = "0000000000"1265        myfile = request.params['uploadedfiles[]']1266        fname = myfile.filename.lstrip(os.sep)1267        ext = fname.split(".")[len(fname.split("."))-1]1268        if not ext:1269            return  "Error no file type found."1270        fname = re.sub('[^A-Za-z0-9]+', '', fname)1271        fname = fname+"."+ext1272        try:1273            dir = "/tmp/"1274            permanent_file = open(os.path.join(dir,fname), 'w')1275            shutil.copyfileobj(myfile.file, permanent_file)1276            myfile.file.close()1277            permanent_file.close()1278        except:1279            return "Error uploading file. The administrator has been contacted."1280        converted = fname.split(".")[0]+".tiff"1281        call("convert -density 204x98 -units PixelsPerInch -resize 1728x1186\! -monochrome -compress Fax /tmp/"+fname+" /tmp/"+converted, shell=True)1282        os.remove("/tmp/"+fname)1283        con = ESLconnection(ESL_HOST, ESL_PORT, ESL_PASS)1284        if con.connected:1285            con.bgapi("originate", "{fax_ident='FreePyBX Web Fax',fax_header="+str(origination_caller_id_number)+",fax_enable_t38=true,origination_caller_id_number="+str(origination_caller_id_number)+"}sofia/gateway/voipinnovations/"+str(request.params["fax_recipient"])+" &txfax(/tmp/"+str(converted)+")")1286    @restrict("GET")1287    @authorize(logged_in)1288    def del_fax(self, **kw):1289        """For security, we check the input, then put them into their own context"""1290        file_name = request.params['name'].split("/")[len(request.params['name'].split("/"))-1]1291        try:1292            dir = fs_vm_dir+session['context']+"/faxes/"+file_name1293            os.remove(dir)1294        except:1295            return "Error deleting fax."1296        return "Deleted fax."1297    @authorize(logged_in)1298    def del_fax_ext(self, **kw):1299        try:1300            delete_fax_ext(request.params['name'])1301        except:1302            return "Error deleting fax extension."1303        return  "Successfully deleted fax extension."1304    @authorize(logged_in)1305    def tod_routes(self):1306        items=[]1307        for tod in PbxTODRoute.query.filter_by(context=session['context']).all():1308            route_match = db.query(PbxRoute.id, PbxRouteType.name, PbxRoute.name)\1309            .join(PbxRouteType).filter(PbxRoute.context==session['context']).filter(PbxRoute.id==tod.match_route_id).first()1310            route_nomatch = db.query(PbxRoute.id, PbxRouteType.name, PbxRoute.name)\1311            .join(PbxRouteType).filter(PbxRoute.context==session['context']).filter(PbxRoute.id==tod.nomatch_route_id).first()1312            items.append({'id': tod.id, 'name': tod.name, 'day_start': tod.day_start, 'day_end': tod.day_end, 'time_start': tod.time_start[1:len(tod.time_start)-3], 'time_end': tod.time_end[1:len(tod.time_end)-3],1313                          'match_route_id': tod.match_route_id, 'nomatch_route_id': tod.nomatch_route_id, 'match_name': route_match[1]+': '+route_match[2],1314                          'match_id': route_match[0], 'nomatch_name': route_nomatch[1]+': '+route_nomatch[2], 'nomatch_id': route_nomatch[0]})1315        db.remove()1316        out = dict({'identifier': 'id', 'label': 'extension', 'items': items})1317        response = make_response(out)1318        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1319        return response(request.environ, self.start_response)1320    @authorize(logged_in)1321    def tod_route_add(self, **kw):1322        schema = TODForm()1323        try:1324            form_result = schema.to_python(request.params)1325            t = PbxTODRoute()1326            t.domain = session['context']1327            t.context = session['context']1328            t.name = form_result.get('name')1329            t.day_start = form_result.get('day_start')1330            t.day_end = form_result.get('day_end')1331            t.time_start = form_result.get('time_start')1332            t.time_end = form_result.get('time_end')1333            t.match_route_id = form_result.get('match_route_id')1334            t.nomatch_route_id = form_result.get('nomatch_route_id')1335            db.add(t)1336            db.commit(); db.flush()1337            r = PbxRoute()1338            r.context = session['context']1339            r.domain = session['context']1340            r.name = form_result.get('name')1341            r.continue_route = True1342            r.voicemail_enable = True1343            r.voicemail_ext = form_result.get('name')1344            r.pbx_route_type_id = 61345            r.pbx_to_id = t.id1346            db.add(r)1347            db.commit(); db.flush()1348        except validators.Invalid, error:1349            return 'Error: %s' % error1350        db.remove()1351        return "Successfully added time of day route."1352    @authorize(logged_in)1353    def tod_by_id(self, id, **kw):1354        items=[]1355        row = PbxTODRoute.query.filter_by(id=id).filter_by(context=session['context']).first()1356        items.append({'id': row.id, 'name': row.name, 'day_start': row.day_start,1357                      'day_end': row.day_end, 'time_start': row.time_start, 'time_end': row.time_end,1358                      'match_route_id': row.match_route_id, 'nomatch_route_id': row.nomatch_route_id})1359        out = dict({'identifier': 'id', 'label': 'name', 'items': items})1360        response = make_response(out)1361        response.headers = [("Content-type", 'application/json'),]1362        return response(request.environ, self.start_response)1363    @authorize(logged_in)1364    def edit_tod(self, **kw):1365        try:1366            tod = PbxTODRoute.query.filter_by(context=session['context'])\1367                .filter(PbxTODRoute.id==request.params.get('tod_id')).first()1368            if not tod:1369                return "Error: No route found with that id."1370            tod.name = request.params.get('name')1371            tod.store_id = request.params.get('store_id')1372            tod.day_start = request.params.get('day_start')1373            tod.day_end = request.params.get('day_end')1374            tod.time_start = request.params.get('time_start')1375            tod.time_end = request.params.get('time_end')1376            tod.active = True if request.params.get('active')=="true" else False1377            tod.match_route_id = request.params.get('match_route_id')1378            tod.nomatch_route_id = request.params.get('nomatch_route_id')1379            db.commit(); db.flush()1380            db.remove()1381        except validators.Invalid, error:1382            db.remove()1383            return 'Error: %s' % error1384        return "Successfully updated time of day route."1385    @restrict("GET")1386    @authorize(logged_in)1387    def del_tod(self, **kw):1388        try:1389            t = PbxTODRoute.query.filter(PbxTODRoute.id==request.params['id']).first()1390            delete_tod(t.name)1391        except:1392            return "Error deleting Time of Day Route"1393        return  "Successfully deleted Time of Day Route."1394    @authorize(logged_in)1395    def recordings(self):1396        files = []1397        dir = fs_vm_dir+session['context']+"/recordings/"1398        try:1399            for i in os.listdir(dir):1400                files.append(generateFileObject(i, "",  dir))1401        except:1402            os.makedirs(dir)1403        out = dict({'identifier': 'name', 'label': 'name', 'items': files})1404        response = make_response(out)1405        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1406        return response(request.environ, self.start_response)1407    @authorize(logged_in)1408    def audio_recordings(self):1409        items = []1410        dir = fs_vm_dir+session['context']+"/recordings/"1411        try:1412            for i in os.listdir(dir):1413                fo = generateFileObject(i, "",  dir)1414                items.append({'id': '1,'+fo["name"], 'name': 'Recording: '+fo["name"] , 'data': fo["path"], 'type': 1, 'real_id': ""})1415            db.remove()1416        except:1417            pass1418        out = dict({'identifier': 'id', 'label': 'name', 'items': items})1419        response = make_response(out)1420        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1421        return response(request.environ, self.start_response)1422    @restrict("POST")1423    @authorize(logged_in)1424    def delete_recording(self, **kw):1425        t = PbxIVR.query.filter(PbxIVR.data==request.params['name']).filter(PbxIVR.context==session['context']).first()1426        if t:1427            return "Error: Recording "+request.params['name']+" is in use by IVR named "+t.name+"!"1428        try:1429            dir = fs_vm_dir+session['context']+"/recordings/"+request.params['name']1430            os.remove(dir)1431        except:1432            db.remove()1433            return "Error deleting recording."1434        db.remove()1435        return "Deleted recording."1436    @authorize(logged_in)1437    def upload_recording(self):1438        myfile = request.params['uploadedfiles[]']1439        if not myfile.filename.endswith(".wav"):1440            return "Error uploading file. File must have .wav extension."1441        try:1442            dir = fs_vm_dir + "/"+session['context']+"/recordings/"1443            permanent_file = open(os.path.join(dir,myfile.filename.lstrip(os.sep)), 'w')1444            shutil.copyfileobj(myfile.file, permanent_file)1445            myfile.file.close()1446            permanent_file.close()1447        except:1448            return "Error uploading file. The administrator has been contacted."1449        return "Successfully uploaded recording."1450    @authorize(logged_in)1451    def recording_name(self, **kw):1452        files = []1453        dir = fs_vm_dir+session['context']+"/recordings/"1454        old_name = request.params['old_name']1455        new_name = request.params['new_name']1456        src = dir+old_name1457        dst = dir+new_name1458        if not new_name.endswith(".wav"):1459            dst +=".wav"1460        os.rename(src, dst)1461        return "Successfully renamed recording"1462    @authorize(logged_in)1463    def conferences(self):1464        items=[]1465        for conf in PbxConferenceBridge.query.filter_by(context=session['context']).all():1466            items.append({'id': conf.id, 'extension': conf.extension, 'pin': conf.pin})1467        db.remove()1468        out = dict({'identifier': 'id', 'label': 'extension', 'items': items})1469        response = make_response(out)1470        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1471        return response(request.environ, self.start_response)1472    @authorize(logged_in)1473    def conf_add(self, **kw):1474        schema = ConferenceForm()1475        try:1476            form_result = schema.to_python(request.params)1477            sc = PbxConferenceBridge()1478            sc.extension = form_result.get('extension')1479            sc.pin = form_result.get('pin')1480            sc.context = session['context']1481            sc.domain = session['context']1482            db.add(sc)1483            db.commit(); db.flush()1484        except validators.Invalid, error:1485            db.remove()1486            return 'Validation Error: %s' % error1487        r = PbxRoute()1488        r.context = session['context']1489        r.domain = session['context']1490        r.name = form_result.get('extension')1491        r.continue_route = False1492        r.voicemail_enable = False1493        r.voicemail_ext = form_result.get('extension')1494        r.pbx_route_type_id = 71495        r.pbx_to_id = sc.id1496        db.add(r)1497        db.commit(); db.flush()1498        db.remove()1499        return "Successfully added conference bridge."1500    @restrict("GET")1501    @authorize(logged_in)1502    def del_conf(self, **kw):1503        try:1504            delete_conf(request.params['extension'])1505        except:1506            return "Error deleting conference bridge."1507        return  "Successfully deleted conference bridge."1508    @authorize(logged_in)1509    def cid_routes(self):1510        items=[]1511        for cid in PbxCallerIDRoute.query.filter_by(context=session['context']).all():1512            route = db.query(PbxRoute.id, PbxRouteType.name, PbxRoute.name)\1513            .join(PbxRouteType).filter(PbxRoute.context==session['context']).filter(PbxRoute.id==cid.pbx_route_id).first()1514            items.append({'id': cid.id, 'cid_number': cid.cid_number, 'pbx_route_id': cid.pbx_route_id, 'pbx_route_name': route[1]+': '+route[2]})1515        db.remove()1516        out = dict({'identifier': 'id', 'label': 'cid_number', 'items': items})1517        response = make_response(out)1518        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1519        return response(request.environ, self.start_response)1520    @authorize(logged_in)1521    def cid_add(self, **kw):1522        schema = CIDForm()1523        try:1524            form_result = schema.to_python(request.params)1525            sc = PbxCallerIDRoute()1526            sc.cid_number = form_result.get('cid_number')1527            sc.pbx_route_id = form_result.get('pbx_route_id')1528            sc.context = session['context']1529            sc.domain = session['context']1530            db.add(sc)1531            db.commit(); db.flush()1532        except validators.Invalid, error:1533            db.remove()1534            return 'Validation Error: %s' % error1535        db.remove()1536        return "Successfully added Caller ID Route."1537    @restrict("GET")1538    @authorize(logged_in)1539    def del_cid(self, **kw):1540        try:1541            delete_cid(request.params['cid_number'])1542        except:1543            return "Error deleting CallerID Route."1544        return  "Successfully deleted CallerID route."1545    @authorize(logged_in)1546    def blacklisted(self):1547        items=[]1548        for cid in PbxBlacklistedNumber.query.filter_by(context=session['context']).all():1549            items.append({'id': cid.id, 'cid_number': cid.cid_number})1550            members = []1551        db.remove()1552        out = dict({'identifier': 'id', 'label': 'cid_number', 'items': items})1553        response = make_response(out)1554        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1555        return response(request.environ, self.start_response)1556    @authorize(logged_in)1557    def blacklist_add(self, **kw):1558        schema = PbxBlacklistedForm()1559        try:1560            form_result = schema.to_python(request.params)1561            sc = PbxBlacklistedNumber()1562            sc.cid_number = form_result.get('cid_number')1563            sc.context = session['context']1564            sc.domain = session['context']1565            db.add(sc)1566            db.commit(); db.flush()1567        except validators.Invalid, error:1568            db.remove()1569            return 'Validation Error: %s' % error1570        db.remove()1571        return "Successfully added to blacklist."1572    @restrict("GET")1573    @authorize(logged_in)1574    def del_bl(self, **kw):1575        try:1576            del_blacklist(request.params['cid_number'])1577        except:1578            return "Error deleting blacklisted number."1579        return  "Successfully deleted blacklisted number."1580    @authorize(logged_in)1581    def tts(self):1582        items=[]1583        for row in PbxTTS.query.filter_by(context=session['context']).all():1584            items.append({'id': row.id, 'name': row.name, 'text': row.text})1585        db.remove()1586        out = dict({'identifier': 'id', 'label': 'name', 'items': items})1587        response = make_response(out)1588        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1589        return response(request.environ, self.start_response)1590    @authorize(logged_in)1591    def tts_add(self, **kw):1592        schema = TTSForm()1593        try:1594            form_result = schema.to_python(request.params)1595            t = PbxTTS()1596            t.name = form_result.get('name')1597            t.text = form_result.get('text')1598            t.context = session['context']1599            t.domain = session['context']1600            t.voice = u'Allison'1601            db.add(t)1602            db.commit(); db.flush()1603        except validators.Invalid, error:1604            db.remove()1605            return 'Validation Error: %s' % error1606        db.remove()1607        return "Successfully added Text to Speech entry."1608    @authorize(logged_in)1609    def update_tts_grid(self, **kw):1610        try:1611            w = loads(urllib.unquote_plus(request.params.get("data")))1612            for i in w['modified']:1613                t = PbxTTS.query.filter_by(id=i['id']).filter_by(context=session['context']).first()1614                t.name = i['name'].strip()1615                t.text = i['text'].strip()1616                db.commit()1617                db.commit(); db.flush()1618        except DataInputError, error:1619            db.remove()1620            return 'Error: %s' % error1621        return "Successfully updated TTS entry."1622    @restrict("GET")1623    @authorize(logged_in)1624    def del_tts(self, **kw):1625        return  delete_tts(request.params['name'])1626    @authorize(logged_in)1627    def ivr(self):1628        items=[]1629        for ivr in PbxIVR.query.filter_by(context=session['context']).all():1630            items.append({'id': ivr.id, 'name': ivr.name})1631        db.remove()1632        out = dict({'identifier': 'id', 'label': 'name', 'items': items})1633        response = make_response(out)1634        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1635        return response(request.environ, self.start_response)1636    @authorize(logged_in)1637    def ivr_by_id(self, id, **kw):1638        items=[]1639        for ivr in PbxIVR.query.filter_by(context=session['context']).filter_by(id=id).all():1640            options=[]1641            for opt in PbxIVROption.query.filter_by(pbx_ivr_id=ivr.id).all():1642                options.append({'option': opt.option, 'pbx_route_id': opt.pbx_route_id})1643            items.append({'id': ivr.id, 'name': ivr.name,'timeout': ivr.timeout, 'direct_dial': ivr.direct_dial, 'data': ivr.data,\1644                          'audio_name': str(ivr.audio_type)+','+str(ivr.data), 'timeout_destination': ivr.timeout_destination, 'options': options})1645        db.remove()1646        out = dict({'identifier': 'id', 'label': 'name', 'items': items})1647        response = make_response(out)1648        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1649        return response(request.environ, self.start_response)1650    @authorize(logged_in)1651    def ivr_add(self, **kw):1652        schema = IVRForm()1653        try:1654            form_result = schema.to_python(request.params)1655            s = PbxIVR()1656            s.name = form_result.get('ivr_name')1657            s.audio_type = form_result.get('audio_name').split(",")[0].strip()1658            s.data = form_result.get('audio_name').split(",")[1].strip()1659            s.domain = session['context']1660            s.context = session['context']1661            s.timeout = form_result.get('timeout')1662            s.timeout_destination = form_result.get('timeout_destination')1663            if request.params.has_key('direct_dial'):1664                s.direct_dial = True1665            else:1666                s.direct_dial = False1667            db.add(s)1668            db.commit(); db.flush()1669            if len(form_result.get('option_1'))>0:1670                i = PbxIVROption()1671                i.option=11672                i.pbx_ivr_id = s.id1673                i.pbx_route_id = form_result.get('option_1')1674                db.add(i)1675                db.commit(); db.flush()1676            if len(form_result.get('option_2'))>0:1677                i = PbxIVROption()1678                i.option=21679                i.pbx_ivr_id = s.id1680                i.pbx_route_id = form_result.get('option_2')1681                db.add(i)1682                db.commit(); db.flush()1683            if len(form_result.get('option_3'))>0:1684                i = PbxIVROption()1685                i.option=31686                i.pbx_ivr_id = s.id1687                i.pbx_route_id = form_result.get('option_3')1688                db.add(i)1689                db.commit(); db.flush()1690            if len(form_result.get('option_4'))>0:1691                i = PbxIVROption()1692                i.option=41693                i.pbx_ivr_id = s.id1694                i.pbx_route_id = form_result.get('option_4')1695                db.add(i)1696                db.commit(); db.flush()1697            if len(form_result.get('option_5'))>0:1698                i = PbxIVROption()1699                i.option=51700                i.pbx_ivr_id = s.id1701                i.pbx_route_id = form_result.get('option_5')1702                db.add(i)1703                db.commit(); db.flush()1704            if len(form_result.get('option_6'))>0:1705                i = PbxIVROption()1706                i.option=61707                i.pbx_ivr_id = s.id1708                i.pbx_route_id = form_result.get('option_6')1709                db.add(i)1710                db.commit(); db.flush()1711            if len(form_result.get('option_7'))>0:1712                i = PbxIVROption()1713                i.option=71714                i.pbx_ivr_id = s.id1715                i.pbx_route_id = form_result.get('option_7')1716                db.add(i)1717                db.commit(); db.flush()1718            if len(form_result.get('option_8'))>0:1719                i = PbxIVROption()1720                i.option=81721                i.pbx_ivr_id = s.id1722                i.pbx_route_id = form_result.get('option_8')1723                db.add(i)1724                db.commit(); db.flush()1725            if len(form_result.get('option_9'))>0:1726                i = PbxIVROption()1727                i.option=91728                i.pbx_ivr_id = s.id1729                i.pbx_route_id = form_result.get('option_9')1730                db.add(i)1731                db.commit(); db.flush()1732            if len(form_result.get('option_0'))>0:1733                i = PbxIVROption()1734                i.option=01735                i.pbx_ivr_id = s.id1736                i.pbx_route_id = form_result.get('option_0')1737                db.add(i)1738                db.commit(); db.flush()1739        except validators.Invalid, error:1740            db.remove()1741            return 'Validation Error: Please correct form inputs and resubmit.'1742        r = PbxRoute()1743        r.context = session['context']1744        r.domain = session['context']1745        r.name = form_result.get('ivr_name')1746        r.continue_route = True1747        r.voicemail_enable = True1748        r.voicemail_ext = form_result.get('ivr_name')1749        r.pbx_route_type_id = 51750        r.pbx_to_id = s.id1751        db.add(r)1752        db.commit(); db.flush()1753        db.remove()1754        return "Successfully added IVR."1755    @authorize(logged_in)1756    def ivr_edit(self, **kw):1757        schema = IVREditForm()1758        try:1759            form_result = schema.to_python(request.params)1760            s = PbxIVR.query.filter_by(id=form_result.get('ivr_id')).filter_by(context=session['context']).first()1761            s.audio_type = form_result.get('audio_name').split(",")[0].strip()1762            s.data = form_result.get('audio_name').split(",")[1].strip()1763            s.domain = session['context']1764            s.context = session['context']1765            s.timeout = form_result.get('timeout')1766            s.timeout_destination=form_result.get('timeout_destination')1767            if request.params.has_key('direct_dial'):1768                s.direct_dial=True1769            else:1770                s.direct_dial=False1771            db.commit(); db.flush()1772            PbxIVROption.query.filter_by(pbx_ivr_id=s.id).delete()1773            db.commit(); db.flush()1774            if len(form_result.get('option_1'))>0:1775                i = PbxIVROption()1776                i.option=11777                i.pbx_ivr_id=s.id1778                i.pbx_route_id=form_result.get('option_1')1779                db.add(i)1780                db.commit(); db.flush()1781            if len(form_result.get('option_2'))>0:1782                i = PbxIVROption()1783                i.option=21784                i.pbx_ivr_id=s.id1785                i.pbx_route_id=form_result.get('option_2')1786                db.add(i)1787                db.commit(); db.flush()1788            if len(form_result.get('option_3'))>0:1789                i = PbxIVROption()1790                i.option=31791                i.pbx_ivr_id=s.id1792                i.pbx_route_id=form_result.get('option_3')1793                db.add(i)1794                db.commit(); db.flush()1795            if len(form_result.get('option_4'))>0:1796                i = PbxIVROption()1797                i.option=41798                i.pbx_ivr_id=s.id1799                i.pbx_route_id=form_result.get('option_4')1800                db.add(i)1801                db.commit(); db.flush()1802            if len(form_result.get('option_5'))>0:1803                i = PbxIVROption()1804                i.option=51805                i.pbx_ivr_id=s.id1806                i.pbx_route_id=form_result.get('option_5')1807                db.add(i)1808                db.commit(); db.flush()1809            if len(form_result.get('option_6'))>0:1810                i = PbxIVROption()1811                i.option=61812                i.pbx_ivr_id=s.id1813                i.pbx_route_id=form_result.get('option_6')1814                db.add(i)1815                db.commit(); db.flush()1816            if len(form_result.get('option_7'))>0:1817                i = PbxIVROption()1818                i.option=71819                i.pbx_ivr_id=s.id1820                i.pbx_route_id=form_result.get('option_7')1821                db.add(i)1822                db.commit(); db.flush()1823            if len(form_result.get('option_8'))>0:1824                i = PbxIVROption()1825                i.option=81826                i.pbx_ivr_id=s.id1827                i.pbx_route_id=form_result.get('option_8')1828                db.add(i)1829                db.commit(); db.flush()1830            if len(form_result.get('option_9'))>0:1831                i = PbxIVROption()1832                i.option=91833                i.pbx_ivr_id=s.id1834                i.pbx_route_id=form_result.get('option_9')1835                db.add(i)1836                db.commit(); db.flush()1837            if len(form_result.get('option_0'))>0:1838                i = PbxIVROption()1839                i.option=01840                i.pbx_ivr_id=s.id1841                i.pbx_route_id=form_result.get('option_0')1842                db.add(i)1843                db.commit(); db.flush()1844        except validators.Invalid, error:1845            db.remove()1846            return 'Validation Error: Please correct form inputs and resubmit.'1847        db.remove()1848        return "Successfully edited IVR."1849    @authorize(logged_in)1850    def update_ivr_grid(self, **kw):1851        w = loads(urllib.unquote_plus(request.params.get("data")))1852        for i in w['modified']:1853            ivr = PbxIVR.query.filter_by(context=session['context']).filter(PbxIVR.id==int(i['id'])).first()1854            ivr.name = i['name']1855            route = PbxRoute.query.filter_by(context=session['context']).\1856            filter(PbxRoute.pbx_route_type_id==5).filter(PbxRoute.pbx_to_id==int(i['id'])).first()1857            route.name = i['name']1858            db.commit(); db.flush()1859            db.remove()1860        return "Successfully updated IVR."1861    @restrict("GET")1862    @authorize(logged_in)1863    def del_ivr(self, **kw):1864        return  delete_ivr(request.params['name'])1865    @authorize(logged_in)1866    def ivr_audio(self):1867        items = []1868        dir = fs_vm_dir+session['context']+"/recordings/"1869        try:1870            for i in os.listdir(dir):1871                fo = generateFileObject(i, "",  dir)1872                items.append({'id': '1,'+fo["name"], 'name': 'Recording: '+fo["name"] , 'data': fo["path"], 'type': 1, 'real_id': ""})1873        except:1874            os.makedirs(dir)1875        for row in PbxTTS.query.filter_by(context=session['context']).all():1876            items.append({'id': '2,'+str(row.id), 'name': 'TTS: '+row.name, 'data': row.text, 'type': 2, 'real_id': row.id})1877        db.remove()1878        out = dict({'identifier': 'id', 'label': 'name', 'items': items})1879        response = make_response(out)1880        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1881        return response(request.environ, self.start_response)1882    @authorize(logged_in)1883    def voicemail_from_file_system(self):1884        files = []1885        dir = fs_vm_dir+session['context']+"/"+session['ext']1886        try:1887            for i in os.listdir(dir):1888                if i.startswith("greeting_"):1889                    continue1890                id = i.split("_")[1].split(".")[0].strip()1891                row = PbxCdr.query.filter(PbxCdr.uuid==id).first()1892                path = dir+"/"+i1893                tpath = "/vm/"+session['context']+"/"+session['ext']+"/"+i1894                received = str(modification_date(path)).strip("\"")1895                fsize = str(os.path.getsize(path))1896                caller = row.caller_id_number[len(row.caller_id_number)-10:]1897                files.append({'name': caller, 'path': tpath, 'received': received, 'size': fsize})1898        except:1899            os.makedirs(dir)1900            out = dict({'identifier': 'path', 'label': 'name', 'items': files})1901        response = make_response(out)1902        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1903        return response(request.environ, self.start_response)1904    @authorize(logged_in)1905    def voicemail(self):1906        items=[]1907        path = []1908        i = 41909        if session['group_id'] > 1:1910            rows = VoiceMail.query.filter_by(domain=session['context']).filter(VoiceMail.username==session['ext']).all()1911        else:1912            rows = VoiceMail.query.filter_by(domain=session['context']).all()1913        for row in rows:1914            received = time.strftime("%a, %d %b %Y %H:%M", time.localtime(row.created_epoch))1915            name = row.cid_number[len(row.cid_number)-10:]1916            fname = row.file_path.split("/")[len(row.file_path.split("/"))-1]1917            for x in range(1,5):1918                path.append(row.file_path.split("/")[len(row.file_path.split("/"))-i])1919                i=i-11920            i = 41921            fpath = "/"+"/".join(path)1922            path = []1923            items.append({'name': name, 'to': row.username, 'received': received, 'path': fpath, 'size': row.message_len})1924        db.remove()1925        out = dict({'identifier': 'path', 'label': 'name', 'items': items})1926        response = make_response(out)1927        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1928        return response(request.environ, self.start_response)1929    @restrict("POST")1930    @authorize(logged_in)1931    def delete_voicemail(self, **kw):1932        path = request.params['data']1933        file_name = path.split("/")[len(path.split("/"))-1]1934        uuid = file_name.split("_")[1].split(".")[0].strip()1935        try:1936            VoiceMail.query.filter(VoiceMail.uuid==uuid).filter(VoiceMail.username==session['ext']).delete()1937            dir = fs_vm_dir+"/"+session['context']+"/"+session['ext']1938            os.remove(os.path.join(dir, file_name))1939        except:1940            return "Error: Virtual Extension voicemail can be deleted by dialing * plus extension from a registered endpoint."1941        return "Deleted voicemail."1942    @authorize(logged_in)1943    def cdr(self):1944        items=[]1945        for row in PbxCdr.query.filter_by(context=session['context']).order_by(desc(PbxCdr.id)).all():1946            num = row.caller_id_number if len(row.caller_id_number)<=10 else row.caller_id_number[len(row.caller_id_number)-10:]1947            items.append({'id': row.id, 'caller_id_name': row.caller_id_name, 'caller_id_number': num,1948                          'destination_number': row.destination_number, 'start_stamp': fix_date(row.start_stamp), 'answer_stamp': fix_date(row.answer_stamp),1949                          'end_stamp': fix_date(row.end_stamp), 'duration': row.duration, 'billsec':row.billsec, 'hangup_cause': row.hangup_cause})1950        db.remove()1951        out = dict({'identifier': 'id', 'label': 'caller_id_number', 'items': items})1952        response = make_response(out)1953        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1954        return response(request.environ, self.start_response)1955    @authorize(logged_in)1956    def cdr_summary(self):1957        items=[]1958        sdate = request.params.get("sdate", 'TIMESTAMP')1959        edate = request.params.get("edate", 'CURRENT_TIMESTAMP')1960        sdate = "TIMESTAMP '"+sdate+"'" if sdate != 'TIMESTAMP' else "CURRENT_TIMESTAMP - INTERVAL '1 MONTH'"1961        edate = "TIMESTAMP '"+edate+"' + interval '1 day'" if edate != 'CURRENT_TIMESTAMP' else 'CURRENT_TIMESTAMP'1962        for row in db.execute("SELECT * "1963                              "FROM cdr "1964                              "WHERE customer_id = :customer_id "1965                              "AND bleg_uuid IS NOT NULL "1966                              "AND cdr.start_stamp > "+sdate+" AND cdr.end_stamp < "+edate+" "1967                              "ORDER BY start_stamp DESC", {'customer_id': str(session['customer_id'])}).fetchall():1968            num = row.caller_id_number if len(row.caller_id_number)<=10 else row.caller_id_number[len(row.caller_id_number)-10:]1969            items.append({'id': row.id, 'caller_id_name': row.caller_id_name, 'caller_id_number': num,1970                          'destination_number': row.destination_number, 'start_stamp': fix_date(row.start_stamp), 'answer_stamp': fix_date(row.answer_stamp),1971                          'end_stamp': fix_date(row.end_stamp), 'duration': row.duration, 'billsec':row.billsec, 'hangup_cause': row.hangup_cause})1972        db.remove()1973        out = dict({'identifier': 'id', 'label': 'caller_id_number', 'items': items})1974        response = make_response(out)1975        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]1976        return response(request.environ, self.start_response)1977    @authorize(logged_in)1978    def cdr_ext_summary(self):1979        items=[]1980        sdate = request.params.get("sdate", 'TIMESTAMP')1981        edate = request.params.get("edate", 'CURRENT_TIMESTAMP')1982        sdate = "TIMESTAMP '"+sdate+"'" if sdate != 'TIMESTAMP' else "TIMESTAMP '"+datetime.today().strftime("%m/%d/%Y 12:00:00 AM")+"'"1983        edate = "TIMESTAMP '"+edate+"' + interval '1 day'" if edate != 'CURRENT_TIMESTAMP' else 'CURRENT_TIMESTAMP'1984        for row in db.execute("SELECT DISTINCT users.id, users.first_name ||' '|| users.last_name AS agent, users.portal_extension as extension, "1985                              "(SELECT COUNT(uuid) FROM cdr WHERE (cdr.caller_id_number = users.portal_extension or cdr.destination_number = users.portal_extension) "1986                              "AND cdr.start_stamp > "+sdate+" AND cdr.end_stamp < "+edate+" AND call_direction = 'inbound' AND cdr.context = customers.context) AS call_count_in, "1987                              "(SELECT COUNT(uuid) FROM cdr WHERE (cdr.caller_id_number = users.portal_extension or cdr.destination_number = users.portal_extension) "1988                              "AND cdr.start_stamp > "+sdate+" AND cdr.end_stamp < "+edate+" AND call_direction = 'outbound' AND cdr.context =  customers.context) AS call_count_out, "1989                              "(SELECT coalesce(sum(billsec),0) FROM cdr WHERE  (cdr.caller_id_number = users.portal_extension or cdr.destination_number = users.portal_extension) "1990                              "AND cdr.start_stamp > "+sdate+" AND cdr.end_stamp < "+edate+" AND call_direction = 'inbound' AND cdr.context =  customers.context) AS time_on_call_in, "1991                              "(SELECT coalesce(sum(billsec),0) FROM cdr WHERE  (cdr.caller_id_number = users.portal_extension or cdr.destination_number = users.portal_extension) "1992                              "AND cdr.start_stamp > "+sdate+" AND cdr.end_stamp < "+edate+" AND call_direction = 'outbound' AND cdr.context =  customers.context) AS time_on_call_out "1993                              "FROM users "1994                              "INNER JOIN customers ON customers.id = users.customer_id "1995                              "WHERE customers.id = :customer_id "1996                              "ORDER BY extension", {'customer_id': session['customer_id']}).fetchall():1997            m, s = divmod(row.time_on_call_in, 60)1998            h, m = divmod(m, 60)1999            toci = "%dh:%02dm:%02ds" % (h, m, s)2000            m, s = divmod(row.time_on_call_out, 60)2001            h, m = divmod(m, 60)2002            toco = "%dh:%02dm:%02ds" % (h, m, s)2003            items.append({'id': row.id, 'agent': row.agent, 'extension': row.extension, 'call_count_in': row.call_count_in,2004                          'qstring': '?ext='+row.extension+'&sdate='+request.params.get("sdate", 'TIMESTAMP')+'&edate='+request.params.get("edate", 'CURRENT_TIMESTAMP'),2005                          'call_count_out': row.call_count_out, 'time_on_call_in': toci, 'time_on_call_out': toco,2006                          'from': request.params.get("sdate", 'TIMESTAMP') if request.params.get("sdate", 'TIMESTAMP') != 'TIMESTAMP' else datetime.today().strftime("%m/%d/%Y"),2007                          'to': request.params.get("edate", 'CURRENT_TIMESTAMP') if request.params.get("edate", 'CURRENT_TIMESTAMP') != 'CURRENT_TIMESTAMP' else datetime.today().strftime("%m/%d/%Y")})2008        db.remove()2009        out = dict({'identifier': 'id', 'label': 'agent', 'items': items})2010        response = make_response(out)2011        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2012        return response(request.environ, self.start_response)2013    def cdr_ext(self):2014        items=[]2015        sdate = request.params.get("sdate", 'TIMESTAMP')2016        edate = request.params.get("edate", 'CURRENT_TIMESTAMP')2017        ext = request.params.get("ext")2018        sdate = "TIMESTAMP '"+sdate+"'" if sdate != 'TIMESTAMP' else "TIMESTAMP '"+datetime.today().strftime("%m/%d/%Y 12:00:00 AM")+"'"2019        edate = "TIMESTAMP '"+edate+"' + interval '1 day'" if edate != 'CURRENT_TIMESTAMP' else 'CURRENT_TIMESTAMP'2020        for row in db.execute("SELECT  cdr.id AS id, caller_id_name, caller_id_number, destination_number, start_stamp, answer_stamp, "2021                              "end_stamp, duration, billsec, hangup_cause "2022                              "FROM cdr "2023                              "INNER JOIN customers ON cdr.context = customers.context "2024                              "WHERE customers.id = :customer_id "2025                              "AND cdr.start_stamp > "+sdate+" AND cdr.end_stamp < "+edate+" "2026                              "AND cdr.call_direction IS NOT NULL "2027                              "AND (cdr.caller_id_number = :extension or cdr.destination_number = :extension) "2028                              "ORDER BY id", {'customer_id': session['customer_id'], 'extension': ext}).fetchall():2029            num = row.caller_id_number if len(row.caller_id_number)<=10 else row.caller_id_number[len(row.caller_id_number)-10:]2030            items.append({'id': row.id, 'caller_id_name': row.caller_id_name, 'caller_id_number': num,2031                          'destination_number': row.destination_number, 'start_stamp': fix_date(row.start_stamp), 'answer_stamp': fix_date(row.answer_stamp),2032                          'end_stamp': fix_date(row.end_stamp), 'duration': row.duration, 'billsec':row.billsec, 'hangup_cause': row.hangup_cause})2033        db.remove()2034        out = dict({'identifier': 'id', 'label': 'caller_id_number', 'items': items})2035        response = make_response(out)2036        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2037        return response(request.environ, self.start_response)2038    @authorize(logged_in)2039    def cdr_ext_download(self):2040        items=[]2041        start = request.params.get("sdate")2042        end = request.params.get("edate")2043        sdate = request.params.get("sdate", 'TIMESTAMP')2044        edate = request.params.get("edate", 'CURRENT_TIMESTAMP')2045        ext = request.params.get("ext")2046        sdate = "TIMESTAMP '"+sdate+"'" if sdate != 'TIMESTAMP' else "TIMESTAMP '"+datetime.today().strftime("%m/%d/%Y 12:00:00 AM")+"'"2047        edate = "TIMESTAMP '"+edate+"' + interval '1 day'" if edate != 'CURRENT_TIMESTAMP' else 'CURRENT_TIMESTAMP'2048        for row in db.execute("SELECT  cdr.id AS id, caller_id_name, caller_id_number, destination_number, start_stamp, answer_stamp, "2049                              "end_stamp, duration, billsec, hangup_cause "2050                              "FROM cdr "2051                              "INNER JOIN customers ON cdr.context = customers.context "2052                              "WHERE customers.id = :customer_id "2053                              "AND cdr.start_stamp > "+sdate+" AND cdr.end_stamp < "+edate+" "2054                              "AND cdr.call_direction IS NOT NULL "2055                              "AND (cdr.caller_id_number = :extension or cdr.destination_number = :extension) "2056                              "ORDER BY id", {'customer_id': session['customer_id'], 'extension': ext}).fetchall():2057            num = row.caller_id_number if len(row.caller_id_number)<=10 else row.caller_id_number[len(row.caller_id_number)-10:]2058            items.append({'id': row.id, 'caller_id_name': row.caller_id_name, 'caller_id_number': num,2059                          'destination_number': row.destination_number, 'start_stamp': fix_date(row.start_stamp), 'answer_stamp': fix_date(row.answer_stamp),2060                          'end_stamp': fix_date(row.end_stamp), 'duration': row.duration, 'billsec':row.billsec, 'hangup_cause': row.hangup_cause})2061        db.remove()2062        f = open("/tmp/Report_ext"+ext+".csv", "wb+")2063        csv_file = csv.writer(f)2064        #f=csv.writer(open("/tmp/Report_ext"+ext+".csv",'wb+'))2065        csv_file.writerow(["Name","Number","Destination","Start Time","End Time", "Duration Seconds","Hangup Cause"])2066        for csv_items in items:2067            csv_file.writerow([csv_items['caller_id_name'], csv_items['caller_id_number'], csv_items['destination_number'], csv_items['start_stamp'], csv_items['duration'], csv_items['hangup_cause']])2068        f.close()2069        size = os.path.getsize("/tmp/Report_ext"+ext+".csv")2070        response = make_file_response("/tmp/Report_ext"+ext+".csv")2071        response.headers = [("Content-type", "application/octet-stream"),2072            ("Content-Disposition", "attachment; filename="+"Report_ext"+ext+".csv"),2073            ("Content-length", str(size)),]2074        return response(request.environ, self.start_response)2075    @authorize(logged_in)2076    def customer_by_id(self, **kw):2077        items=[]2078        row = Customer.query.filter(Customer.id==session['customer_id']).first()2079        items.append({'id': row.id, 'name': row.name, 'email': row.email, 'address': row.address, 'address_2': row.address_2,2080                      'city': row.city, 'state': row.state, 'zip': row.zip,2081                      'tel': row.tel, 'url': row.url, 'active': row.active, 'context': row.context, 'has_crm': row.has_crm,2082                      'has_call_center': row.has_call_center, 'contact_name': row.contact_name, 'contact_phone': row.contact_phone,2083                      'contact_mobile': row.contact_mobile, 'contact_title': row.contact_title, 'contact_email': row.contact_email, 'notes': row.notes})2084        out = dict({'identifier': 'id', 'label': 'name', 'items': items})2085        response = make_response(out)2086        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2087        return response(request.environ, self.start_response)2088    @authorize(logged_in)2089    def edit_customer(self):2090        schema = CustomerForm()2091        try:2092            form_result = schema.to_python(request.params)2093            co = Customer.query.filter(Customer.id==session['customer_id']).first()2094            co.tel = form_result.get('tel')2095            co.address = form_result.get('address')2096            co.address_2 = form_result.get('address_2')2097            co.city = form_result.get('city')2098            co.state = form_result.get('state')2099            co.zip = form_result.get('zip')2100            co.url = form_result.get('url')2101            co.email = form_result.get('email')2102            co.contact_name = form_result.get('contact_name')2103            co.contact_phone = form_result.get('contact_phone')2104            co.contact_mobile = form_result.get('contact_mobile')2105            co.contact_title = form_result.get('contact_title')2106            co.contact_email = form_result.get('contact_email')2107            db.commit(); db.flush()2108        except validators.Invalid, error:2109            db.remove()2110            return 'Error: %s' % error2111        return "Successfully edited customer."2112    @authorize(logged_in)2113    def avail_findme_endpoints(self):2114        items=[]2115        for row in PbxEndpoint.query.filter_by(user_context=session['context']).order_by(PbxEndpoint.auth_id).all():2116            if PbxFindMeRoute.query.filter_by(pbx_endpoint_id=row.id).count()>0:2117                continue2118            items.append({'id': row.id, 'auth_id': row.auth_id})2119        db.remove()2120        out = dict({'identifier': 'id', 'label': 'auth_id', 'items': items})2121        response = make_response(out)2122        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2123        return response(request.environ, self.start_response)2124    @authorize(logged_in)2125    def inuse_findme_endpoints(self):2126        items=[]2127        for row in db.query(PbxFindMeRoute.id, PbxEndpoint.auth_id)\2128        .select_from(join(PbxFindMeRoute, PbxEndpoint, PbxEndpoint.pbx_find_me))\2129        .filter(PbxEndpoint.user_context==session['context']).all():2130            items.append({'id': row.id, 'auth_id': row.auth_id})2131        db.remove()2132        out = dict({'identifier': 'id', 'label': 'auth_id', 'items': items})2133        response = make_response(out)2134        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2135        return response(request.environ, self.start_response)2136    @authorize(logged_in)2137    def routes(self):2138        items=[]2139        for row in db.execute("SELECT sr.id, sr.name AS data, sr.pbx_to_id AS to_id, sr.pbx_route_type_id AS type_id, srt.name|| ': ' ||sr.name AS name "2140                              "FROM pbx_routes sr "2141                              "INNER JOIN pbx_route_types srt ON sr.pbx_route_type_id = srt.id "2142                              "WHERE sr.context = :context", {'context': session['context']}):2143            items.append({'id': row.id, 'data': row.data, 'to_id': row.to_id, 'type_id': row.type_id, 'name': row.name})2144        db.remove()2145        out = dict({'identifier': 'id', 'label': 'name', 'items': items})2146        response = make_response(out)2147        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2148        return response(request.environ, self.start_response)2149    @jsonify2150    @authorize(logged_in)2151    def route_id_names(self):2152        return db.query(PbxRoute.name, PbxRoute.id).filter_by(context=session['context']).all()2153    @jsonify2154    @authorize(logged_in)2155    def route_ids(self):2156        names=[]2157        ids=[]2158        for r in db.query(PbxRoute.name, PbxRoute.id).filter_by(context=session['context']).order_by(PbxRoute.name).all():2159            names.append(r.name)2160            ids.append(r.id)2161        return dict({'names': names, 'ids': ids})2162    @authorize(logged_in)2163    def call_stats(self):2164        items=[]2165        volume=[]2166        ttime=[]2167        minimumt = 02168        maximumt = 02169        minimumv = 02170        maximumv = 102171        for row in User.query.filter(User.customer_id==session['customer_id']).all():2172            if not len(row.portal_extension):2173                continue2174            else:2175                extension = row.portal_extension2176            vol =  get_volume(extension)2177            tt = get_talk_time(extension)2178            if vol > maximumv:2179                maximumv = vol2180            if tt > maximumt:2181                maximumt = tt2182            volume.append({'x': row.first_name+' '+row.last_name, 'y': vol})2183            ttime.append({'x': row.first_name+' '+row.last_name, 'y': tt})2184            items.append({'id': row.id, 'extension': extension, 'name': row.first_name+' '+row.last_name, 'volume': vol, 'talk_time': tt})2185        db.remove()2186        out = dict({'identifier': 'id', 'label': 'name', 'items': items, 'mint': minimumt,2187                    'maxt': maximumt, 'minv': minimumv, 'maxv': maximumv, 'volume': volume, 'talk_time': ttime})2188        response = make_response(out)2189        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2190        return response(request.environ, self.start_response)2191    @authorize(logged_in)2192    def get_find_me_edit(self, id, **kw):2193        c.findme = db.query(PbxFindMeRoute.id,PbxFindMeRoute.ring_strategy, PbxFindMeRoute.destination_1, PbxFindMeRoute.destination_2,\2194            PbxFindMeRoute.destination_3, PbxFindMeRoute.destination_4, PbxEndpoint.auth_id)\2195                .select_from(join(PbxFindMeRoute, PbxEndpoint, PbxEndpoint.pbx_find_me))\2196                .filter(PbxEndpoint.user_context==session['context'])\2197                .filter_by(id=id).first()2198        db.remove()2199        return render('find_me_edit.html')2200    @authorize(credential('pbx_admin'))2201    def permissions(self, id, **kw):2202        c.findme = db.query(PbxFindMeRoute.id,PbxFindMeRoute.ring_strategy, PbxFindMeRoute.destination_1, PbxFindMeRoute.destination_2,\2203            PbxFindMeRoute.destination_3, PbxFindMeRoute.destination_4, PbxEndpoint.auth_id)\2204                .select_from(join(PbxFindMeRoute, PbxEndpoint, PbxEndpoint.pbx_find_me))\2205                .filter(PbxEndpoint.user_context==session['context'])\2206                .filter_by(id=id).first()2207        db.remove()2208        return render('find_me_edit.html')2209    @authorize(logged_in)2210    def names_user_ids(self):2211        names=[]2212        user_ids=[]2213        for row in User.query.filter_by(customer_id=session['customer_id']).all():2214            names.append(row.first_name+' '+row.last_name)2215            user_ids.append(row.id)2216        db.remove()2217        out = dict({'names': names, 'user_ids': user_ids})2218        response = make_response(out)2219        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2220        return response(request.environ, self.start_response)2221    @authorize(logged_in)2222    def destinations(self):2223        items=[]2224        for row in PbxEndpoint.query.filter_by(user_context=session['context']).all():2225            items.append({'id': row.id, 'ext': row.auth_id})2226        db.remove()2227        out = dict({'identifier': 'ext', 'label': 'ext', 'items': items})2228        response = make_response(out)2229        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2230        return response(request.environ, self.start_response)2231    @authorize(logged_in)2232    def device_store(self):2233        items=[]2234        for row in db.query(PbxDeviceManufacturer.id, PbxDeviceManufacturer.name,  PbxDeviceType.model,2235            PbxDeviceType.id).join(PbxDeviceType).order_by(PbxDeviceManufacturer.name).all():2236            items.append({'id': row[0], 'manufacturer': row[1], 'model': row[2], 'name':  row[1]+ ': '+row[2], 'device_type_id': row[3]})2237        db.remove()2238        out = dict({'identifier': 'device_type_id', 'label': 'name', 'items': items})2239        response = make_response(out)2240        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2241        return response(request.environ, self.start_response)2242    @authorize(logged_in)2243    def login_ext(self, id):2244        items=[]2245        for row in PbxEndpoint.query.filter_by(user_context=session['context']).\2246        filter_by(user_id=id).order_by(PbxEndpoint.auth_id).all():2247            items.append({'id': row.id, 'extension': row.auth_id})2248        db.remove()2249        out = dict({'identifier': 'extension', 'label': 'extension', 'items': items})2250        response = make_response(out)2251        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2252        return response(request.environ, self.start_response)2253    @authorize(logged_in)2254    def help(self, id, **kw):2255        help = PbxHelp.query.filter(PbxHelp.category_id==id).first()2256        if help:2257            data = help.data2258        else:2259            data = "No help to display in this category."2260        db.remove()2261        out = dict({'help': data})2262        response = make_response(out)2263        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2264        return response(request.environ, self.start_response)2265    @authorize(logged_in)2266    def ext_recordings2(self):2267        files = []2268        dir = fs_vm_dir+session['context']+"/extension-recordings/"2269        try:2270            for i in os.listdir(dir):2271                id = i.split("_")[1].split("_")[0].strip()2272                direction = i.split("_")[2]2273                ext = i.split("_")[0]2274                row = PbxCdr.query.filter(PbxCdr.uuid==id).first()2275                if not row:2276                    continue2277                path = dir+"/"+i2278                tpath = "/vm/"+session['context']+"/extension-recordings/"+i2279                received = str(modification_date(path)).strip("\"")2280                fsize = str(os.path.getsize(path))2281                caller = row.caller_id_number[len(row.caller_id_number)-10:]2282                dest = row.destination_number[len(row.destination_number)-10 if len(row.destination_number) > 10 else 0:]2283                files.append({'name': caller, 'dest': dest, 'path': tpath, 'received': received, 'size': fsize, 'extension': ext, 'id': id, 'direction': direction})2284        except Exception, e:2285            raise2286        out = dict({'identifier': 'id', 'label': 'name', 'items': files})2287        response = make_response(out)2288        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2289        return response(request.environ, self.start_response)2290    @authorize(logged_in)2291    def ext_recordings(self):2292        files = []2293        dir = fs_vm_dir+session['context']+"/extension-recordings/"2294        try:2295            for i in os.listdir(dir):2296                id = i.split("_")[1].split("_")[0].strip()2297                direction = i.split("_")[2]2298                ext = i.split("_")[0]2299                row = PbxCdr.query.filter(PbxCdr.uuid==id).first()2300                if not row:2301                    continue2302                path = dir+"/"+i2303                tpath = "/vm/"+session['context']+"/extension-recordings/"+i2304                received = str(modification_date(path)).strip("\"")2305                fsize = str(os.path.getsize(path))2306                caller = row.caller_id_number[len(row.caller_id_number)-10:]2307                dest = row.destination_number[len(row.destination_number)-10 if len(row.destination_number) > 10 else 0:]2308                files.append({'name': caller, 'dest': dest, 'path': tpath, 'received': received, 'size': fsize, 'extension': ext, 'id': id, 'direction': direction})2309        except Exception, e:2310            raise2311        out = dict({'identifier': 'id', 'label': 'name', 'items': files})2312        response = make_response(out)2313        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2314        return response(request.environ, self.start_response)2315    @authorize(logged_in)2316    def active_tickets(self):2317        items=[]2318        for row in Ticket.query.filter_by(customer_id=session['customer_id']).filter(Ticket.ticket_status_id!=4).all():2319            items.append({'id': row.id, 'customer_id': row.customer_id, 'opened_by': row.opened_by,2320                          'status': row.ticket_status_id, 'priority': row.ticket_priority_id,2321                          'type': row.ticket_type_id, 'created': row.created.strftime("%m/%d/%Y %I:%M:%S %p"),2322                          'expected_resolve_date': row.expected_resolve_date.strftime("%m/%d/%Y %I:%M:%S %p"),2323                          'subject': row.subject, 'description': row.description})2324        db.remove()2325        out = dict({'identifier': 'id', 'label': 'id', 'items': items})2326        response = make_response(out)2327        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2328        return response(request.environ, self.start_response)2329    @authorize(logged_in)2330    def closed_tickets(self):2331        items=[]2332        for row in Ticket.query.filter_by(customer_id=session['customer_id']).filter(Ticket.ticket_status_id==4).all():2333            items.append({'id': row.id, 'customer_id': row.customer_id, 'opened_by': row.opened_by,2334                          'status': row.ticket_status_id, 'priority': row.ticket_priority_id,2335                          'type': row.ticket_type_id, 'created': row.created.strftime("%m/%d/%Y %I:%M:%S %p"),2336                          'expected_resolve_date': row.expected_resolve_date.strftime("%m/%d/%Y %I:%M:%S %p"),2337                          'subject': row.subject, 'description': row.description})2338        db.remove()2339        out = dict({'identifier': 'id', 'label': 'id', 'items': items})2340        response = make_response(out)2341        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2342        return response(request.environ, self.start_response)2343    @authorize(logged_in)2344    def internal_tickets(self):2345        items=[]2346        for row in Ticket.query.filter_by(customer_id=session['customer_id']).filter(Ticket.ticket_status_id==7).all():2347            items.append({'id': row.id, 'customer_id': row.customer_id, 'opened_by': row.opened_by,2348                          'status': row.ticket_status_id, 'priority': row.ticket_priority_id,2349                          'type': row.ticket_type_id, 'created': row.created.strftime("%m/%d/%Y %I:%M:%S %p"),2350                          'expected_resolve_date': row.expected_resolve_date.strftime("%m/%d/%Y %I:%M:%S %p"),2351                          'subject': row.subject, 'description': row.description})2352        db.remove()2353        out = dict({'identifier': 'id', 'label': 'id', 'items': items})2354        response = make_response(out)2355        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2356        return response(request.environ, self.start_response)2357    @authorize(logged_in)2358    def ticket_data(self):2359        ticket_status_id =[]2360        ticket_status_name =[]2361        ticket_type_id = []2362        ticket_type_name = []2363        ticket_priority_id = []2364        ticket_priority_name = []2365        opened_by_id = []2366        opened_by_name = []2367        for row in TicketStatus.query.all():2368            ticket_status_id.append(row.id)2369            ticket_status_name.append(row.name)2370        for row in TicketType.query.all():2371            ticket_type_id.append(row.id)2372            ticket_type_name.append(row.name)2373        for row in TicketPriority.query.all():2374            ticket_priority_id.append(row.id)2375            ticket_priority_name.append(row.name)2376        for row in User.query.filter_by(customer_id=session['customer_id']).all():2377            opened_by_id.append(row.id)2378            opened_by_name.append(row.first_name+' '+row.last_name)2379        db.remove()2380        out = dict({'ticket_status_names': ticket_status_name, 'ticket_status_ids': ticket_status_id,2381                    'ticket_type_names': ticket_type_name, 'ticket_type_ids': ticket_type_id,2382                    'ticket_priority_names': ticket_priority_name, 'ticket_priority_ids': ticket_priority_id,2383                    'opened_by_names': opened_by_name, 'opened_by_ids': opened_by_id})2384        response = make_response(out)2385        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2386        return response(request.environ, self.start_response)2387    @authorize(logged_in)2388    def ticket_types(self):2389        items=[]2390        for row in TicketType.query.all():2391            items.append({'id': row.id, 'name': row.name, 'description': row.description})2392        db.remove()2393        out = dict({'identifier': 'id', 'label': 'name', 'items': items})2394        response = make_response(out)2395        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2396        return response(request.environ, self.start_response)2397    @authorize(logged_in)2398    def ticket_statuses(self):2399        items=[]2400        for row in TicketStatus.query.all():2401            items.append({'id': row.id, 'name': row.name, 'description': row.description})2402        db.remove()2403        out = dict({'identifier': 'id', 'label': 'name', 'items': items})2404        response = make_response(out)2405        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2406        return response(request.environ, self.start_response)2407    @authorize(logged_in)2408    def ticket_priorities(self):2409        items=[]2410        for row in TicketPriority.query.all():2411            items.append({'id': row.id, 'name': row.name, 'description': row.description})2412        db.remove()2413        out = dict({'identifier': 'id', 'label': 'name', 'items': items})2414        response = make_response(out)2415        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2416        return response(request.environ, self.start_response)2417    @authorize(logged_in)2418    def ticket_add(self, **kw):2419        schema = TicketForm()2420        try:2421            form_result = schema.to_python(request.params)2422            t = Ticket()2423            t.subject = form_result.get('subject')2424            t.description = form_result.get('description')2425            t.customer_id = session['customer_id']2426            t.opened_by = form_result.get('user_id')2427            t.ticket_status_id = form_result.get('status_id')2428            t.ticket_priority_id = form_result.get('priority_id')2429            t.ticket_type_id = form_result.get('type_id')2430            t.expected_resolution_date = form_result.get('expected_resolution_date')2431            db.add(t)2432            db.commit(); db.flush()2433        except validators.Invalid, error:2434            db.remove()2435            return 'Validation Error: %s' % error2436        db.remove()2437        return "Successfully added ticket."2438    @authorize(logged_in)2439    def update_ticket_grid(self, **kw):2440        w = loads(urllib.unquote_plus(request.params.get("data")))2441        for i in w['modified']:2442            ticket = Ticket.query.filter_by(id=i['id']).first()2443            ticket.ticket_status_id = int(i['status'])2444            ticket.ticket_type_id = int(i['type'])2445            ticket.ticket_priority_id = int(i['priority'])2446            db.commit(); db.flush()2447            db.remove()2448        return "Successfully updated ticket."2449    @authorize(logged_in)2450    def ticket_view_by_id(self, id):2451        items=[]2452        notes=[]2453        for row in Ticket.query.filter_by(customer_id=session['customer_id']).filter(Ticket.id==id).all():2454            for note in TicketNote.query.filter_by(ticket_id=row.id).all():2455                notes.append({'id': note.id, 'ticket_id': note.ticket_id, 'user_id': note.user_id,2456                              'created': note.created.strftime("%m/%d/%Y %I:%M:%S %p"), 'subject': note.subject,2457                              'description': note.description})2458            items.append({'id': row.id, 'customer_id': row.customer_id, 'opened_by': row.opened_by,2459                          'status': row.ticket_status_id, 'priority': row.ticket_priority_id,2460                          'type': row.ticket_type_id, 'created': row.created.strftime("%m/%d/%Y %I:%M:%S %p"),2461                          'expected_resolve_date': row.expected_resolve_date.strftime("%m/%d/%Y %I:%M:%S %p"),2462                          'subject': row.subject, 'description': row.description, 'notes': notes})2463        out = dict({'identifier': 'id', 'label': 'id', 'items': items})2464        response = make_response(out)2465        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2466        return response(request.environ, self.start_response)2467    @authorize(logged_in)2468    def ticket_notes_by_id(self, id):2469        items=[]2470        for note in TicketNote.query.filter_by(ticket_id=id).all():2471            items.append({'id': note.id, 'ticket_id': note.ticket_id, 'user_id': note.user_id,2472                          'created': note.created.strftime("%m/%d/%Y %I:%M:%S %p"), 'subject': note.subject,2473                          'description': note.description})2474        out = dict({'identifier': 'id', 'label': 'subject', 'items': items})2475        response = make_response(out)2476        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]2477        return response(request.environ, self.start_response)2478    @authorize(logged_in)2479    def add_ticket_note(self, **kw):2480        schema = TicketNoteForm()2481        try:2482            form_result = schema.to_python(request.params)2483            t = TicketNote()2484            t.ticket_id = form_result.get('ticket_note_id')2485            t.subject = form_result.get('ticket_subject')2486            t.description = form_result.get('ticket_note')2487            t.user_id = form_result.get('user_id')2488            db.add(t)2489            db.commit(); db.flush()2490        except validators.Invalid, error:2491            db.remove()2492            return 'Validation Error: %s' % error2493        db.remove()...call_center.py
Source:call_center.py  
1""" This Source Code Form is subject to the terms of the Mozilla Public2    License, v. 2.0. If a copy of the MPL was not distributed with this3    file, You can obtain one at http://mozilla.org/MPL/2.0/.4    Software distributed under the License is distributed on an "AS IS"5    basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the6    License for the specific language governing rights and limitations7    under the License.8    The Original Code is FreePyBX/VoiceWARE.9    The Initial Developer of the Original Code is Noel Morgan,10    Copyright (c) 2011-2012 VoiceWARE Communications, Inc. All Rights Reserved.11    http://www.vwci.com/12    You may not remove or alter the substance of any license notices (including13    copyright notices, patent notices, disclaimers of warranty, or limitations14    of liability) contained within the Source Code Form of the Covered Software,15    except that You may alter any license notices to the extent required to16    remedy known factual inaccuracies."""17import logging18from datetime import datetime19from pylons import request, response, session, config, tmpl_context as c, url20from pylons.controllers.util import abort, redirect21from freepybx.lib.base import BaseController, render22from freepybx.model import meta23from freepybx.model.meta import *24from freepybx.lib.util import *25from itertools import chain26from genshi import HTML27from pylons.decorators.rest import restrict28from genshi import HTML29import formencode30from formencode import validators31from freepybx.lib.pymap.imap import Pymap32from freepybx.lib.auth import *33from freepybx.lib.validators import *34from decorator import decorator35from pylons.decorators.rest import restrict36import formencode37from formencode import validators38from pylons.decorators import validate39from simplejson import loads, dumps40from webob import Request, Response41import simplejson as json42import transaction43import pprint44import os, sys45from stat import *46from webob import Request, Response47import cgi48import simplejson as json49from simplejson import loads, dumps50import os, sys51import simplejson as json52from simplejson import loads, dumps53import urllib, urllib254from freepybx.model import meta55from freepybx.model.meta import *56from freepybx.model.meta import Session as db57import cgitb; cgitb.enable()58logged_in = IsLoggedIn()59log = logging.getLogger(__name__)60DEBUG=False61fs_vm_dir = config['app_conf']['fs_vm_dir']62ESL_HOST = config['app_conf']['esl_host']63ESL_PORT = config['app_conf']['esl_port']64ESL_PASS = config['app_conf']['esl_pass']65class DataInputError(Exception):66    message=""67    def __init__(self, message=None):68        Exception.__init__(self, message or self.message)69class CallCenterController(BaseController):70    @authorize(logged_in)71    def queues(self):72        items=[]73        for queue in CallCenterQueue.query.filter_by(context=session['context']).all():74            items.append({'id': queue.id, 'name': queue.name})75        out = dict({'identifier': 'name', 'label': 'name', 'items': items})76        response = make_response(out)77        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]78        return response(request.environ, self.start_response)79    @authorize(logged_in)80    def ccq_add(self):81        schema = QueueForm()82        try:83            form_result = schema.to_python(request.params)84            ccq = CallCenterQueue()85            ccq.name = form_result['name']86            ccq.context = session['context']87            ccq.domain = session['context']88            ccq.audio_type = form_result.get('audio_name').split(",")[0]89            ccq.audio_name = form_result.get('audio_name').split(",")[1]90            ccq.moh_sound = form_result.get('moh_sound', 'local_stream://moh')91            ccq.time_base_score = form_result.get('time_base_score', 'system')92            ccq.max_wait_time = form_result.get('max_wait_time', 0)93            ccq.max_wait_time_with_no_agent = form_result.get('max_wait_time_with_no_agent', 0)94            ccq.max_wait_time_with_no_agent_reached = form_result.get('max_wait_time_with_no_agent_reached', 5)95            ccq.tier_rules_apply = form_result.get('tier_rules_apply', False)96            ccq.tier_rule_wait_second = form_result.get('tier_rule_wait_second', 300)97            ccq.tier_rule_wait_multiply_level = form_result.get('tier_rule_wait_multiply_level', False)98            ccq.tier_rule_agent_no_wait = form_result.get('tier_rule_agent_no_wait', False)99            ccq.discard_abandoned_after = form_result.get('discard_abandoned_after', 1800)100            ccq.abandoned_resume_allowed = form_result.get('abandoned_resume_allowed', False)101            ccq.strategy = form_result.get('strategy', 'callback')102            ccq.failed_route_id = form_result.get('failed_route_id', 0)103            ccq.record_calls = form_result.get('record_calls', False)104            ccq.announce_position = form_result.get('announce_position', False)105            ccq.announce_sound = form_result.get('announce_sound').split(",")[1]106            ccq.announce_frequency = form_result.get('announce_frequency')107            db.add(ccq)108            db.commit()109            db.flush()110            dir = fs_vm_dir+session['context']+"/queue-recordings/"+ccq.name111            if not os.path.exists(dir):112                os.makedirs(dir)113        except validators.Invalid, error:114            db.remove()115            return 'Error: %s.' % error116        r = PbxRoute()117        r.context = session['context']118        r.domain = session['context']119        r.name = form_result['name']120        r.continue_route = True121        r.voicemail_enable = True122        r.voicemail_ext = form_result['name']123        r.pbx_route_type_id = 10124        r.pbx_to_id = ccq.id125        db.add(r)126        db.commit()127        db.flush()128        db.remove()129        return "Successfully added Call Center queue "+form_result['name']+"."130    @authorize(logged_in)131    def ccq_edit(self):132        schema = QueueEditForm()133        try:134            form_result = schema.to_python(request.params)135            ccq =  CallCenterQueue.query.filter_by(context=session['context']).filter_by(id=form_result.get('ccq_id')).first()136            ccq.context = session['context']137            ccq.domain = session['context']138            ccq.audio_type = form_result.get('audio_name').split(",")[0]139            ccq.audio_name = form_result.get('audio_name').split(",")[1]140            ccq.moh_sound = form_result.get('moh_sound', 'local_stream://moh')141            ccq.time_base_score = form_result.get('time_base_score', 'system')142            ccq.max_wait_time = form_result.get('max_wait_time', 0)143            ccq.max_wait_time_with_no_agent = form_result.get('max_wait_time_with_no_agent', 0)144            ccq.max_wait_time_with_no_agent_reached = form_result.get('max_wait_time_with_no_agent_reached', 5)145            ccq.tier_rules_apply = form_result.get('tier_rules_apply', False)146            ccq.tier_rule_wait_second = form_result.get('tier_rule_wait_second', 300)147            ccq.tier_rule_wait_multiply_level = form_result.get('tier_rule_wait_multiply_level', False)148            ccq.tier_rule_agent_no_wait = form_result.get('tier_rule_agent_no_wait', False)149            ccq.discard_abandoned_after = form_result.get('discard_abandoned_after', 1800)150            ccq.abandoned_resume_allowed = form_result.get('abandoned_resume_allowed', False)151            ccq.strategy = form_result.get('strategy')152            ccq.failed_route_id = form_result.get('failed_route_id', 0)153            ccq.record_calls = form_result.get('record_calls', False)154            ccq.announce_position = form_result.get('announce_position', False)155            ccq.announce_sound = form_result.get('announce_sound').split(",")[1]156            ccq.announce_frequency = form_result.get('announce_frequency')157            db.commit()158            db.flush()159        except validators.Invalid, error:160            db.remove()161            return 'Error: %s.' % error162        db.remove()163        return "Successfully updated Call Center queue "+ccq.name+"."164    def ccq_by_id(self, id, **kw):165        items=[]166        for ccq in CallCenterQueue.query.filter_by(context=session['context']).filter_by(id=id).all():167            items.append({'id': ccq.id, 'name': ccq.name, 'audio_type': ccq.audio_type, 'audio_name': str(ccq.audio_type)+","+str(ccq.audio_name),168                          'moh_sound': ccq.moh_sound, 'time_base_score': ccq.time_base_score, 'max_wait_time': ccq.max_wait_time,169                          'max_wait_time_with_no_agent': ccq.max_wait_time_with_no_agent, 'max_wait_time_with_no_agent_reached': ccq.max_wait_time_with_no_agent_reached,170                          'tier_rules_apply': ccq.tier_rules_apply, 'tier_rule_wait_second': ccq.tier_rule_wait_second, 'tier_rule_wait_multiply_level': ccq.tier_rule_wait_multiply_level,171                          'tier_rule_agent_no_wait': ccq.tier_rule_agent_no_wait, 'discard_abandoned_after': ccq.discard_abandoned_after,172                          'abandoned_resume_allowed': ccq.abandoned_resume_allowed, 'strategy': ccq.strategy, 'failed_route_id': ccq.failed_route_id,173                          'record_calls': ccq.record_calls, 'announce_position': ccq.announce_position, 'announce_sound': "1,"+ccq.announce_sound,174                          'announce_frequency': ccq.announce_frequency})175        out = dict({'identifier': 'id', 'label': 'name', 'items': items})176        response = make_response(out)177        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]178        return response(request.environ, self.start_response)179    @authorize(logged_in)180    def ccq_audio(self):181        items = []182        dir = fs_vm_dir+session['context']+"/recordings/"183        for i in os.listdir(dir):184            fo = generateFileObject(i, "",  dir)185            items.append({'id': '1,'+fo["name"], 'name': 'Recording: '+fo["name"] , 'data': fo["path"], 'type': 1, 'real_id': ""})186        items.append({'id': '0,local_stream://moh', 'name': 'Default Music on Hold' , 'data': 'local_stream://moh', 'type': 1, 'real_id': ""})187        out = dict({'identifier': 'id', 'label': 'name', 'items': items})188        response = make_response(out)189        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]190        return response(request.environ, self.start_response)191    @authorize(logged_in)192    def delete_queue(self, **kw):193        id = request.params.get('id', None)194        q = CallCenterQueue.query.filter(CallCenterQueue.id==id).filter(CallCenterQueue.context==session['context']).first()195        queue = CallCenterQueue.query.filter(CallCenterQueue.id==q.id).first()196        CallCenterTier.query.filter(CallCenterTier.queue_id==queue.id).delete()197        CallCenterQueue.query.filter(CallCenterQueue.id==q.id).delete()198        db.commit()199        db.flush()200        db.remove()201        return "Successfully removed queue."202    @authorize(logged_in)203    def agents(self):204        items=[]205        for agent in CallCenterAgent.query.filter_by(context=session['context']).all():206            items.append({'id': agent.id, 'extension': agent.extension, 'status': agent.status})207        out = dict({'identifier': 'extension', 'label': 'extension', 'items': items})208        response = make_response(out)209        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]210        return response(request.environ, self.start_response)211    @authorize(logged_in)212    def agent_avail_endpoints(self):213        items=[]214        ext = request.params.get('ext', None)215        if ext:216            items.append({'id': 0, 'extension': ext})217        for row in PbxEndpoint.query.filter_by(user_context=session['context']).order_by(PbxEndpoint.auth_id).all():218            if CallCenterAgent.query.filter_by(extension=row.auth_id).filter_by(context=session['context']).count()>0:219                continue220            items.append({'id': row.id, 'extension': row.auth_id})221        out = dict({'identifier': 'extension', 'label': 'extension', 'items': items})222        response = make_response(out)223        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]224        return response(request.environ, self.start_response)225    @authorize(logged_in)226    def agent_endpoints(self):227        items=[]228        for row in PbxEndpoint.query.filter_by(user_context=session['context']).order_by(PbxEndpoint.auth_id).all():229            items.append({'id': row.id, 'extension': row.auth_id})230        out = dict({'identifier': 'extension', 'label': 'extension', 'items': items})231        response = make_response(out)232        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]233        return response(request.environ, self.start_response)234    @authorize(logged_in)235    def agent_add(self):236        schema = AgentForm()237        try:238            form_result = schema.to_python(request.params)239            cca = CallCenterAgent()240            cca.extension = form_result.get('extension')241            e = PbxEndpoint.query.filter_by(user_context=session['context']).filter(PbxEndpoint.auth_id==cca.extension).first()242            cca.context = session['context']243            cca.domain = session['context']244            cca.type = 'callback'245            cca.system = 'single_box'246            cca.name = cca.extension+"@"+session['context']247            cca.timeout = form_result.get('timeout', 30)248            cca.contact = "[call_timeout="+cca.timeout+"]user/"+cca.name249            cca.max_no_answer = form_result.get('max_no_answer', 3)250            cca.wrap_up_time = form_result.get('wrap_up_time', 30)251            cca.reject_delay_time = form_result.get('reject_delay_time', 30)252            cca.busy_delay_time = form_result.get('busy_delay_time', 0)253            cca.no_answer_delay_time = form_result.get('no_answer_delay_time', 5)254            cca.record_calls = form_result.get('record_calls', 0)255            cca.status = 'Available'256            cca.state = 'Waiting'257            cca.user_id = e.user_id258            cca.pbx_endpoint_id = e.id259            db.add(cca)260            db.commit()261            db.flush()262        except validators.Invalid, error:263            db.remove()264            return 'Error: %s.' % error265        db.remove()266        return "Successfully added agent."267    @authorize(logged_in)268    def agent_edit(self):269        schema = AgentEditForm()270        try:271            form_result = schema.to_python(request.params)272            cca = CallCenterAgent.query.filter_by(context=session['context']).filter(CallCenterAgent.id==form_result.get('agent_id')).first()273            cca.extension = form_result.get('extension')274            e = PbxEndpoint.query.filter_by(user_context=session['context']).filter(PbxEndpoint.auth_id==cca.extension).first()275            cca.context = session['context']276            cca.domain = session['context']277            cca.type = 'callback'278            cca.record_calls = form_result.get('record_calls', 0)279            cca.timeout = form_result.get('timeout', 30)280            cca.max_no_answer = form_result.get('max_no_answer', 3)281            cca.wrap_up_time = form_result.get('wrap_up_time', 30)282            cca.reject_delay_time = form_result.get('reject_delay_time', 30)283            cca.busy_delay_time = form_result.get('busy_delay_time', 0)284            cca.no_answer_delay_time = form_result.get('no_answer_delay_time', 5)285            cca.user_id = e.user_id286            cca.pbx_endpoint_id = e.id287            db.commit()288            db.flush()289        except validators.Invalid, error:290            db.remove()291            return 'Error: %s.' % error292        db.remove()293        return "Successfully edited agent."294    @restrict("GET")295    @authorize(logged_in)296    def del_agent(self, **kw):297        try:298            CallCenterAgent.query.filter_by(id=request.params.get('id', 0)).delete()299            db.commit()300            db.flush()301            db.remove()302        except:303            return "Error deleting agent."304        return  "Successfully deleted agent."305    def cca_by_id(self, id, **kw):306        items=[]307        for cca in CallCenterAgent.query.filter_by(context=session['context']).filter_by(id=id).all():308            items.append({'id': cca.id, 'extension': cca.extension, 'type': cca.type, 'timeout': cca.timeout,309                          'max_no_answer': cca.max_no_answer, 'wrap_up_time': cca.wrap_up_time, 'reject_delay_time': cca.reject_delay_time,310                          'busy_delay_time': cca.busy_delay_time, 'no_answer_delay_time': cca.no_answer_delay_time, 'record_calls': cca.record_calls})311        out = dict({'identifier': 'id', 'label': 'name', 'items': items})312        response = make_response(out)313        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]314        return response(request.environ, self.start_response)315    @authorize(logged_in)316    def update_agent_grid(self):317        try:318            w = loads(urllib.unquote_plus(request.params.get("data")))319            for i in w['modified']:320                log.debug(w['modified'])321                fsa = CallCenterAgent.query.filter(CallCenterAgent.name==str(i['extension'])+"@"+str(session['context'])).first()322                fsa.status = i['status']323                db.commit()324                db.flush()325                db.remove()326        except DataInputError, error:327            return 'Error: %s' % error328        return "Successfully update agent."329    @authorize(logged_in)330    def tiers(self):331        items=[]332        for tier in CallCenterTier.query.join(CallCenterQueue).filter(CallCenterQueue.context==session['context']).all():333            agent = get_agent(tier.agent_id)334            queue = get_queue(tier.queue_id)335            items.append({'id': tier.id, 'agent': agent.extension, 'queue': queue.name, 'level': tier.level, 'position': tier.position, 'state': tier.state})336        out = dict({'identifier': 'id', 'label': 'agent', 'items': items})337        response = make_response(out)338        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]339        return response(request.environ, self.start_response)340    @authorize(logged_in)341    def tier_add(self):342        schema = TierForm()343        try:344            form_result = schema.to_python(request.params)345            log.debug("######################" + form_result.get('queue_name'))346            cca = CallCenterAgent.query.filter_by(extension=form_result.get('agent_extension', None)).filter_by(context=session['context']).first()347            cur_cct = CallCenterTier.query.filter_by(agent=cca.name).first()348            ccq = CallCenterQueue.query.filter_by(name=form_result.get('queue_name', None)).first()349            if cur_cct:350                return "Agent in tier already exists!"351            cct = CallCenterTier()352            cct.extension = cca.extension353            cct.queue_id = ccq.id354            cct.agent_id = cca.id355            cct.queue = str(ccq.name)+"@"+session['context']356            cct.agent = str(cca.extension)+"@"+session['context']357            cct.level = form_result.get('level', 1)358            cct.state = 'Ready'359            cct.position = form_result.get('position', 1)360            cct.context = session['context']361            cct.domain = session['context']362            db.add(cct)363            db.commit()364            db.flush()365        except validators.Invalid, error:366            db.remove()367            return 'Error: %s.' % error368        db.remove()369        return "Successfully created tier agent."370    @authorize(logged_in)371    def update_tier_grid(self):372        try:373            w = loads(urllib.unquote_plus(request.params.get("data")))374            for i in w['modified']:375                log.debug(w['modified'])376                tier = CallCenterTier.query.filter_by(id=i['id']).first()377                tier.state = i['state']378                tier.level = i['level']379                tier.position = i['position']380                db.commit()381                db.flush()382                db.remove()383        except DataInputError, error:384            return 'Error: %s' % error385        return "Sucessfully updated agent tiers."386    @restrict("GET")387    @authorize(logged_in)388    def del_tier(self, **kw):389        try:390            CallCenterTier.query.filter_by(id=request.params.get('id', 0)).delete()391            db.commit()392            db.flush()393            db.remove()394        except:395            return "Error deleting tier agent."396        return  "Successfully deleted tier agent."397    def cc_cdr_stats(self):398        pass399    def get_queue_calls(self):400        log.debug(request.params.get("sid"))401        user = User.query.filter_by(session_id=request.params.get("sid")).first()402        if user:403            context = user.get_context()404        else:405            return ""406        items = []407        sql = "SELECT * FROM call_center_callers WHERE queue like '%@{0}'".format(context)408        for call in db.execute(sql):409            items.append({'queue': call.queue.split("@")[0], 'cid_name': call.cid_name, 'cid_number': call.cid_number, 'agent': call.serving_agent.split("@")[0], 'state': call.state, 'uuid': call.uuid})410        if not len(items) == 0:411            return ""412        out = items413        response = make_response(out)414        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]415        return response(request.environ, self.start_response)416    @restrict("POST")417    @authorize(logged_in)418    def delete_queue_recording(self, **params):419        try:420            path = request.params.get("data")421            queue = request.params.get("queue_name")422            file_name = path.split("/")[len(path.split("/"))-1]423            dir = fs_vm_dir+session['context']+"/queue-recordings/"+queue+"/"424            os.remove(os.path.join(dir, file_name))425        except:426            return "Error..."427        return "Deleted queue recording."428    @authorize(logged_in)429    def get_queue_recordings(self):430        files = []431        queue = request.params.get("queue_name")432        dir = fs_vm_dir+session['context']+"/queue-recordings/"+queue433        for i in os.listdir(dir):434            path = dir+"/"+i435            id = i.split(".")[3].strip()436            row = PbxCdr.query.filter(PbxCdr.uuid==id).first()437            if row:438                caller = row.caller_id_number[len(row.caller_id_number)-10:]439                dest = row.destination_number440                agent = PbxCdr.query.filter(PbxCdr.uuid==row.bleg_uuid).first()441                agent_ext = agent.destination_number442            else:443                agent_ext = "No CDR"444                dest = "No CDR"445                caller = "No CDR"446            tpath = "/vm/" +session['context']+"/queue-recordings/"+queue+"/"+i447            received = str(modification_date(path)).strip("\"")448            fsize = str(os.path.getsize(path))449            files.append({'name': caller, 'queue': queue, 'destination': dest, 'agent': agent_ext, 'path': tpath, 'received': received, 'size': fsize})450        db.remove()451        out = dict({'identifier': 'path', 'label': 'name', 'items': files})452        response = make_response(out)453        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]454        return response(request.environ, self.start_response)455    @authorize(logged_in)456    def ad_audio(self):457        items = []458        dir = fs_vm_dir+session['context']+"/recordings/"459        try:460            for i in os.listdir(dir):461                fo = generateFileObject(i, "",  dir)462                items.append({'id': '1,'+fo["name"], 'name': 'Recording: '+fo["name"] , 'data': fo["path"], 'type': 1, 'real_id': ""})463            db.remove()464        except:465            pass466        out = dict({'identifier': 'id', 'label': 'name', 'items': items})467        response = make_response(out)468        response.headers = [("Content-type", 'application/json; charset=UTF-8'),]469        return response(request.environ, self.start_response)470    ...main.py
Source:main.py  
1import numpy as nm2import pytesseract3import re4import pydirectinput5import time6import cv27import math8from PIL import ImageGrab9from PIL import ImageFilter10import sched11import sys12import tkinter13from tkinter import ttk, simpledialog, messagebox14from throttle import *15import requests16import logging17from win32 import win32api18import webbrowser19import ctypes20from ahk import AHK21from multiprocessing import Process, Value22import socket23from flask import Flask24from flask import render_template25from flask import request, redirect, send_file26active = Value(ctypes.c_bool, False)27newchange = Value(ctypes.c_bool, False)28def ws(active, newchange):29    app = Flask(__name__)30    @app.route('/')31    def home():32        return render_template("index.html", toggle=active.value)33    @app.route('/status')34    def status():35        status = { "toggle": active.value }36        return status37    @app.route('/status/off')38    def status_off():39        active.value = False40        status = { "toggle": active.value, "response": 200 }41        return status42    @app.route('/status/on')43    def status_on():44        active.value = True45        status = { "toggle": active.value, "response": 200 }46        return status47    @app.route('/shot')48    def shot():49        im = ImageGrab.grab()50        im.save("temp/screenshot.png")51        return send_file("temp/screenshot.png", "PNG")52    @app.route("/send", methods=["POST"])53    def send():54        newchange.value = True55        form = request.form56        try:57            if form["switch"] == "on":58                active.value = True59            else:60                active.value = False61        except:62            active.value = False63        return redirect("/")64    def run():65        app.run(host='0.0.0.0', port='7878')66    run()67if __name__ == '__main__':68    root = tkinter.Tk()69    photo = tkinter.PhotoImage(file="img/ap_icon_new.png")70    root.title("button")71    screen_width = root.winfo_screenwidth()72    screen_height = root.winfo_screenheight()73    w = 5074    h = 5075    x = 10076    y = 10077    root.geometry('%dx%d+%d+%d' % (w, h, x, y))78    root.lift()79    root.overrideredirect(True)80    root.call('wm', 'attributes', '.', '-topmost', '1')81    button = tkinter.Button(root, text="button1",82                            image=photo, bg="orange")83    button.grid(column=1, row=1, sticky=tkinter.E+tkinter.W)84    root.grid_columnconfigure(2, weight=2)85    try:86        ahk = AHK()87    except:88        print("AutoHotkey was not found! Please install it in order to continue.")89        exit()90    continue_route = False91    print("SCR-Autopilot v0.4.1-beta by MaTY")92    93    print("Checking for updates...")94    URL = "https://matyapi.matymt.repl.co/scr-autopilot/newest-version"95    r = requests.get(url=URL)96    data = r.json()97    version = data['version']98    if not version == "0.4.1":99        print("Your version is outdated! Please install the latest release on https://github.com/scr-autopilot/scr-autopilot/releases")100        outdatedask = messagebox.askyesno(101            "SCR-Autopilot", "Your version of SCR-Autopilot is outdated. Do you want to go to the releases page to download a new version?")102        if outdatedask == True:103            webbrowser.open(104                "https://github.com/scr-autopilot/scr-autopilot/releases")105            exit()106    else:107        print("Your version is up-to-date.")108    logging.basicConfig(filename='autopilot.log', filemode='w',109                        level=logging.DEBUG, format="[%(levelname)s] [%(asctime)s] %(message)s")110    print("\nDisclaimer:\nSCR-Autopilot is still in a beta version so it can't handle some situations well.\nWe recommend using SCR-Autopilot on private servers.\nUSE OF THIS SOFTWARE AT YOUR RISK.\nWaiting for the user input in the dialog box.")111    warningask = messagebox.askokcancel("Disclaimer", "SCR-Autopilot is still in a beta version so it can't handle some situations well.\nWe recommend using SCR-Autopilot on private servers.\n\nUSE OF THIS SOFTWARE AT YOUR RISK.", icon='warning')112    if warningask == False:113        exit()114    display_size = ImageGrab.grab().size115    logging.debug(f'Display resolution: {display_size[0]}, {display_size[1]}')116    resolution = simpledialog.askstring(117        "Question", "What is the resolution? (fhd, hd)")118    if resolution == "fhd":119        spd_pos = 884, 957, 947, 985120        lim_pos = 889, 987, 942, 1016121        green_pos = 1440, 983, 1441, 984122        yellow_pos = 1438, 1016, 1439, 1017123        double_yellow_pos = 1438, 950, 1439, 951124        red_pos = 1438, 1045, 1439, 1046125        distance_pos = 555, 1046, 605, 1070126        awsbutton_pos = 1330, 994, 1331, 995127        throttle_pos = 843, 931, 845, 1074128        doors_pos = 870, 822, 871, 823129        loading_pos = 781, 823, 782, 824130        continue_pos = 1032, 460, 1033, 461131        undershoot_pos = 709, 906, 710, 907132        awaiting_pos = 862, 823, 863, 824133        buzzer_pos = 824, 816, 825, 817134    elif resolution == "hd":135        messagebox.showerror(136            "Error", 'HD resolution is not supported in this version of SCR-Autopilot. Please install v0.3.1-beta to use the HD resolution.')137        sys.exit()138        time.sleep(1)139        spd_pos = 573, 594, 630, 630140        lim_pos = 569, 627, 618, 653141        green_pos = 1118, 624, 1119, 625142        yellow_pos = 1120, 654, 1121, 655143        double_yellow_pos = 1120, 590, 1121, 591144        red_pos = 1120, 688, 1121, 689145        distance_pos = 239, 686, 284, 708146        awsbutton_pos = 1047, 597, 1048, 598147        throttle_pos = 522, 570, 525, 713148    else:149        messagebox.showerror(150            "Error", 'Please type only "fhd" (without the quotation marks) if you have FHD monitor, or type "hd" (without the quotation marks) if you have HD monitor.')151        sys.exit()152    max_speed = simpledialog.askinteger(153        "Question", "What is the maximum speed of your train in MPH? (E.g. 100, 125, 75 etc.)", minvalue=1)154    continue_ask = messagebox.askyesno(155        "Question", "Would you like to automatically continue in the route after finsihing?")156    if max_speed == None:157        messagebox.showerror("Error", 'Settings incorrect. Please try again.')158        exit()159    if continue_ask == True:160        continue_route = True161    PROCESS_PER_MONITOR_DPI_AWARE = 2162    MDT_EFFECTIVE_DPI = 0163    def print_dpi():164        shcore = ctypes.windll.shcore165        monitors = win32api.EnumDisplayMonitors()166        hresult = shcore.SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE)167        assert hresult == 0168        dpiX = ctypes.c_uint()169        dpiY = ctypes.c_uint()170        for i, monitor in enumerate(monitors):171            shcore.GetDpiForMonitor(172                monitor[0].handle,173                MDT_EFFECTIVE_DPI,174                ctypes.byref(dpiX),175                ctypes.byref(dpiY)176            )177            logging.debug(178                f"Monitor {i} = dpiX: {dpiX.value}, dpiY: {dpiY.value}"179            )180    print_dpi()181    pytesseract.pytesseract.tesseract_cmd = 'C:/Program Files (x86)/Tesseract-OCR/tesseract.exe'182    time.sleep(1)183    solve = None184    continuing = False185    ignorelim = False186    ignoreaws = False187    wsask = continue_ask = messagebox.askyesno(188        "Question", "Would you like to start a webserver so you can remotely control the autopilot?")189    if wsask == True:190        print("Starting the webserver...")191        p = Process(target=ws, args=(active,newchange,))192        p.start()193        time.sleep(3)194    print("\n\n\n\n\n\n\n\n\n\n\n\n\n\n")195    print("""  ___  ___ ___      _       _            _ _     _   196    / __|/ __| _ \___ /_\ _  _| |_ ___ _ __(_) |___| |_197    \__ \ (__|   /___/ _ \ || |  _/ _ \ '_ \ | / _ \  _|198    |___/\___|_|_\  /_/ \_\_,_|\__\___/ .__/_|_\___/\__|199                                    |_|               200    """)201    print("Press the red button that has appeared on your screen to engage the autopilot. You can press the button again to disengage the autopilot.")202    if wsask == True:203        print("\n\nFor the remote control, navigate to:", "http://" + socket.gethostbyname(socket.gethostname()) + ":7878 on a different device.","\nYou need to be on a same network to open the website.\n\n")204    print("Settings:")205    print("Screen resolution:", resolution)206    print("Train max speed:", max_speed)207    print("Automatically continue:", continue_route)208    def task():209        global solve210        global continuing211        global ignorelim212        global ignoreaws213        print("ignorelim", ignorelim)214        if continue_route == True:215            im = ImageGrab.grab(bbox=(continue_pos))216            pix = im.load()217            continue_value = pix[0, 0]  # Set the RGBA Value of the image (tuple)218            if continue_value == (255, 255, 255):219                continuing = True220                ahk.click(991, 470)221                ahk.click(327, 833)222        im = ImageGrab.grab(bbox=(awsbutton_pos))223        pix = im.load()224        awsbutton_value = pix[0, 0]  # Set the RGBA Value of the image (tuple)225        if awsbutton_value == (255, 255, 255):226            pydirectinput.keyDown("q")227            pydirectinput.keyUp("q")228            print("Reset the AWS")229        logging.debug(f'AWS pixel RGB: {awsbutton_value}')230        cap = ImageGrab.grab(bbox=(throttle_pos))231        img = cap232        count = 0233        bottom_throttle_pixel = None234        for y in range(img.height):235            for x in range(img.width):236                pixel = img.getpixel((x, y))237                if y == img.height - 1:238                    bottom_throttle_pixel = pixel239                if pixel == (0, 176, 85):240                    count += 1241        currentThrottle = int(math.floor(100 * (count / 142)))242        speed = currentThrottle/100 * max_speed243        if currentThrottle == 0:244            logging.debug(f'Throttle pixel RGB: {bottom_throttle_pixel}')245        print("Current throttle: ", currentThrottle)246        if currentThrottle == None:247            messagebox.showerror("Error", "I can't read the throttle")248            supportask = messagebox.askyesno(249                "Question", "It looks like you got an error. You can try again, but if this error persists, you can join the support server. Do you want to join the support server on Discord?")250            if supportask == True:251                webbrowser.open(252                    "https://discord.gg/jtQ2R8cxWq")253                exit()254        else:255            # LIMIT256            cap = ImageGrab.grab(bbox=(lim_pos))257            cap = cap.filter(ImageFilter.MedianFilter())258            cap = cv2.cvtColor(nm.array(cap), cv2.COLOR_RGB2GRAY)259            tesstr = pytesseract.image_to_string(260                cap,261                config="--psm 7")262            lim = 0263            lim = [int(s) for s in re.findall(r'\b\d+\b', tesstr)]264            if lim == []:265                if continuing == False and ignorelim == False:266                    messagebox.showerror("Error", "I can't read the limit")267                    supportask = messagebox.askyesno(268                        "Question", "It looks like you got an error. You can try again, but if this error persists, you can join the support server. Do you want to join the support server on Discord?")269                    if supportask == True:270                        webbrowser.open(271                            "https://discord.gg/jtQ2R8cxWq")272                        exit()273            else:274                cap = ImageGrab.grab()275                src = nm.array(cap)276                gray = cv2.cvtColor(src, cv2.COLOR_RGB2GRAY)277                gray = cv2.medianBlur(gray, 5)278                rows = gray.shape[0]279                circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, rows / 8,280                                        param1=100, param2=30,281                                        minRadius=1, maxRadius=30)282                283                if circles is not None:284                    circles = nm.uint16(nm.around(circles))285                    for i in circles[0, :]:286                        x = i[0] - i[2]287                        y = i[1] - i[2]288                        w = 2*i[2]289                        h = 2*i[2]290                        center = (i[0], i[1])291                        if w > 39:292                            txt = pytesseract.image_to_string(gray[y:y+h, x:x+w], config="--psm 6")293                            if "W" in txt:294                                pydirectinput.keyDown("h")295                                pydirectinput.keyUp("h")296                        cv2.circle(src, center, 1, (0, 100, 100), 3)297                        radius = i[2]298                        cv2.circle(src, center, radius, (255, 0, 255), 3)299                templim = lim[0]300                lim = lim[0]301                lim = int(lim)302                if ignoreaws == False:303                    im = ImageGrab.grab(bbox=(red_pos))304                    pix = im.load()305                    # Set the RGBA Value of the image (tuple)306                    red_value = pix[0, 0]307                    im = ImageGrab.grab(bbox=(yellow_pos))308                    pix = im.load()309                    # Set the RGBA Value of the image (tuple)310                    yellow_value = pix[0, 0]311                    im = ImageGrab.grab(bbox=(green_pos))312                    pix = im.load()313                    # Set the RGBA Value of the image (tuple)314                    green_value = pix[0, 0]315                    im = ImageGrab.grab(bbox=(double_yellow_pos))316                    pix = im.load()317                    # Set the RGBA Value of the image (tuple)318                    double_yellow_value = pix[0, 0]319                    if red_value == (255, 0, 0):320                        print("AWS:", "red")321                        lim = 0322                    if yellow_value == (255, 190, 0):323                        print("AWS:", "yellow")324                        if templim > 45:325                            lim = 45326                    if double_yellow_value == (255, 190, 0):327                        print("AWS:", "double_yellow")328                        if templim > 75:329                            lim = 75330                    if green_value == (0, 255, 0):331                        print("AWS:", "green")332                print("Limit: ", lim)333                limitThrottle = int((lim / max_speed) * 100)334                print("Limit throttle: ", limitThrottle)335                cap = ImageGrab.grab(bbox=(distance_pos))336                cap = cap.filter(ImageFilter.MedianFilter())337                cap = cv2.cvtColor(nm.array(cap), cv2.COLOR_RGB2GRAY)338                tesstr = pytesseract.image_to_string(339                    cap,340                    config="--psm 6")341                distance = 0342                distance = [int(s) for s in re.findall(r'\b\d+\b', tesstr)]343                try:344                    m_distance = distance[0]345                    distance = distance[1]346                    print(m_distance, distance)347                    if distance == 00 and m_distance == 0 or continuing == True:348                        im = ImageGrab.grab(bbox=(loading_pos))349                        pix = im.load()350                        loading_value = pix[0, 0]351                        im = ImageGrab.grab(bbox=(doors_pos))352                        pix = im.load()353                        doors_value = pix[0, 0]354                        im = ImageGrab.grab(bbox=(undershoot_pos))355                        pix = im.load()356                        undershoot_value = pix[0, 0]357                        im = ImageGrab.grab(bbox=(awaiting_pos))358                        pix = im.load()359                        awaiting_value = pix[0, 0]360                        im = ImageGrab.grab(bbox=(buzzer_pos))361                        pix = im.load()362                        buzzer_value = pix[0, 0]363                        print(buzzer_value)364                        if undershoot_value == (255, 255, 255):365                            print("UNDERSHOOT")366                            pydirectinput.keyDown("w")367                            time.sleep(0.4)368                            pydirectinput.keyUp("w")369                        if doors_value == (255, 255, 255):370                            print("CLOSING DOORS")371                            pydirectinput.keyDown("t")372                            pydirectinput.keyUp("t")373                            time.sleep(4)374                            continuing = False375                            ignorelim = False376                            ignoreaws = False377                        elif loading_value == (255, 255, 255):378                            print("LOADING")379                        elif awaiting_value == (255, 255, 255):380                            print("WAITING FOR GUARD")381                        elif buzzer_value == (255, 255, 255):382                            print("ACTIVATING THE BUZZER")383                            pydirectinput.keyDown("t")384                            pydirectinput.keyUp("t")385                        else:386                            print("Autopilot is currently stopping.")387                            pydirectinput.keyDown("s")388                            time.sleep(5)389                            pydirectinput.keyUp("s")390                            pydirectinput.keyDown("t")391                            pydirectinput.keyUp("t")392                    elif distance <= 20 and m_distance == 0:393                        if lim >= 45:394                            print("Slowing down to prepare for station arrival.")395                            ignoreaws = True396                            ignorelim = True397                            throttle(currentThrottle, int((42 / max_speed) * 100))398                        else:399                            throttle(currentThrottle, limitThrottle)400                    else:401                        throttle(currentThrottle, limitThrottle)402                except IndexError:403                    pass404        solve = root.after(600, task)405    checkChanges = None406    def f_checkChanges():407        global checkChanges408        if newchange.value == True:409            newchange.value = False410            if active.value == True:411                button.configure(bg="green")412                root.after(600, task)413            elif active.value == False:414                button.configure(bg="red")415                try:416                    root.after_cancel(solve)417                except:418                    print("Error...")419        checkChanges = root.after(2000, f_checkChanges)420    checkChanges = root.after(2000, f_checkChanges)421    def onClick():422        if active.value == False:423            active.value = True424            button.configure(bg="green")425            root.after(600, task)426        else:427            active.value = False428            button.configure(bg="red")429            root.after_cancel(solve)430    button.configure(bg="red", command=onClick)431    switchask = messagebox.askyesno(432        "SCR-Autopilot", 'Autopilot is set up. Do you want to turn it on now? You can also turn it on or off by using the "AP" button on your screen.')433    if switchask == True:434        onClick()..._network.py
Source:_network.py  
...234        await self._race_with_page_close(235            self._channel.send("continue", cast(Any, overrides))236        )237    def _internal_continue(self) -> None:238        async def continue_route() -> None:239            try:240                await self.continue_()241            except Exception:242                pass243        asyncio.create_task(continue_route())244    async def _race_with_page_close(self, future: Coroutine) -> None:245        if hasattr(self.request.frame, "_page"):246            page = self.request.frame._page247            # When page closes or crashes, we catch any potential rejects from this Route.248            # Note that page could be missing when routing popup's initial request that249            # does not have a Page initialized just yet.250            fut = asyncio.create_task(future)251            await asyncio.wait(252                [fut, page._closed_or_crashed_future],253                return_when=asyncio.FIRST_COMPLETED,254            )255            if page._closed_or_crashed_future.done():256                await asyncio.gather(fut, return_exceptions=True)257        else:...LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!
