import sys
import traceback

from django.conf import settings
from django.urls import resolve
from lxml import etree
from six.moves.urllib.request import urlopen, Request

class Client(object):
    API_URL = '%s://airbrake.io/notifier_api/v2/notices'
    ERRORS = {
        403: "Cannot use SSL",
        422: "Invalid XML sent to Airbrake",
        500: "Airbrake has braked too hard",
    }

    DEFAULTS = {
        'TIMEOUT': 5,
        'USE_SSL': False,
    }

    @property
    def url(self):
        scheme = 'http'
        if self.settings['USE_SSL']:
            scheme = 'https'

        return Client.API_URL % scheme

    @property
    def settings(self):
        if getattr(self, '_settings', None):
            return self._settings

        self._settings = Client.DEFAULTS
        self._settings.update(getattr(settings, 'AIRBRAKE', {}))
        return self._settings

    def notify(self, exception=None, request=None):
        headers = {
            'Content-Type': 'text/xml'
        }

        payload = self._generate_xml(exception=exception, request=request)
        req = Request(self.url, payload, headers)
        resp = urlopen(req, timeout=self.settings['TIMEOUT'])
        status = resp.getcode()

        if status == 200:
            return True
        elif status in Client.ERRORS:
            raise Exception(Client.ERRORS[status])

    def _generate_xml(self, exception=None, request=None):
        _, _, trace = sys.exc_info()
        notice_em = etree.Element('notice', version='2.0')

        tb = traceback.extract_tb(trace)

        api_key = etree.SubElement(notice_em, 'api-key').text = self.settings['API_KEY']

        notifier_em = etree.SubElement(notice_em, 'notifier')

        etree.SubElement(notifier_em, 'name').text = 'django-airbrake'
        etree.SubElement(notifier_em, 'version').text = '0.0.4'
        url_el = etree.SubElement(notifier_em, 'url')
        url_el.text = 'http://example.com'

        if request:
            request_em = etree.SubElement(notice_em, 'request')

            if request.is_secure():
                scheme = 'https'
            else:
                scheme = 'http'
            url = '%s://%s%s' % (scheme, request.get_host(),
                request.get_full_path())
            etree.SubElement(request_em, 'url').text = str(url)
            url_el.text = url

            cb, _, _ = resolve(request.path)
            etree.SubElement(request_em, 'component').text = str(cb.__module__)
            etree.SubElement(request_em, 'action').text = str(cb.__name__)
            if 'context' in self.settings:
                cgi_em = etree.SubElement(request_em, 'cgi-data')
                for key, val in list(self.settings['context'].items()):
                    var = etree.SubElement(cgi_em, 'var')
                    var.set('key', str(key))
                    var.text = str(val)

            session = list(request.session.items())
            if len(session):
                session_em = etree.SubElement(request_em, 'session')
                for key, val in session:
                    var = etree.SubElement(session_em, 'var')
                    var.set('key', str(key))
                    var.text = str(val)

            if exception:
                error_em = etree.SubElement(notice_em, 'error')

                etree.SubElement(error_em, 'class').text = str(exception.__class__.__name__)
                etree.SubElement(error_em, 'message').text = str(exception)

                backtrace_em = etree.SubElement(error_em, 'backtrace')

                for line in tb:
                    etree.SubElement(backtrace_em, 'line',
                        file=str(line[0]),
                        number=str(line[1]),
                        method=str(line[2]))

        env_em = etree.SubElement(notice_em, 'server-environment')

        etree.SubElement(env_em, 'environment-name').text = self.settings.get('ENVIRONMENT', 'development')

        return '<?xml version="1.0" encoding="UTF-8"?>%s' % etree.tostring(notice_em)

