<commit_before># -*- coding: utf-8 -*-
from flask import Blueprint, render_template, current_app, request, Response, g, jsonify
from flask.ext.login import login_required

from functools import wraps
import twilio.twiml
from twilio import TwilioRestException
from twilio.rest import TwilioRestClient
from twilio.util import TwilioCapability

from phonedusk.user.models import User, WhitelistPhoneNumber, BlacklistPhoneNumber, UserPhoneNumber


blueprint = Blueprint("api", __name__, url_prefix='/api',
                        static_folder="../static")


def check_api_auth(username, password):
    user = User.query.filter_by(username=username).first()
    if not (user and user.check_password(password) and user.active):
        return False
    g.user = user
    return True


def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_api_auth(auth.username, auth.password):
            return Response('Unauthorized', 401)
        return f(*args, **kwargs)
    return decorated


def returns_xml(f):
    '''Decorator to return an XML response.'''
    @wraps(f)
    def decorated_function(*args, **kwargs):
        r = f(*args, **kwargs)
        return Response(r, content_type='text/xml; charset=utf-8')
    return decorated_function


def returns_plaintext(f):
    '''Decorator to return a plaintext response.'''
    @wraps(f)
    def decorated_function(*args, **kwargs):
        r = f(*args, **kwargs)
        return Response(r, content_type='text/plain; charset=utf-8')
    return decorated_function


@blueprint.route("/capability_token", methods=['GET'])
@requires_auth
@returns_plaintext
def get_capability():
    user = g.user
    capability = TwilioCapability(current_app.config['TWILIO_ACCOUNT_SID'],
                                         current_app.config['TWILIO_AUTH_TOKEN'])
    capability.allow_client_incoming(user.username)
    capability.allow_client_outgoing(current_app.config['TWILIO_ACCOUNT_SID'])
    return capability.generate()


@blueprint.route("/call", methods=['GET', 'POST']) # GET added for debugging
@returns_xml
def twilio_route_incoming_call():
    # Called by twilio at start of incoming voice call
    to_num = request.form['To']
    from_num = request.form['From']

    # TODO: Fix this with SQLAlchemy
    users = User.query.all()
    users = filter(lambda user: to_num in [x.phone_number for x in user.phone_numbers], users)
    if len(users) > 0:
        user = users[0]
        blacklist = user.blacklist_numbers
        whitelist = user.whitelist_numbers
        blacklist_matches = [x for x in blacklist if x.phone_number == from_num]
        whitelist_matches = [x for x in whitelist if x.phone_number == from_num]
    else:
        user = None
    resp = twilio.twiml.Response()
    if not user:
        # User not found by To number, check to see if this is an outgoing call
        # TODO: Refactor spaghetti logic
        users = User.query.all()
        users = filter(lambda user: from_num in [x.phone_number for x in user.phone_numbers], users)
        if len(users) > 0:
            user = users[0]
            with resp.dial(callerId=user.phone_numbers[0].phone_number) as d:
                d.number(to_num)
        else:
            resp.reject('User not found')
    elif user.enable_blacklist and len(blacklist_matches) > 0:
        resp.reject('Blacklisted')
    else:
        with resp.dial() as d:
            d.client(user.username)
    return str(resp)


@blueprint.route("/start_call", methods=['POST'])
@requires_auth
def user_route_outgoing_call():
    to_num = request.form['to']
    from_num = request.form['from']
    if not to_num or not from_num:
        return 'Request missing "to" or "from" parameters'

    try:
        client = TwilioRestClient(current_app.config['TWILIO_ACCOUNT_SID'],
                                  current_app.config['TWILIO_AUTH_TOKEN'])<commit_msg>Implemented whitelisting<commit_after># -*- coding: utf-8 -*-
from flask import Blueprint, render_template, current_app, request, Response, g, jsonify
from flask.ext.login import login_required

