# Path: pypi_portal/core/email.py
# def send_exception(subject):
#     """Send Python exception tracebacks via email to the ADMINS list.
# 
#     Use the same HTML styling as Flask tracebacks in debug web servers.
# 
#     This function must be called while the exception is happening. It picks up the raised exception with sys.exc_info().
# 
#     Positional arguments:
#     subject -- subject line of the email (to be prepended by 'Application Error: ').
#     """
#     # Generate and modify html.
#     tb = tbtools.get_current_traceback()  # Get exception information.
#     with _override_html():
#         html = tb.render_full().encode('utf-8', 'replace')
#     html = html.replace('<blockquote>', '<blockquote style="margin: 1em 0 0; padding: 0;">')
#     subject = 'Application Error: {}'.format(subject)
# 
#     # Apply throttle.
#     md5 = hashlib.md5('{}{}'.format(subject, html)).hexdigest()
#     seconds = int(current_app.config['MAIL_EXCEPTION_THROTTLE'])
#     lock = redis.lock(EMAIL_THROTTLE.format(md5=md5), timeout=seconds)
#     have_lock = lock.acquire(blocking=False)
#     if not have_lock:
#         LOG.debug('Suppressing email: {}'.format(subject))
#         return
# 
#     # Send email.
#     msg = Message(subject=subject, recipients=current_app.config['ADMINS'], html=html)
#     mail.send(msg)
# 
# Path: pypi_portal/extensions.py
# LOG = getLogger(__name__)
# def _on_connect(dbapi_connection, **_):


import locale
import os
from logging import getLogger
from celery.signals import task_failure, worker_process_init
from flask import current_app, render_template, request
from markupsafe import Markup
from pypi_portal.core.email import send_exception
from pypi_portal.extensions import db

    Without this, the existing session to the MySQL server is cloned to all Celery workers, so they
    all share a single session. A SQLAlchemy session is not thread/concurrency-safe, causing weird
    exceptions to be raised by workers.

    Based on http://stackoverflow.com/a/14146403/1198943
    """
    LOG.debug('Initializing SQLAlchemy for PID {}.'.format(os.getpid()))
    db.init_app(current_app)


# Send email when a Celery task raises an unhandled exception.
@task_failure.connect
def celery_error_handler(sender, exception, **_):
    exception_name = exception.__class__.__name__
    task_module = sender.name
    send_exception('{} exception in {}'.format(exception_name, task_module))


# Setup default error templates.
@current_app.errorhandler(400)
@current_app.errorhandler(403)
@current_app.errorhandler(404)
@current_app.errorhandler(500)
def error_handler(e):
    code = getattr(e, 'code', 500)  # If 500, e == the exception.
    if code == 500:
        # Send email to all ADMINS.
        exception_name = e.__class__.__name__
        view_module = request.endpoint

# Path: pypi_portal/core/email.py
# def send_exception(subject):
#     """Send Python exception tracebacks via email to the ADMINS list.
# 
#     Use the same HTML styling as Flask tracebacks in debug web servers.
# 
#     This function must be called while the exception is happening. It picks up the raised exception with sys.exc_info().
# 
#     Positional arguments:
#     subject -- subject line of the email (to be prepended by 'Application Error: ').
#     """
#     # Generate and modify html.
#     tb = tbtools.get_current_traceback()  # Get exception information.
#     with _override_html():
#         html = tb.render_full().encode('utf-8', 'replace')
#     html = html.replace('<blockquote>', '<blockquote style="margin: 1em 0 0; padding: 0;">')
#     subject = 'Application Error: {}'.format(subject)
# 
#     # Apply throttle.
#     md5 = hashlib.md5('{}{}'.format(subject, html)).hexdigest()
#     seconds = int(current_app.config['MAIL_EXCEPTION_THROTTLE'])
#     lock = redis.lock(EMAIL_THROTTLE.format(md5=md5), timeout=seconds)
#     have_lock = lock.acquire(blocking=False)
#     if not have_lock:
#         LOG.debug('Suppressing email: {}'.format(subject))
#         return
# 
#     # Send email.
#     msg = Message(subject=subject, recipients=current_app.config['ADMINS'], html=html)
#     mail.send(msg)
# 
# Path: pypi_portal/extensions.py
# LOG = getLogger(__name__)
# def _on_connect(dbapi_connection, **_):


# Path: pypi_portal/middleware.py
import locale
import os
from logging import getLogger
from celery.signals import task_failure, worker_process_init
from flask import current_app, render_template, request
from markupsafe import Markup
from pypi_portal.core.email import send_exception
from pypi_portal.extensions import db


    Without this, the existing session to the MySQL server is cloned to all Celery workers, so they
    all share a single session. A SQLAlchemy session is not thread/concurrency-safe, causing weird
    exceptions to be raised by workers.

    Based on http://stackoverflow.com/a/14146403/1198943
    """
    LOG.debug('Initializing SQLAlchemy for PID {}.'.format(os.getpid()))
    db.init_app(current_app)


# Send email when a Celery task raises an unhandled exception.
@task_failure.connect
def celery_error_handler(sender, exception, **_):
    exception_name = exception.__class__.__name__
    task_module = sender.name
    send_exception('{} exception in {}'.format(exception_name, task_module))


# Setup default error templates.
@current_app.errorhandler(400)
@current_app.errorhandler(403)
@current_app.errorhandler(404)
@current_app.errorhandler(500)
def error_handler(e):
    code = getattr(e, 'code', 500)  # If 500, e == the exception.
    if code == 500:
        # Send email to all ADMINS.
        exception_name = e.__class__.__name__
        view_module = request.endpoint

        send_exception('{} exception in {}'.format(exception_name, view_module))