[((1096, 1131), 'six.moves.urllib.request.Request', 'Request', (['self.url', 'payload', 'headers'], {}), '(self.url, payload, headers)\n', (1103, 1131), False, 'from six.moves.urllib.request import urlopen, Request\n'), ((1147, 1193), 'six.moves.urllib.request.urlopen', 'urlopen', (['req'], {'timeout': "self.settings['TIMEOUT']"}), "(req, timeout=self.settings['TIMEOUT'])\n", (1154, 1193), False, 'from six.moves.urllib.request import urlopen, Request\n'), ((1448, 1462), 'sys.exc_info', 'sys.exc_info', ([], {}), '()\n', (1460, 1462), False, 'import sys\n'), ((1483, 1521), 'lxml.etree.Element', 'etree.Element', (['"""notice"""'], {'version': '"""2.0"""'}), "('notice', version='2.0')\n", (1496, 1521), False, 'from lxml import etree\n'), ((1536, 1563), 'traceback.extract_tb', 'traceback.extract_tb', (['trace'], {}), '(trace)\n', (1556, 1563), False, 'import traceback\n'), ((1677, 1716), 'lxml.etree.SubElement', 'etree.SubElement', (['notice_em', '"""notifier"""'], {}), "(notice_em, 'notifier')\n", (1693, 1716), False, 'from lxml import etree\n'), ((1870, 1906), 'lxml.etree.SubElement', 'etree.SubElement', (['notifier_em', '"""url"""'], {}), "(notifier_em, 'url')\n", (1886, 1906), False, 'from lxml import etree\n'), ((3791, 3840), 'lxml.etree.SubElement', 'etree.SubElement', (['notice_em', '"""server-environment"""'], {}), "(notice_em, 'server-environment')\n", (3807, 3840), False, 'from lxml import etree\n'), ((1583, 1621), 'lxml.etree.SubElement', 'etree.SubElement', (['notice_em', '"""api-key"""'], {}), "(notice_em, 'api-key')\n", (1599, 1621), False, 'from lxml import etree\n'), ((1726, 1763), 'lxml.etree.SubElement', 'etree.SubElement', (['notifier_em', '"""name"""'], {}), "(notifier_em, 'name')\n", (1742, 1763), False, 'from lxml import etree\n'), ((1797, 1837), 'lxml.etree.SubElement', 'etree.SubElement', (['notifier_em', '"""version"""'], {}), "(notifier_em, 'version')\n", (1813, 1837), False, 'from lxml import etree\n'), ((1996, 2034), 'lxml.etree.SubElement', 'etree.SubElement', (['notice_em', '"""request"""'], {}), "(notice_em, 'request')\n", (2012, 2034), False, 'from lxml import etree\n'), ((2375, 2396), 'django.urls.resolve', 'resolve', (['request.path'], {}), '(request.path)\n', (2382, 2396), False, 'from django.urls import resolve\n'), ((3850, 3894), 'lxml.etree.SubElement', 'etree.SubElement', (['env_em', '"""environment-name"""'], {}), "(env_em, 'environment-name')\n", (3866, 3894), False, 'from lxml import etree\n'), ((4011, 4036), 'lxml.etree.tostring', 'etree.tostring', (['notice_em'], {}), '(notice_em)\n', (4025, 4036), False, 'from lxml import etree\n'), ((2269, 2304), 'lxml.etree.SubElement', 'etree.SubElement', (['request_em', '"""url"""'], {}), "(request_em, 'url')\n", (2285, 2304), False, 'from lxml import etree\n'), ((2409, 2450), 'lxml.etree.SubElement', 'etree.SubElement', (['request_em', '"""component"""'], {}), "(request_em, 'component')\n", (2425, 2450), False, 'from lxml import etree\n'), ((2489, 2527), 'lxml.etree.SubElement', 'etree.SubElement', (['request_em', '"""action"""'], {}), "(request_em, 'action')\n", (2505, 2527), False, 'from lxml import etree\n'), ((2620, 2660), 'lxml.etree.SubElement', 'etree.SubElement', (['request_em', '"""cgi-data"""'], {}), "(request_em, 'cgi-data')\n", (2636, 2660), False, 'from lxml import etree\n'), ((2987, 3026), 'lxml.etree.SubElement', 'etree.SubElement', (['request_em', '"""session"""'], {}), "(request_em, 'session')\n", (3003, 3026), False, 'from lxml import etree\n'), ((3269, 3305), 'lxml.etree.SubElement', 'etree.SubElement', (['notice_em', '"""error"""'], {}), "(notice_em, 'error')\n", (3285, 3305), False, 'from lxml import etree\n'), ((3508, 3547), 'lxml.etree.SubElement', 'etree.SubElement', (['error_em', '"""backtrace"""'], {}), "(error_em, 'backtrace')\n", (3524, 3547), False, 'from lxml import etree\n'), ((2759, 2790), 'lxml.etree.SubElement', 'etree.SubElement', (['cgi_em', '"""var"""'], {}), "(cgi_em, 'var')\n", (2775, 2790), False, 'from lxml import etree\n'), ((3094, 3129), 'lxml.etree.SubElement', 'etree.SubElement', (['session_em', '"""var"""'], {}), "(session_em, 'var')\n", (3110, 3129), False, 'from lxml import etree\n'), ((3323, 3358), 'lxml.etree.SubElement', 'etree.SubElement', (['error_em', '"""class"""'], {}), "(error_em, 'class')\n", (3339, 3358), False, 'from lxml import etree\n'), ((3416, 3453), 'lxml.etree.SubElement', 'etree.SubElement', (['error_em', '"""message"""'], {}), "(error_em, 'message')\n", (3432, 3453), False, 'from lxml import etree\n')]