from functools import wraps
import twilio.twiml
from twilio import TwilioRestException
from twilio.rest import TwilioRestClient
from twilio.util import TwilioCapability

from phonedusk.user.models import User, WhitelistPhoneNumber, BlacklistPhoneNumber, UserPhoneNumber


blueprint = Blueprint("api", __name__, url_prefix='/api',
                        static_folder="../static")


def check_api_auth(username, password):
    user = User.query.filter_by(username=username).first()
    if not (user and user.check_password(password) and user.active):
        return False
    g.user = user
    return True


def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_api_auth(auth.username, auth.password):
            return Response('Unauthorized', 401)
        return f(*args, **kwargs)
    return decorated


def returns_xml(f):
    '''Decorator to return an XML response.'''
    @wraps(f)
    def decorated_function(*args, **kwargs):
        r = f(*args, **kwargs)
        return Response(r, content_type='text/xml; charset=utf-8')
    return decorated_function


def returns_plaintext(f):
    '''Decorator to return a plaintext response.'''
    @wraps(f)
    def decorated_function(*args, **kwargs):
        r = f(*args, **kwargs)
        return Response(r, content_type='text/plain; charset=utf-8')
    return decorated_function


@blueprint.route("/capability_token", methods=['GET'])
@requires_auth
@returns_plaintext
def get_capability():
    user = g.user
    capability = TwilioCapability(current_app.config['TWILIO_ACCOUNT_SID'],
                                         current_app.config['TWILIO_AUTH_TOKEN'])
    capability.allow_client_incoming(user.username)
    capability.allow_client_outgoing(current_app.config['TWILIO_ACCOUNT_SID'])
    return capability.generate()


@blueprint.route("/call", methods=['GET', 'POST']) # GET added for debugging
@returns_xml
def twilio_route_incoming_call():
    # Called by twilio at start of incoming voice call
    to_num = request.form['To']
    from_num = request.form['From']

    # TODO: Fix this with SQLAlchemy
    users = User.query.all()
    users = filter(lambda user: to_num in [x.phone_number for x in user.phone_numbers], users)
    if len(users) > 0:
        user = users[0]
        blacklist = user.blacklist_numbers
        whitelist = user.whitelist_numbers
        blacklist_matches = [x for x in blacklist if x.phone_number == from_num]
        whitelist_matches = [x for x in whitelist if x.phone_number == from_num]
    else:
        user = None
    resp = twilio.twiml.Response()
    if not user:
        # User not found by To number, check to see if this is an outgoing call
        # TODO: Refactor spaghetti logic
        users = User.query.all()
        users = filter(lambda user: from_num in [x.phone_number for x in user.phone_numbers], users)
        if len(users) > 0:
            user = users[0]
            with resp.dial(callerId=user.phone_numbers[0].phone_number) as d:
                d.number(to_num)
        else:
            resp.reject('User not found')
    elif user.enable_blacklist and len(blacklist_matches) > 0:
        resp.reject('Blacklisted')
    elif user.enable_whitelist:
        if len(whitelist_matches) > 0:
            with resp.dial() as d:
                d.client(user.username)
        else:
            resp.reject('Not in whitelist')
    else:
        with resp.dial() as d:
            d.client(user.username)
    return str(resp)


@blueprint.route("/start_call", methods=['POST'])
@requires_auth
def user_route_outgoing_call():
    to_num = request.form['to']
    from_num = request.form['from']
    if not to_num or not from_num:
        return 'Request missing "to" or "from" parameters'

    try:
        client = TwilioRestClient(current_app.config['TWILIO_ACCOUNT_SID'],
                                  current_app.config['TWILIO_AUTH_TOKEN'])
{'fraction_non_alphanumeric': 0.10604375231738969, 'fraction_numerical': 0.003089852923000865, 'mean_word_length': 3.0704225352112675, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3477477', 'n_tokens_mistral': 2497, 'n_tokens_neox': 2412, 'n_words': 628}