<commit_before># -*- coding: utf-8 -*-

from datetime import datetime
import json
import re
import requests
from django.http import HttpResponse
from accounts.models import AuthToken
from moderations.models import Moderation, ModerationAction
from moderations.utils import timedelta_to_str
from .tasks import async_get_request

class SlackSdk(object):

    @staticmethod
    def get_channel_data(channel):
        auth_token_object = AuthToken.objects.filter(
            service_name='slack', service_entity_auth_name=channel
        ).first()
        if auth_token_object:
            channel_id = auth_token_object.service_entity_auth_id
            token = auth_token_object.service_auth_token

            return token, channel_id
        else:
            return None, None

    @staticmethod
    def post_moderation(text):

        attachments = [
            {
                'fallback': "Moderator actions",
                'callback_id': 'mod-inbox',
                'attachment_type': 'default',
                'actions': [
                    {
                        'name': 'approve',
                        'text': "Approve",
                        'type': 'button',
                        'value': 'approve',
                        'style': 'primary'
                    },
                    {
                        'name': 'reject',
                        'text': "Reject",
                        'type': 'button',
                        'value': 'reject'
                    }
                ]
            }
        ]

        token, channel_id = SlackSdk.get_channel_data('#mod-inbox')
        if channel_id:
            response = SlackSdk.create_message(token,
                                               channel_id, text, attachments)

            return response.json()
        else:
            data = {
                'success': False,
                'message': "{} is not a valid channel or "
                           "was not previously authorized".format(channel_id)
            }
            return data

    @staticmethod
    def post_leaderboard(leaderboard):
        """
        leaderboard = [
            {'@jared': 12,345},
        ]
        """

        def render_board(leaderboard, title):
            text = '┌----------------------┬----------------------┐\n'
            text += '│ {0: <20} | {1: <20} │\n'.format('Mod', title)

            sorted_leaderboard = sorted(leaderboard.items(),
                                        key=lambda x: x[1],
                                        reverse=True)
            for k, v in sorted_leaderboard:
                if k:
                    text += '├----------------------┼----------------------┤\n'
                    text += '│ {0: <20} │ {1: <20} │\n'.format(k, v)

            text += '└----------------------┴----------------------┘\n'
            return text

        def avg(a, b):
            if b > 0.0:
                return a/float(b) * 100.0
            else:
                return 0

        text = (
            "LEADERBOARD as of {date}\n"
            "```\n"
            "{all_time}\n"
            "{seven_days}\n"
            "```\n"
        )
        text = text.format(
            date=datetime.utcnow(),
            all_time=render_board(leaderboard['all_time'], 'All Time'),
            seven_days=render_board(leaderboard['seven_days'], 'Last 7 Days')
        )

        text += 'MOD TEAM SPEED REPORT AS OF {} UTC\n'.format(datetime.utcnow())
        text += '```\n'
        text += 'Average time to first mod review (all-time): %s over %i pieces of content\n' \
            % (timedelta_to_str(leaderboard['avg']['all_time']['review'][0]),
               leaderboard['avg']['all_time']['review'][1])

        text += 'Average time to first mod review (last 7 days): %s over %i pieces of content\n' \
            % (timedelta_to_str(leaderboard['avg']['seven_days']['review'][0]),
               leaderboard['avg']['seven_days']['review'][1])

        text += 'Average time to first mod resolution (all-time): %s over %i pieces of content\n' \
            % (timedelta_to_str(leaderboard['avg']['all_time']['resolution'][0]),
               leaderboard['avg']['all_time']['resolution'][1])

        text += 'Average time to first mod resolution (last 7 days): %s over %i pieces of content\n' \
            % (timedelta_to_str(leaderboard['avg']['seven_days']['resolution'][0]),
               leaderboard['avg']['seven_days']['resolution'][1])
        text += '```\n'

        text += 'CONTENT QUALITY REPORT AS OF {} UTC\n'.format(datetime.utcnow())
        counts = leaderboard['counts']
        text += '```\n'
        text += 'Past 7 days content: %i\n' \
            % counts['total']

        text += 'Past 7 days flagged by mods: %i (%.2f%%)\n' \
            % (counts['total_flagged'],
               avg(counts['total_flagged'], counts['total']))

        text += 'Reason: Off topic: %i (%.2f%% of flags)\n' \
            % (counts['off_topic'],
               avg(counts['off_topic'], counts['total_flagged']))

        text += 'Reason: Inappropriate: %i (%.2f%% of flags)\n' \
            % (counts['inappropriate'],
               avg(counts['inappropriate'], counts['total_flagged']))

        text += 'Reason: Contact info: %i (%.2f%% of flags)\n' \
            % (counts['contact_info'],
               avg(counts['contact_info'], counts['total_flagged']))

        text += 'Reason: Other: %i (%.2f%% of flags)\n' \
            % (counts['other'],
               avg(counts['other'], counts['total_flagged']))
        text += '```\n'

        token, channel_id = SlackSdk.get_channel_data('#mod-leaderboard')
        return SlackSdk.create_message(token, channel_id,
                                       text, [], in_channel=True)

    @staticmethod
    def create_message(access_token, channel_id,
                       text='', attachments=[], in_channel=False, async=False):

        is_image = False
        if 'https://res.cloudinary.com/' in text:
            is_image = True

        if len(text) >= 3500:
            search_text = re.findall(
                '^(.* posted the) <(https://.*)\|(.*)>.*:\n',
                text
            )
            if search_text:
                new_content_text = search_text[0][0]
                link = search_text[0][1]
                new_content_type = search_text[0][2]
                text = '%s %s. WARNING: this content cannot be displayed, ' \
                       'please read the complete content <%s|HERE>' \
                       % (new_content_text, new_content_type, link)

        params = {
            'token': access_token,
            'channel': channel_id,
            'text': text,
            'attachments': json.dumps(attachments),
            'unfurl_links': False,
            'unfurl_media': is_image,
        }
        if in_channel:
            params['response_type'] = 'in_channel'

        if not async:
            return requests.get(url='https://slack.com/api/chat.postMessage', params=params)
        else:
            return async_get_request(url='https://slack.com/api/chat.postMessage', params=params)

    @staticmethod
    def delete_message(access_token, channel_id, ts):
        return async_get_request(url='https://slack.com/api/chat.delete',
                                 params={
                                     'token': access_token,
                                     'ts': ts,
                                     'channel': channel_id,
                                 })

    @staticmethod
    def update_message(access_token, channel_id, ts,
                       text='', attachments=[]):

        return async_get_request(url='https://slack.com/api/chat.update',
                                 params={
                                     'token': access_token,
                                     'ts': ts,
                                     'channel': channel_id,
                                     'text': text,
                                     'attachments': json.dumps(attachments),
                                     'parse': 'none',
                                 })

def mod_inbox_approved(data, moderation):

    original_message = data.get('original_message')
    text = original_message.get('text')
    approved_by = data.get('user').get('name')
    approved_time = float(data.get('action_ts').split('.')[0])
    approved_time = datetime.utcfromtimestamp(approved_time)
    approved_time = approved_time.strftime('%Y-%m-%d %I:%M%p')
    ts = data.get('message_ts')

    attachments = [
        {
            "fallback": "Please moderate this.",
            "text": ":white_check_mark: _Approved by @%s %s UTC_" %
                    (approved_by, approved_time),
            "callback_id": "mod-approved",
            "attachment_type": "default",
            "mrkdwn_in": [
                "text"
            ]
        }
    ]

    token, channel_id = SlackSdk.get_channel_data('#mod-approved')
    response = SlackSdk.create_message(token, channel_id, text, attachments)
    if response.status_code == 200:
        data = response.json()
        if data.get('ok'):
            token, channel_id = SlackSdk.get_channel_data('#mod-inbox')
            save_moderation_action(moderation, approved_by, channel_id,
                                   'approve', data.get('ts'))
            reponse = SlackSdk.delete_message(token, channel_id, ts)

    return HttpResponse('')

def mod_inbox_reject(data, moderation):

    original_message = data.get('original_message')
    text = original_message.get('text')
    ts = data.get('message_ts')

    attachments = [
        {
            "fallback": "Moderator actions",
            "text": "_Reject: Select a reason_",
            "callback_id": "mod-inbox",
            "attachment_type": "default",
            "mrkdwn_in": [
                "text"
            ],
            "actions": [
                {
                    "name": "Off topic",
                    "text": "Off topic",
                    "type": "button",
                    "value": "off_topic",
                    "style": "danger"
                },
                {
                    "name": "Inappropriate",
                    "text": "Inappropriate",
                    "type": "button",
                    "value": "inappropriate",
                    "style": "danger"
                },
                {
                    "name": "Contact info",
                    "text": "Contact info",
                    "type": "button",
                    "value": "contact_info",
                    "style": "danger"
                },
                {
                    "name": "Other",
                    "text": "Other",
                    "type": "button",
                    "value": "other",
                    "style": "danger"
                },
                {
                    "name": "Undo",
                    "text": "Undo",
                    "type": "button",
                    "value": "undo"
                }
            ]
        }
    ]

    token, channel_id = SlackSdk.get_channel_data('#mod-inbox')
    SlackSdk.update_message(token, channel_id, ts, text=text, attachments=attachments)

    return HttpResponse('')

def mod_inbox_reject_undo(data):
    original_message = data.get('original_message')
    text = original_message.get('text')
    ts = data.get('message_ts')

    attachments = [
        {
            "fallback": "Moderator actions",
            "callback_id": "mod-inbox",
            "attachment_type": "default",
            "actions": [
                {
                    "name": "approve",
                    "text": "Approve",
                    "type": "button",
                    "value": "approve",
                    "style": "primary"
                },
                {
                    "name": "reject",
                    "text": "Reject",
                    "type": "button",
                    "value": "reject"
                }
            ]
        }
    ]

    token, channel_id = SlackSdk.get_channel_data('#mod-inbox')
    SlackSdk.update_message(token, channel_id,
                            ts, text=text, attachments=attachments)

    return HttpResponse('')

def mod_inbox_reject_reason(data, moderation):
    original_message = data.get('original_message')
    text = original_message.get('text')
    rejected_by = data.get('user').get('name')
    rejected_time = float(data.get('action_ts').split('.')[0])
    rejected_time = datetime.utcfromtimestamp(rejected_time)
    rejected_time = rejected_time.strftime('%Y-%m-%d %I:%M%p')
    rejected_reason = data.get('actions')[0]['value']
    ts = data.get('message_ts')

    attachments = [
        {
            "fallback": "Moderator actions",
            "text": "_%s UTC: @%s rejected this with the reason: \"%s\"_" %
                    (rejected_time, rejected_by, rejected_reason),
            "callback_id": "mod-flagged",
            "attachment_type": "default",
            "mrkdwn_in": [
                "text"
            ],
            "actions": [
                {
                    "name": "Resolve",
                    "text": "Mark resolved",
                    "type": "button",
                    "value": "resolve",
                    "style": "primary"
                }
            ]
        }
    ]

    token, channel_id = SlackSdk.get_channel_data('#mod-flagged')

    response = SlackSdk.create_message(token, channel_id,
                                       text=text, attachments=attachments)

    if response.status_code == 200:
        data = response.json()
        if data.get('ok'):

            token, channel_id = SlackSdk.get_channel_data('#mod-inbox')

            save_moderation_action(moderation, rejected_by,
                                   channel_id, rejected_reason, data.get('ts'))

            SlackSdk.delete_message(token, channel_id, ts)

    return HttpResponse('')

def mod_inbox(data, action, moderation):

    if action == 'approve':
        return mod_inbox_approved(data, moderation)

    elif action == 'reject':
        return mod_inbox_reject(data, moderation)

    elif action == 'undo':
        return mod_inbox_reject_undo(data)

    elif (action == 'off_topic') or (action == 'inappropriate') \
            or (action == 'contact_info') or (action == 'other'):
        return mod_inbox_reject_reason(data, moderation)

def mod_flagged_resolve(data, moderation):
    original_message = data.get('original_message')
    text = original_message.get('text')
    resolved_by = data.get('user').get('name')
    resolved_time = float(data.get('action_ts').split('.')[0])
    resolved_time = datetime.utcfromtimestamp(resolved_time)
    resolved_time = resolved_time.strftime('%Y-%m-%d %I:%M%p')
    rejected_reason = original_message.get('attachments')[0]['text']
    message_ts = data.get('message_ts')

    attachments = [
        {
            "fallback": "Please moderate this.",
            "text": "%s\n_%s UTC: @%s marked this \"Resolved\"_" %
                    (rejected_reason, resolved_time, resolved_by),
            "callback_id": "mod-resolved",
            "attachment_type": "default",
            "mrkdwn_in": [
                "text"
            ]
        }
    ]

    token, channel_id = SlackSdk.get_channel_data('#mod-resolved')
    response = SlackSdk.create_message(token, channel_id, text=text,
                                       attachments=attachments)

    if response.status_code == 200:
        data = response.json()
        if data.get('ok'):

            token, channel_id = SlackSdk.get_channel_data('#mod-flagged')
            ts = data.get('ts')

            save_moderation_action(moderation, resolved_by, channel_id,
                                   'resolve', ts)
            SlackSdk.delete_message(token, channel_id, message_ts)

    return HttpResponse('')

def mod_flagged(data, action, moderation):

    if action == 'resolve':
        return mod_flagged_resolve(data, moderation)
    assert False, action

def save_moderation_action(moderation, username, channel_id,
                           action, message_id):
    moderation.status = channel_id
    moderation.status_reason = action
    moderation.message_id = message_id
    moderation.save()
    ModerationAction.objects.create(moderation=moderation,
                                    action=action,
                                    action_author_id=username)

def moderate(data):
    """
    """
    data = data.get('payload')
    data = json.loads(data)
    if data:

        action = data.get('actions')[0].get('value')
        message_id = data.get('message_ts')

        moderation = Moderation.objects.get_by_message_id(message_id)

        callback_id = data.get('callback_id')

        if callback_id == 'mod-inbox':
            return mod_inbox(data, action, moderation)

        elif callback_id == 'mod-flagged':
            return mod_flagged(data, action, moderation)

        return HttpResponse(json.dumps(data, indent=4))
<commit_msg>make the call to post a message async when posting leadership board<commit_after># -*- coding: utf-8 -*-

from datetime import datetime
import json
import re
import requests
from django.http import HttpResponse
from accounts.models import AuthToken
from moderations.models import Moderation, ModerationAction
from moderations.utils import timedelta_to_str
from .tasks import async_get_request

class SlackSdk(object):

    @staticmethod
    def get_channel_data(channel):
        auth_token_object = AuthToken.objects.filter(
            service_name='slack', service_entity_auth_name=channel
        ).first()
        if auth_token_object:
            channel_id = auth_token_object.service_entity_auth_id
            token = auth_token_object.service_auth_token

            return token, channel_id
        else:
            return None, None

    @staticmethod
    def post_moderation(text):

        attachments = [
            {
                'fallback': "Moderator actions",
                'callback_id': 'mod-inbox',
                'attachment_type': 'default',
                'actions': [
                    {
                        'name': 'approve',
                        'text': "Approve",
                        'type': 'button',
                        'value': 'approve',
                        'style': 'primary'
                    },
                    {
                        'name': 'reject',
                        'text': "Reject",
                        'type': 'button',
                        'value': 'reject'
                    }
                ]
            }
        ]

        token, channel_id = SlackSdk.get_channel_data('#mod-inbox')
        if channel_id:
            response = SlackSdk.create_message(token,
                                               channel_id, text, attachments)

            return response.json()
        else:
            data = {
                'success': False,
                'message': "{} is not a valid channel or "
                           "was not previously authorized".format(channel_id)
            }
            return data

    @staticmethod
    def post_leaderboard(leaderboard):
        """
        leaderboard = [
            {'@jared': 12,345},
        ]
        """

        def render_board(leaderboard, title):
            text = '┌----------------------┬----------------------┐\n'
            text += '│ {0: <20} | {1: <20} │\n'.format('Mod', title)

            sorted_leaderboard = sorted(leaderboard.items(),
                                        key=lambda x: x[1],
                                        reverse=True)
            for k, v in sorted_leaderboard:
                if k:
                    text += '├----------------------┼----------------------┤\n'
                    text += '│ {0: <20} │ {1: <20} │\n'.format(k, v)

            text += '└----------------------┴----------------------┘\n'
            return text

        def avg(a, b):
            if b > 0.0:
                return a/float(b) * 100.0
            else:
                return 0

        text = (
            "LEADERBOARD as of {date}\n"
            "```\n"
            "{all_time}\n"
            "{seven_days}\n"
            "```\n"
        )
        text = text.format(
            date=datetime.utcnow(),
            all_time=render_board(leaderboard['all_time'], 'All Time'),
            seven_days=render_board(leaderboard['seven_days'], 'Last 7 Days')
        )

        text += 'MOD TEAM SPEED REPORT AS OF {} UTC\n'.format(datetime.utcnow())
        text += '```\n'
        text += 'Average time to first mod review (all-time): %s over %i pieces of content\n' \
            % (timedelta_to_str(leaderboard['avg']['all_time']['review'][0]),
               leaderboard['avg']['all_time']['review'][1])

        text += 'Average time to first mod review (last 7 days): %s over %i pieces of content\n' \
            % (timedelta_to_str(leaderboard['avg']['seven_days']['review'][0]),
               leaderboard['avg']['seven_days']['review'][1])

        text += 'Average time to first mod resolution (all-time): %s over %i pieces of content\n' \
            % (timedelta_to_str(leaderboard['avg']['all_time']['resolution'][0]),
               leaderboard['avg']['all_time']['resolution'][1])

        text += 'Average time to first mod resolution (last 7 days): %s over %i pieces of content\n' \
            % (timedelta_to_str(leaderboard['avg']['seven_days']['resolution'][0]),
               leaderboard['avg']['seven_days']['resolution'][1])
        text += '```\n'

        text += 'CONTENT QUALITY REPORT AS OF {} UTC\n'.format(datetime.utcnow())
        counts = leaderboard['counts']
        text += '```\n'
        text += 'Past 7 days content: %i\n' \
            % counts['total']

        text += 'Past 7 days flagged by mods: %i (%.2f%%)\n' \
            % (counts['total_flagged'],
               avg(counts['total_flagged'], counts['total']))

        text += 'Reason: Off topic: %i (%.2f%% of flags)\n' \
            % (counts['off_topic'],
               avg(counts['off_topic'], counts['total_flagged']))

        text += 'Reason: Inappropriate: %i (%.2f%% of flags)\n' \
            % (counts['inappropriate'],
               avg(counts['inappropriate'], counts['total_flagged']))

        text += 'Reason: Contact info: %i (%.2f%% of flags)\n' \
            % (counts['contact_info'],
               avg(counts['contact_info'], counts['total_flagged']))

        text += 'Reason: Other: %i (%.2f%% of flags)\n' \
            % (counts['other'],
               avg(counts['other'], counts['total_flagged']))
        text += '```\n'

        token, channel_id = SlackSdk.get_channel_data('#mod-leaderboard')
        return SlackSdk.create_message(token, channel_id,
                                       text, [], in_channel=True, async=True)

    @staticmethod
    def create_message(access_token, channel_id,
                       text='', attachments=[], in_channel=False, async=False):

        is_image = False
        if 'https://res.cloudinary.com/' in text:
            is_image = True

        if len(text) >= 3500:
            search_text = re.findall(
                '^(.* posted the) <(https://.*)\|(.*)>.*:\n',
                text
            )
            if search_text:
                new_content_text = search_text[0][0]
                link = search_text[0][1]
                new_content_type = search_text[0][2]
                text = '%s %s. WARNING: this content cannot be displayed, ' \
                       'please read the complete content <%s|HERE>' \
                       % (new_content_text, new_content_type, link)

        params = {
            'token': access_token,
            'channel': channel_id,
            'text': text,
            'attachments': json.dumps(attachments),
            'unfurl_links': False,
            'unfurl_media': is_image,
        }
        if in_channel:
            params['response_type'] = 'in_channel'

        if not async:
            return requests.get(url='https://slack.com/api/chat.postMessage', params=params)
        else:
            return async_get_request(url='https://slack.com/api/chat.postMessage', params=params)

    @staticmethod
    def delete_message(access_token, channel_id, ts):
        return async_get_request(url='https://slack.com/api/chat.delete',
                                 params={
                                     'token': access_token,
                                     'ts': ts,
                                     'channel': channel_id,
                                 })

    @staticmethod
    def update_message(access_token, channel_id, ts,
                       text='', attachments=[]):

        return async_get_request(url='https://slack.com/api/chat.update',
                                 params={
                                     'token': access_token,
                                     'ts': ts,
                                     'channel': channel_id,
                                     'text': text,
                                     'attachments': json.dumps(attachments),
                                     'parse': 'none',
                                 })

def mod_inbox_approved(data, moderation):

    original_message = data.get('original_message')
    text = original_message.get('text')
    approved_by = data.get('user').get('name')
    approved_time = float(data.get('action_ts').split('.')[0])
    approved_time = datetime.utcfromtimestamp(approved_time)
    approved_time = approved_time.strftime('%Y-%m-%d %I:%M%p')
    ts = data.get('message_ts')

    attachments = [
        {
            "fallback": "Please moderate this.",
            "text": ":white_check_mark: _Approved by @%s %s UTC_" %
                    (approved_by, approved_time),
            "callback_id": "mod-approved",
            "attachment_type": "default",
            "mrkdwn_in": [
                "text"
            ]
        }
    ]

    token, channel_id = SlackSdk.get_channel_data('#mod-approved')
    response = SlackSdk.create_message(token, channel_id, text, attachments)
    if response.status_code == 200:
        data = response.json()
        if data.get('ok'):
            token, channel_id = SlackSdk.get_channel_data('#mod-inbox')
            save_moderation_action(moderation, approved_by, channel_id,
                                   'approve', data.get('ts'))
            reponse = SlackSdk.delete_message(token, channel_id, ts)

    return HttpResponse('')

def mod_inbox_reject(data, moderation):

    original_message = data.get('original_message')
    text = original_message.get('text')
    ts = data.get('message_ts')

    attachments = [
        {
            "fallback": "Moderator actions",
            "text": "_Reject: Select a reason_",
            "callback_id": "mod-inbox",
            "attachment_type": "default",
            "mrkdwn_in": [
                "text"
            ],
            "actions": [
                {
                    "name": "Off topic",
                    "text": "Off topic",
                    "type": "button",
                    "value": "off_topic",
                    "style": "danger"
                },
                {
                    "name": "Inappropriate",
                    "text": "Inappropriate",
                    "type": "button",
                    "value": "inappropriate",
                    "style": "danger"
                },
                {
                    "name": "Contact info",
                    "text": "Contact info",
                    "type": "button",
                    "value": "contact_info",
                    "style": "danger"
                },
                {
                    "name": "Other",
                    "text": "Other",
                    "type": "button",
                    "value": "other",
                    "style": "danger"
                },
                {
                    "name": "Undo",
                    "text": "Undo",
                    "type": "button",
                    "value": "undo"
                }
            ]
        }
    ]

    token, channel_id = SlackSdk.get_channel_data('#mod-inbox')
    SlackSdk.update_message(token, channel_id, ts, text=text, attachments=attachments)

    return HttpResponse('')

def mod_inbox_reject_undo(data):
    original_message = data.get('original_message')
    text = original_message.get('text')
    ts = data.get('message_ts')

    attachments = [
        {
            "fallback": "Moderator actions",
            "callback_id": "mod-inbox",
            "attachment_type": "default",
            "actions": [
                {
                    "name": "approve",
                    "text": "Approve",
                    "type": "button",
                    "value": "approve",
                    "style": "primary"
                },
                {
                    "name": "reject",
                    "text": "Reject",
                    "type": "button",
                    "value": "reject"
                }
            ]
        }
    ]

    token, channel_id = SlackSdk.get_channel_data('#mod-inbox')
    SlackSdk.update_message(token, channel_id,
                            ts, text=text, attachments=attachments)

    return HttpResponse('')

def mod_inbox_reject_reason(data, moderation):
    original_message = data.get('original_message')
    text = original_message.get('text')
    rejected_by = data.get('user').get('name')
    rejected_time = float(data.get('action_ts').split('.')[0])
    rejected_time = datetime.utcfromtimestamp(rejected_time)
    rejected_time = rejected_time.strftime('%Y-%m-%d %I:%M%p')
    rejected_reason = data.get('actions')[0]['value']
    ts = data.get('message_ts')

    attachments = [
        {
            "fallback": "Moderator actions",
            "text": "_%s UTC: @%s rejected this with the reason: \"%s\"_" %
                    (rejected_time, rejected_by, rejected_reason),
            "callback_id": "mod-flagged",
            "attachment_type": "default",
            "mrkdwn_in": [
                "text"
            ],
            "actions": [
                {
                    "name": "Resolve",
                    "text": "Mark resolved",
                    "type": "button",
                    "value": "resolve",
                    "style": "primary"
                }
            ]
        }
    ]

    token, channel_id = SlackSdk.get_channel_data('#mod-flagged')

    response = SlackSdk.create_message(token, channel_id,
                                       text=text, attachments=attachments)

    if response.status_code == 200:
        data = response.json()
        if data.get('ok'):

            token, channel_id = SlackSdk.get_channel_data('#mod-inbox')

            save_moderation_action(moderation, rejected_by,
                                   channel_id, rejected_reason, data.get('ts'))

            SlackSdk.delete_message(token, channel_id, ts)

    return HttpResponse('')

def mod_inbox(data, action, moderation):

    if action == 'approve':
        return mod_inbox_approved(data, moderation)

    elif action == 'reject':
        return mod_inbox_reject(data, moderation)

    elif action == 'undo':
        return mod_inbox_reject_undo(data)

    elif (action == 'off_topic') or (action == 'inappropriate') \
            or (action == 'contact_info') or (action == 'other'):
        return mod_inbox_reject_reason(data, moderation)

def mod_flagged_resolve(data, moderation):
    original_message = data.get('original_message')
    text = original_message.get('text')
    resolved_by = data.get('user').get('name')
    resolved_time = float(data.get('action_ts').split('.')[0])
    resolved_time = datetime.utcfromtimestamp(resolved_time)
    resolved_time = resolved_time.strftime('%Y-%m-%d %I:%M%p')
    rejected_reason = original_message.get('attachments')[0]['text']
    message_ts = data.get('message_ts')

    attachments = [
        {
            "fallback": "Please moderate this.",
            "text": "%s\n_%s UTC: @%s marked this \"Resolved\"_" %
                    (rejected_reason, resolved_time, resolved_by),
            "callback_id": "mod-resolved",
            "attachment_type": "default",
            "mrkdwn_in": [
                "text"
            ]
        }
    ]

    token, channel_id = SlackSdk.get_channel_data('#mod-resolved')
    response = SlackSdk.create_message(token, channel_id, text=text,
                                       attachments=attachments)

    if response.status_code == 200:
        data = response.json()
        if data.get('ok'):

            token, channel_id = SlackSdk.get_channel_data('#mod-flagged')
            ts = data.get('ts')

            save_moderation_action(moderation, resolved_by, channel_id,
                                   'resolve', ts)
            SlackSdk.delete_message(token, channel_id, message_ts)

    return HttpResponse('')

def mod_flagged(data, action, moderation):

    if action == 'resolve':
        return mod_flagged_resolve(data, moderation)
    assert False, action

def save_moderation_action(moderation, username, channel_id,
                           action, message_id):
    moderation.status = channel_id
    moderation.status_reason = action
    moderation.message_id = message_id
    moderation.save()
    ModerationAction.objects.create(moderation=moderation,
                                    action=action,
                                    action_author_id=username)

def moderate(data):
    """
    """
    data = data.get('payload')
    data = json.loads(data)
    if data:

        action = data.get('actions')[0].get('value')
        message_id = data.get('message_ts')

        moderation = Moderation.objects.get_by_message_id(message_id)

        callback_id = data.get('callback_id')

        if callback_id == 'mod-inbox':
            return mod_inbox(data, action, moderation)

        elif callback_id == 'mod-flagged':
            return mod_flagged(data, action, moderation)

        return HttpResponse(json.dumps(data, indent=4))
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

"""
    Akvo RSR is covered by the GNU Affero General Public License.
    See more details in the license.txt file located at the root folder of the
    Akvo RSR module. For additional details on the GNU license please
    see < http://www.gnu.org/licenses/agpl.html >.
"""

from django.conf import settings
from django.contrib.sites.models import Site
from django.http import Http404

from djangotoolbox.utils import make_tls_property

SITE_ID = settings.__dict__['_wrapped'].__class__.SITE_ID = make_tls_property()

class PartnerSitesRouterMiddleware(object):
    def process_request(self, request, site=None):
        request.organisation_id = None
        domain = request.get_host().split(':')[0]
        if domain.endswith('.dev'):  # local development domain
            try:
                site = Site.objects.get(development_domain=domain)
            except:
                raise Http404
        elif domain.endswith('.akvo.org'):  # akvo development/production domain
            try:
                site = Site.objects.get(domain=domain)
            except:
                site = Site.objects.get(domain='www.akvo.org')
                request.host = site.domain
        else:  # probably a partner-nominated domain
            try:
                site = Site.objects.get(partner_domain=domain)
            except:
                raise Http404
        if site is not None and site.enabled:
            SITE_ID.value = site.id
            if site.is_partner_site:
                request.organisation_id = site.organisation.id
                request.urlconf = 'akvo.urls_partner_sites'
        return
<commit_msg>Updated middleware to use get_object_or_404.<commit_after># -*- coding: utf-8 -*-

"""
    Akvo RSR is covered by the GNU Affero General Public License.
    See more details in the license.txt file located at the root folder of the
    Akvo RSR module. For additional details on the GNU license please
    see < http://www.gnu.org/licenses/agpl.html >.
"""

from django.conf import settings
from django.contrib.sites.models import Site
from django.shortcuts import get_object_or_404

from djangotoolbox.utils import make_tls_property

SITE_ID = settings.__dict__['_wrapped'].__class__.SITE_ID = make_tls_property()

class PartnerSitesRouterMiddleware(object):
    def process_request(self, request, site=None):
        request.organisation_id = None
        domain = request.get_host().split(':')[0]
        if domain.endswith('.dev'):  # local development domain
            site = get_object_or_404(Site, development_domain=domain)
        elif domain.endswith('.akvo.org'):  # akvo development/production domain
            try:
                site = Site.objects.get(domain=domain)
            except:
                site = Site.objects.get(domain='www.akvo.org')
                request.host = site.domain
        else:  # probably a partner-nominated domain
            site = get_object_or_404(Site, partner_domain=domain)
        if site is not None and site.enabled:
            SITE_ID.value = site.id
            if site.is_partner_site:
                request.organisation_id = site.organisation.id
                request.urlconf = 'akvo.urls_partner_sites'
        return
<|endoftext|>


<commit_before>import os

from flask import Flask

class Config:

    def __init__(self, app: Flask=None) -> None:
        self.app = None
        if app:
            self.init_app(app)

    def init_app(self, app: Flask) -> None:
        config = self.get_user_config()
        app.config.update(config)

    @staticmethod
    def get_user_config():
        from flask import Config
        config = Config('/')

        config.from_object('alerta.settings')
        config.from_pyfile('/etc/alertad.conf', silent=True)
        config.from_envvar('ALERTA_SVR_CONF_FILE', silent=True)

        if 'DEBUG' in os.environ:
            config['DEBUG'] = True

        if 'BASE_URL' in os.environ:
            config['BASE_URL'] = os.environ['BASE_URL']

        if 'USE_PROXYFIX' in os.environ:
            config['USE_PROXYFIX'] = True if os.environ['USE_PROXYFIX'] == 'True' else False

        if 'SECRET_KEY' in os.environ:
            config['SECRET_KEY'] = os.environ['SECRET_KEY']

        database_url = (
            os.environ.get('DATABASE_URL', None) or
            # The following database settings are deprecated.
            os.environ.get('MONGO_URI', None) or
            os.environ.get('MONGODB_URI', None) or
            os.environ.get('MONGOHQ_URL', None) or
            os.environ.get('MONGOLAB_URI', None)
        )
        # Use app config for DATABASE_URL if no env var from above override it
        config['DATABASE_URL'] = database_url or config['DATABASE_URL']

        if 'DATABASE_NAME' in os.environ:
            config['DATABASE_NAME'] = os.environ['DATABASE_NAME']

        if 'AUTH_REQUIRED' in os.environ:
            config['AUTH_REQUIRED'] = True if os.environ['AUTH_REQUIRED'] == 'True' else False

        if 'AUTH_PROVIDER' in os.environ:
            config['AUTH_PROVIDER'] = os.environ['AUTH_PROVIDER']

        if 'ADMIN_USERS' in os.environ:
            config['ADMIN_USERS'] = os.environ['ADMIN_USERS'].split(',')

        if 'SIGNUP_ENABLED' in os.environ:
            config['SIGNUP_ENABLED'] = True if os.environ['SIGNUP_ENABLED'] == 'True' else False

        if 'CUSTOMER_VIEWS' in os.environ:
            config['CUSTOMER_VIEWS'] = True if os.environ['CUSTOMER_VIEWS'] == 'True' else False

        if 'OAUTH2_CLIENT_ID' in os.environ:
            config['OAUTH2_CLIENT_ID'] = os.environ['OAUTH2_CLIENT_ID']

        if 'OAUTH2_CLIENT_SECRET' in os.environ:
            config['OAUTH2_CLIENT_SECRET'] = os.environ['OAUTH2_CLIENT_SECRET']

        if 'ALLOWED_EMAIL_DOMAINS' in os.environ:
            config['ALLOWED_EMAIL_DOMAINS'] = os.environ['ALLOWED_EMAIL_DOMAINS'].split(',')

        if 'AZURE_TENANT' in os.environ:
            config['AZURE_TENANT'] = os.environ['AZURE_TENANT']

        if 'GITHUB_URL' in os.environ:
            config['GITHUB_URL'] = os.environ['GITHUB_URL']

        if 'ALLOWED_GITHUB_ORGS' in os.environ:
            config['ALLOWED_GITHUB_ORGS'] = os.environ['ALLOWED_GITHUB_ORGS'].split(',')

        if 'GITLAB_URL' in os.environ:
            config['GITLAB_URL'] = os.environ['GITLAB_URL']

        if 'ALLOWED_GITLAB_GROUPS' in os.environ:
            RuntimeWarning('Deprecated config setting: ALLOWED_GITLAB_GROUPS (use ALLOWED_OIDC_ROLES)')
            config['ALLOWED_OIDC_ROLES'] = os.environ['ALLOWED_GITLAB_GROUPS'].split(',')

        if 'KEYCLOAK_URL' in os.environ:
            config['KEYCLOAK_URL'] = os.environ['KEYCLOAK_URL']

        if 'KEYCLOAK_REALM' in os.environ:
            config['KEYCLOAK_REALM'] = os.environ['KEYCLOAK_REALM']

        if 'ALLOWED_KEYCLOAK_ROLES' in os.environ:
            RuntimeWarning('Deprecated config setting: ALLOWED_KEYCLOAK_ROLES (use ALLOWED_OIDC_ROLES)')
            config['ALLOWED_OIDC_ROLES'] = os.environ['ALLOWED_KEYCLOAK_ROLES'].split(',')

        if 'OIDC_ISSUER_URL' in os.environ:
            config['OIDC_ISSUER_URL'] = os.environ['OIDC_ISSUER_URL']

        if 'ALLOWED_OIDC_ROLES' in os.environ:
            config['ALLOWED_OIDC_ROLES'] = os.environ['ALLOWED_OIDC_ROLES'].split(',')

        if 'PINGFEDERATE_OPENID_ACCESS_TOKEN_URL' in os.environ:
            config['PINGFEDERATE_OPENID_ACCESS_TOKEN_URL'] = os.environ['PINGFEDERATE_OPENID_ACCESS_TOKEN_URL'].split(
                ',')

        if 'PINGFEDERATE_OPENID_PAYLOAD_USERNAME' in os.environ:
            config['PINGFEDERATE_OPENID_PAYLOAD_USERNAME'] = os.environ['PINGFEDERATE_OPENID_PAYLOAD_USERNAME'].split(
                ',')

        if 'PINGFEDERATE_OPENID_PAYLOAD_EMAIL' in os.environ:
            config['PINGFEDERATE_OPENID_PAYLOAD_EMAIL'] = os.environ['PINGFEDERATE_OPENID_PAYLOAD_EMAIL'].split(',')

        if 'PINGFEDERATE_OPENID_PAYLOAD_GROUP' in os.environ:
            config['PINGFEDERATE_OPENID_PAYLOAD_GROUP'] = os.environ['PINGFEDERATE_OPENID_PAYLOAD_GROUP'].split(',')

        if 'PINGFEDERATE_PUBKEY_LOCATION' in os.environ:
            config['PINGFEDERATE_PUBKEY_LOCATION'] = os.environ['PINGFEDERATE_PUBKEY_LOCATION'].split(',')

        if 'PINGFEDERATE_TOKEN_ALGORITHM' in os.environ:
            config['PINGFEDERATE_TOKEN_ALGORITHM'] = os.environ['PINGFEDERATE_TOKEN_ALGORITHM'].split(',')

        if 'CORS_ORIGINS' in os.environ:
            config['CORS_ORIGINS'] = os.environ['CORS_ORIGINS'].split(',')

        if 'MAIL_FROM' in os.environ:
            config['MAIL_FROM'] = os.environ['MAIL_FROM']

        if 'SMTP_PASSWORD' in os.environ:
            config['SMTP_PASSWORD'] = os.environ['SMTP_PASSWORD']

        if 'GOOGLE_TRACKING_ID' in os.environ:
            config['GOOGLE_TRACKING_ID'] = os.environ['GOOGLE_TRACKING_ID']

        if 'PLUGINS' in os.environ:
            config['PLUGINS'] = os.environ['PLUGINS'].split(',')

        # Runtime config check
        if config['CUSTOMER_VIEWS'] and not config['AUTH_REQUIRED']:
            raise RuntimeError('Must enable authentication to use customer views')

        if config['CUSTOMER_VIEWS'] and not config['ADMIN_USERS']:
            raise RuntimeError('Customer views is enabled but there are no admin users')

        return config
<commit_msg>Do not deprecate gitlab and keycloack settings (#918)<commit_after>import os

from flask import Flask

class Config:

    def __init__(self, app: Flask=None) -> None:
        self.app = None
        if app:
            self.init_app(app)

    def init_app(self, app: Flask) -> None:
        config = self.get_user_config()
        app.config.update(config)

    @staticmethod
    def get_user_config():
        from flask import Config
        config = Config('/')

        config.from_object('alerta.settings')
        config.from_pyfile('/etc/alertad.conf', silent=True)
        config.from_envvar('ALERTA_SVR_CONF_FILE', silent=True)

        if 'DEBUG' in os.environ:
            config['DEBUG'] = True

        if 'BASE_URL' in os.environ:
            config['BASE_URL'] = os.environ['BASE_URL']

        if 'USE_PROXYFIX' in os.environ:
            config['USE_PROXYFIX'] = True if os.environ['USE_PROXYFIX'] == 'True' else False

        if 'SECRET_KEY' in os.environ:
            config['SECRET_KEY'] = os.environ['SECRET_KEY']

        database_url = (
            os.environ.get('DATABASE_URL', None) or
            # The following database settings are deprecated.
            os.environ.get('MONGO_URI', None) or
            os.environ.get('MONGODB_URI', None) or
            os.environ.get('MONGOHQ_URL', None) or
            os.environ.get('MONGOLAB_URI', None)
        )
        # Use app config for DATABASE_URL if no env var from above override it
        config['DATABASE_URL'] = database_url or config['DATABASE_URL']

        if 'DATABASE_NAME' in os.environ:
            config['DATABASE_NAME'] = os.environ['DATABASE_NAME']

        if 'AUTH_REQUIRED' in os.environ:
            config['AUTH_REQUIRED'] = True if os.environ['AUTH_REQUIRED'] == 'True' else False

        if 'AUTH_PROVIDER' in os.environ:
            config['AUTH_PROVIDER'] = os.environ['AUTH_PROVIDER']

        if 'ADMIN_USERS' in os.environ:
            config['ADMIN_USERS'] = os.environ['ADMIN_USERS'].split(',')

        if 'SIGNUP_ENABLED' in os.environ:
            config['SIGNUP_ENABLED'] = True if os.environ['SIGNUP_ENABLED'] == 'True' else False

        if 'CUSTOMER_VIEWS' in os.environ:
            config['CUSTOMER_VIEWS'] = True if os.environ['CUSTOMER_VIEWS'] == 'True' else False

        if 'OAUTH2_CLIENT_ID' in os.environ:
            config['OAUTH2_CLIENT_ID'] = os.environ['OAUTH2_CLIENT_ID']

        if 'OAUTH2_CLIENT_SECRET' in os.environ:
            config['OAUTH2_CLIENT_SECRET'] = os.environ['OAUTH2_CLIENT_SECRET']

        if 'ALLOWED_EMAIL_DOMAINS' in os.environ:
            config['ALLOWED_EMAIL_DOMAINS'] = os.environ['ALLOWED_EMAIL_DOMAINS'].split(',')

        if 'AZURE_TENANT' in os.environ:
            config['AZURE_TENANT'] = os.environ['AZURE_TENANT']

        if 'GITHUB_URL' in os.environ:
            config['GITHUB_URL'] = os.environ['GITHUB_URL']

        if 'ALLOWED_GITHUB_ORGS' in os.environ:
            config['ALLOWED_GITHUB_ORGS'] = os.environ['ALLOWED_GITHUB_ORGS'].split(',')

        if 'GITLAB_URL' in os.environ:
            config['GITLAB_URL'] = os.environ['GITLAB_URL']

        if 'ALLOWED_GITLAB_GROUPS' in os.environ:
            config['ALLOWED_OIDC_ROLES'] = os.environ['ALLOWED_GITLAB_GROUPS'].split(',')

        if 'KEYCLOAK_URL' in os.environ:
            config['KEYCLOAK_URL'] = os.environ['KEYCLOAK_URL']

        if 'KEYCLOAK_REALM' in os.environ:
            config['KEYCLOAK_REALM'] = os.environ['KEYCLOAK_REALM']

        if 'ALLOWED_KEYCLOAK_ROLES' in os.environ:
            config['ALLOWED_OIDC_ROLES'] = os.environ['ALLOWED_KEYCLOAK_ROLES'].split(',')

        if 'OIDC_ISSUER_URL' in os.environ:
            config['OIDC_ISSUER_URL'] = os.environ['OIDC_ISSUER_URL']

        if 'ALLOWED_OIDC_ROLES' in os.environ:
            config['ALLOWED_OIDC_ROLES'] = os.environ['ALLOWED_OIDC_ROLES'].split(',')

        if 'PINGFEDERATE_OPENID_ACCESS_TOKEN_URL' in os.environ:
            config['PINGFEDERATE_OPENID_ACCESS_TOKEN_URL'] = os.environ['PINGFEDERATE_OPENID_ACCESS_TOKEN_URL'].split(
                ',')

        if 'PINGFEDERATE_OPENID_PAYLOAD_USERNAME' in os.environ:
            config['PINGFEDERATE_OPENID_PAYLOAD_USERNAME'] = os.environ['PINGFEDERATE_OPENID_PAYLOAD_USERNAME'].split(
                ',')

        if 'PINGFEDERATE_OPENID_PAYLOAD_EMAIL' in os.environ:
            config['PINGFEDERATE_OPENID_PAYLOAD_EMAIL'] = os.environ['PINGFEDERATE_OPENID_PAYLOAD_EMAIL'].split(',')

        if 'PINGFEDERATE_OPENID_PAYLOAD_GROUP' in os.environ:
            config['PINGFEDERATE_OPENID_PAYLOAD_GROUP'] = os.environ['PINGFEDERATE_OPENID_PAYLOAD_GROUP'].split(',')

        if 'PINGFEDERATE_PUBKEY_LOCATION' in os.environ:
            config['PINGFEDERATE_PUBKEY_LOCATION'] = os.environ['PINGFEDERATE_PUBKEY_LOCATION'].split(',')

        if 'PINGFEDERATE_TOKEN_ALGORITHM' in os.environ:
            config['PINGFEDERATE_TOKEN_ALGORITHM'] = os.environ['PINGFEDERATE_TOKEN_ALGORITHM'].split(',')

        if 'CORS_ORIGINS' in os.environ:
            config['CORS_ORIGINS'] = os.environ['CORS_ORIGINS'].split(',')

        if 'MAIL_FROM' in os.environ:
            config['MAIL_FROM'] = os.environ['MAIL_FROM']

        if 'SMTP_PASSWORD' in os.environ:
            config['SMTP_PASSWORD'] = os.environ['SMTP_PASSWORD']

        if 'GOOGLE_TRACKING_ID' in os.environ:
            config['GOOGLE_TRACKING_ID'] = os.environ['GOOGLE_TRACKING_ID']

        if 'PLUGINS' in os.environ:
            config['PLUGINS'] = os.environ['PLUGINS'].split(',')

        # Runtime config check
        if config['CUSTOMER_VIEWS'] and not config['AUTH_REQUIRED']:
            raise RuntimeError('Must enable authentication to use customer views')

        if config['CUSTOMER_VIEWS'] and not config['ADMIN_USERS']:
            raise RuntimeError('Customer views is enabled but there are no admin users')

        return config
<|endoftext|>


<commit_before>import asyncio
import logging
import traceback

import discord
from discord.ext import commands

from ..tools import Cog, is_in_channel, is_in_guild

log = logging.getLogger(__name__)

class CommandErrorHandler(Cog):
    @Cog.listener()
    async def on_command_error(self, ctx: commands.Context, error: commands.CommandError):
        """The event triggered when an error is raised while invoking a command."""
        if isinstance(error, commands.CommandNotFound):
            return

        msg = None
        alex = ctx.bot.owner
        if isinstance(error, asyncio.TimeoutError):
            msg = f"timed out. you can start again with {ctx.prefix}{ctx.command}"

        if isinstance(error, commands.DisabledCommand):
            msg = f'{ctx.command} has been disabled.'

        elif isinstance(error, commands.NotOwner):
            msg = f'{ctx.command} is a owner only command.'

        elif isinstance(error, commands.NoPrivateMessage):
            msg = f'{ctx.command} can not be used in Private Messages.'

        elif isinstance(error, commands.BadArgument):
            msg = f'Bad argument: {error} See {ctx.prefix}help {ctx.command} for help!'
            log.warning(f"bad argument on {ctx.command}: {error}")

        elif isinstance(error, commands.CheckFailure):
            msg = 'A Check failed for this command.'

        elif isinstance(error, commands.MissingRequiredArgument):
            msg = f'Parameter {error.param} is required but missing, See {ctx.prefix}help {ctx.command} for help!'
        elif isinstance(error, commands.MissingPermissions):
            msg = 'You do not have permission to run that command.'
        elif isinstance(error, commands.CommandInvokeError):
            error = error.original

            if isinstance(error, discord.Forbidden):
                msg = (
                    'A permission error occurred while executing this command, '
                    'Make sure I have the required permissions and try again.'
                )

        # post the error into the chat if no short error message could be generated
        if not msg:
            trace = traceback.format_exception(type(error), error, error.__traceback__, limit=5)
            actual_trace = '\n'.join(trace)
            msg = (
                f"Something, somewhere, broke. if {alex.mention} isnt in this server, "
                f"so you'll have to join the server in `a!about`."
            )
            log.error(
                f"{ctx.author.id} broke bot running {ctx.command.cog_name}.{ctx.command.qualified_name}"
                f"\nquotable: {ctx.channel.id or 'DM'}-{ctx.message.id or None}\n"
                f":{actual_trace}"
            )

        try:
            await ctx.send(msg)
        except discord.HTTPException:
            await ctx.send('error message too long')

def setup(bot: commands.Bot):
    bot.add_cog(CommandErrorHandler(bot))
<commit_msg>catch concurrency<commit_after>import asyncio
import logging
import traceback

import discord
from discord.ext import commands

from ..tools import Cog, is_in_channel, is_in_guild

log = logging.getLogger(__name__)

class CommandErrorHandler(Cog):
    @Cog.listener()
    async def on_command_error(self, ctx: commands.Context, error: commands.CommandError):
        """The event triggered when an error is raised while invoking a command."""
        if isinstance(error, commands.CommandNotFound):
            return

        msg = None
        alex = ctx.bot.owner
        if isinstance(error, asyncio.TimeoutError):
            msg = f"timed out. you can start again with {ctx.prefix}{ctx.command}"

        if isinstance(error, commands.MaxConcurrencyReached):
            msg = f"{ctx.command} is currently being ran. please wait for it to finish."

        if isinstance(error, commands.DisabledCommand):
            msg = f'{ctx.command} has been disabled.'

        elif isinstance(error, commands.NotOwner):
            msg = f'{ctx.command} is a owner only command.'

        elif isinstance(error, commands.NoPrivateMessage):
            msg = f'{ctx.command} can not be used in Private Messages.'

        elif isinstance(error, commands.BadArgument):
            msg = f'Bad argument: {error} See {ctx.prefix}help {ctx.command} for help!'
            log.warning(f"bad argument on {ctx.command}: {error}")

        elif isinstance(error, commands.CheckFailure):
            msg = 'A Check failed for this command.'

        elif isinstance(error, commands.MissingRequiredArgument):
            msg = f'Parameter {error.param} is required but missing, See {ctx.prefix}help {ctx.command} for help!'
        elif isinstance(error, commands.MissingPermissions):
            msg = 'You do not have permission to run that command.'
        elif isinstance(error, commands.CommandInvokeError):
            error = error.original

            if isinstance(error, discord.Forbidden):
                msg = (
                    'A permission error occurred while executing this command, '
                    'Make sure I have the required permissions and try again.'
                )

        # post the error into the chat if no short error message could be generated
        if not msg:
            trace = traceback.format_exception(type(error), error, error.__traceback__, limit=5)
            actual_trace = '\n'.join(trace)
            msg = (
                f"Something, somewhere, broke. if {alex.mention} isnt in this server, "
                f"so you'll have to join the server in `a!about`."
            )
            log.error(
                f"{ctx.author.id} broke bot running {ctx.command.cog_name}.{ctx.command.qualified_name}"
                f"\nquotable: {ctx.channel.id or 'DM'}-{ctx.message.id or None}\n"
                f":{actual_trace}"
            )

        try:
            await ctx.send(msg)
        except discord.HTTPException:
            await ctx.send('error message too long')

def setup(bot: commands.Bot):
    bot.add_cog(CommandErrorHandler(bot))
<|endoftext|>


<commit_before>import logging
log = logging.getLogger(__name__)

from pyramid.config import Configurator
from sqlalchemy import engine_from_config

from .models import DBSession

required_settings = [
        'pyramid.secret.session',
        'pyramid.secret.auth',
        ]

def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    config = Configurator(settings=settings)

    do_start = True

    for _req in required_settings:
        if _req not in settings:
            log.error('{} is not set in configuration file.'.format(_req))
            do_start = False

    if do_start is False:
        log.error('Unable to start due to missing configuration')
        exit(-1)

    # Include the transaction manager
    config.include('pyramid_tm')

    config.include('.session')
    config.include('.security')

    config.add_static_view('css', 'alexandria:static/css', cache_max_age=3600)
    config.add_static_view('js', 'alexandria:static/js', cache_max_age=3600)
    config.add_static_view('static', 'alexandria:static', cache_max_age=3600)

    config.add_route('main',
            '/*traverse',
            factory='.traversal.Root',
            use_global_views=True
            )

    # Scan the views sub-module
    config.scan('.views')

    return config.make_wsgi_app()

<commit_msg>Add static view for the HTML static folder<commit_after>import logging
log = logging.getLogger(__name__)

from pyramid.config import Configurator
from sqlalchemy import engine_from_config

from .models import DBSession

required_settings = [
        'pyramid.secret.session',
        'pyramid.secret.auth',
        ]

def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    config = Configurator(settings=settings)

    do_start = True

    for _req in required_settings:
        if _req not in settings:
            log.error('{} is not set in configuration file.'.format(_req))
            do_start = False

    if do_start is False:
        log.error('Unable to start due to missing configuration')
        exit(-1)

    # Include the transaction manager
    config.include('pyramid_tm')

    config.include('.session')
    config.include('.security')

    config.add_static_view('css', 'alexandria:static/css', cache_max_age=3600)
    config.add_static_view('js', 'alexandria:static/js', cache_max_age=3600)
    config.add_static_view('html', 'alexandria:static/html', cache_max_age=3600)
    config.add_static_view('static', 'alexandria:static', cache_max_age=3600)

    config.add_route('main',
            '/*traverse',
            factory='.traversal.Root',
            use_global_views=True
            )

    # Scan the views sub-module
    config.scan('.views')

    return config.make_wsgi_app()

<|endoftext|>


<commit_before>import lmfit
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from tseries import Constant
from checks import check_oseries
from stats import Statistics

class Model:
    def __init__(self, oseries, xy=(0, 0), metadata=None, freq=None,
                 fillnan='drop'):
        """
        Initiates a time series model.

        Parameters
        ----------
        oseries: pd.Series
            pandas Series object containing the dependent time series. The
            observation can be non-equidistant.
        xy: Optional[tuple]
            XY location of the oseries in lat-lon format.
        metadata: Optional[dict]
            Dictionary containing metadata of the model.
        freq: Optional[str]
            String containing the desired frequency. By default freq=None and the
            observations are used as they are. The required string format is found
            at http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset
            -aliases
        fillnan: Optional[str or float]
            Methods or float number to fill nan-values. Default values is
            'drop'. Currently supported options are: 'interpolate', float,
            'mean' and, 'drop'. Interpolation is performed with a standard linear
            interpolation.

        """
        self.oseries = check_oseries(oseries, freq, fillnan)
        self.xy = xy
        self.metadata = metadata
        self.odelt = self.oseries.index.to_series().diff() / np.timedelta64(1, 'D')
        # delt converted to days
        self.tserieslist = []
        self.noisemodel = None

    def addtseries(self, tseries):
        """
        adds a time series model component to the Model.

        """
        self.tserieslist.append(tseries)

    def addnoisemodel(self, noisemodel):
        """
        Adds a noise model to the time series Model.

        """
        self.noisemodel = noisemodel

    def simulate(self, parameters=None, tmin=None, tmax=None, freq='D'):
        """

        Parameters
        ----------
        t: Optional[pd.series.index]
            Time indices to use for the simulation of the time series model.
        p: Optional[array]
            Array of the parameters used in the time series model.
        noise:

        Returns
        -------
        Pandas Series object containing the simulated time series.

        """

        # Default option when not tmin and tmax is provided
        if tmin is None:
            tmin = self.tmin
        if tmax is None:
            tmax = self.tmax

        tindex = pd.date_range(tmin, tmax, freq=freq)

        if parameters is None:
            parameters = self.parameters
        h = pd.Series(data=0, index=tindex)
        istart = 0  # Track parameters index to pass to ts object
        for ts in self.tserieslist:
            h += ts.simulate(tindex, parameters[istart: istart + ts.nparam])
            istart += ts.nparam
        return h

    def residuals(self, parameters=None, tmin=None, tmax=None, solvemethod='lmfit',
                  noise=False):
        """
        Method that is called by the solve function to calculate the residuals.

        """
        if tmin is None:
            tmin = self.oseries.index.min()
        if tmax is None:
            tmax = self.oseries.index.max()
        tindex = self.oseries[tmin: tmax].index  # times used for calibration

        if isinstance(parameters, np.ndarray):
            p = parameters
        elif isinstance(parameters, lmfit.parameter.Parameters):  # probably needs to be a function call
            p = np.array([p.value for p in parameters.values()])
        elif parameters is None:
            p = self.parameters

        # h_observed - h_simulated
        r = self.oseries[tindex] - self.simulate(p, tmin, tmax)[tindex]
        if noise and (self.noisemodel is not None):
            r = self.noisemodel.simulate(r, self.odelt[tindex], tindex,
                                         p[-self.noisemodel.nparam])
        if np.isnan(sum(r ** 2)):
            print 'nan problem in residuals'  # quick and dirty check
        return r

    def sse(self, parameters=None, tmin=None, tmax=None, solvemethod='lmfit',
                  noise=False):
        res = self.residuals(parameters, tmin=tmin, tmax=tmax,
                             solvemethod=solvemethod, noise=noise)
        return sum(res ** 2)

    def solve(self, tmin=None, tmax=None, solvemethod='lmfit', report=True,
              noise=True, initialize=False, solve=True):
        """
        Methods to solve the time series model.

        Parameters
        ----------
        tmin: Optional[str]
            String with a start date for the simulation period (E.g. '1980')
        tmax: Optional[str]
            String with an end date for the simulation period (E.g. '2010')
        solvemethod: Optional[str]
            Methods used to solve the time series model. Only 'lmfit' is currently
            supported.
        report: Boolean
            Print a report to the screen after optimization finished.
        noise: Boolean
            Use the nose model (True) or not (False).
        initialize: Boolean
            Reset initial parameteres.

        """
        if noise and (self.noisemodel is None):
            print 'Warning, solution with noise model while noise model is not ' \
                  'defined. No noise model is used'
        self.solvemethod = solvemethod
        self.nparam = sum(ts.nparam for ts in self.tserieslist)
        if self.noisemodel is not None:
            self.nparam += self.noisemodel.nparam

        # Check series with tmin, tmax
        tmin, tmax = self.check_series(tmin, tmax)

        # Initialize parameters
        if initialize is True:
            for ts in self.tserieslist:
                ts.set_init_parameters()
            if self.noisemodel: self.noisemodel.set_init_parameters()

        #TODO: the initialization should probably be a separate function and a pandas parmeter dataframe should be stored
        if solve:
            if self.solvemethod == 'lmfit':
                parameters = lmfit.Parameters()
                for ts in self.tserieslist:
                    for k in ts.parameters.index:
                        p = ts.parameters.loc[k]
                        # needed because lmfit doesn't take nan as input
                        pvalues = np.where(np.isnan(p.values), None, p.values)
                        parameters.add(k, value=pvalues[0], min=pvalues[1],
                                       max=pvalues[2], vary=pvalues[3])
                if self.noisemodel is not None:
                    for k in self.noisemodel.parameters.index:
                        p = self.noisemodel.parameters.loc[k]
                        pvalues = np.where(np.isnan(p.values), None,
                                           p.values)  # needed because lmfit doesn't
                        # take nan as input
                        parameters.add(k, value=pvalues[0], min=pvalues[1],
                                       max=pvalues[2], vary=pvalues[3])
                self.lmfit_params = parameters
                self.fit = lmfit.minimize(fcn=self.residuals, params=parameters,
                                          ftol=1e-3, epsfcn=1e-4,
                                          args=(tmin, tmax, self.solvemethod, noise))
                if report: print lmfit.fit_report(self.fit)
                self.parameters = np.array([p.value for p in self.fit.params.values()])
                self.paramdict = self.fit.params.valuesdict()
                # Return parameters to tseries
                for ts in self.tserieslist:
                    for k in ts.parameters.index:
                        ts.parameters.loc[k].value = self.paramdict[k]
                if self.noisemodel is not None:
                    for k in self.noisemodel.parameters.index:
                        self.noisemodel.parameters.loc[k].value = self.paramdict[k]

                # Make the Statistics class available after optimization
                self.stats = Statistics(self)

    def check_series(self, tmin=None, tmax=None):
        """
        Function to check if the dependent and independent time series match.

        - tmin and tmax are in oseries.index for optimization.
        - at least one stress is available for simulation between tmin and tmax.
        -

        Parameters
        ----------
        tmin
        tmax

        Returns
        -------

        """

        # Store tmax and tmin. If none is provided, use oseries to set them.
        if tmin is None:
            tmin = self.oseries.index.min()
        else:
            tmin = pd.tslib.Timestamp(tmin)
        if tmax is None:
            tmax = self.oseries.index.max()
        else:
            tmax = pd.tslib.Timestamp(tmax)

        # Check tmin and tmax compared to oseries and raise warning.
        if tmin not in self.oseries.index:
            print 'Warning, given tmin is outside of the oseries. First valid ' \
                  'index is %s' % self.oseries.first_valid_index()
        if tmax not in self.oseries.index:
            print 'Warning, given tmax is outside of the oseries. Last valid ' \
                  'index is %s' % self.oseries.last_valid_index()

        # Get maximum simulation period.
        tstmin = None
        tstmax = None

        for ts in self.tserieslist:
            if isinstance(ts, Constant):  # Check if it is not a constant tseries.
                pass
            else:
                if tstmin == None:
                    tstmin = ts.tmin
                elif ts.tmin < tstmin:
                    tstmin = ts.tmin
                if tstmax == None:
                    tstmax = ts.tmax
                elif ts.tmax > tstmax:
                    tstmax = ts.tmax

        self.tmin = tmin
        self.tmax = tmax

        # Check if chosen period is within or outside the maximum period.
        if tstmin > tmin:
            tmin = tstmin
        if tstmax < tmax:
            tmax = tstmax

        return tmin, tmax

    def plot(self, tmin=None, tmax=None, oseries=True):
        """

        Parameters
        ----------
        oseries: Boolean
            True to plot the observed time series.

        Returns
        -------
        Plot of the simulated and optionally the observed time series

        """
        h = self.simulate(tmin, tmax)
        plt.figure()
        h.plot()
        if oseries:
            self.oseries.plot(linestyle='', marker='.', color='k', markersize=3)
        plt.show()

    def plot_results(self, tmin=None, tmax=None, savefig=False):
        """

        Parameters
        ----------
        tmin/tmax: str
            start and end time for plotting
        savefig: Optional[Boolean]
            True to save the figure, False is default. Figure is saved in the
            current working directory when running your python scripts.

        Returns
        -------

        """
        plt.figure('Model Results', facecolor='white')
        gs = plt.GridSpec(3, 4, wspace=0.2)

        # Plot the Groundwater levels
        h = self.simulate(tmin=tmin, tmax=tmax)
        ax1 = plt.subplot(gs[:2, :-1])
        h.plot(label='modeled head')
        self.oseries.plot(linestyle='', marker='.', color='k', markersize=3,
                          label='observed head')
        # ax1.xaxis.set_visible(False)
        plt.legend(loc=(0, 1), ncol=3, frameon=False, handlelength=3)
        plt.ylabel('Head [m]')

        # Plot the residuals and innovations
        residuals = self.residuals(tmin=tmin, tmax=tmax)
        ax2 = plt.subplot(gs[2, :-1])  # , sharex=ax1)
        residuals.plot(color='k', label='residuals')
        if self.noisemodel is not None:
            innovations = self.noisemodel.simulate(residuals, self.odelt)
            innovations.plot(label='innovations')
        plt.legend(loc=(0, 1), ncol=3, frameon=False, handlelength=3)
        plt.ylabel('Error [m]')
        plt.xlabel('Time [Years]')

        # Plot the Impulse Response Function
        ax3 = plt.subplot(gs[0, -1])
        n = 0
        for ts in self.tserieslist:
            p = self.parameters[n:n + ts.nparam]
            n += ts.nparam
            if "rfunc" in dir(ts):
                plt.plot(ts.rfunc.block(p))
        ax3.set_xticks(ax3.get_xticks()[::2])
        ax3.set_yticks(ax3.get_yticks()[::2])
        plt.title('Block Response')

        # Plot the Model Parameters (Experimental)
        ax4 = plt.subplot(gs[1:2, -1])
        ax4.xaxis.set_visible(False)
        ax4.yaxis.set_visible(False)
        text = np.vstack((self.paramdict.keys(), [round(float(i), 4) for i in
                                                  self.paramdict.values()])).T
        colLabels = ("Parameter", "Value")
        ytable = ax4.table(cellText=text, colLabels=colLabels, loc='center')
        ytable.scale(1, 1.1)

        # Table of the numerical diagnostic statistics.
        ax5 = plt.subplot(gs[2, -1])
        ax5.xaxis.set_visible(False)
        ax5.yaxis.set_visible(False)
        plt.text(0.05, 0.8, 'AIC: %.2f' % self.fit.aic)
        plt.text(0.05, 0.6, 'BIC: %.2f' % self.fit.bic)
        plt.show()
        if savefig:
            plt.savefig('.eps' % (self.name), bbox_inches='tight')
<commit_msg>not quite sure what changed to be honest<commit_after>import lmfit
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from tseries import Constant
from checks import check_oseries
from stats import Statistics

class Model:
    def __init__(self, oseries, xy=(0, 0), metadata=None, freq=None,
                 fillnan='drop'):
        """
        Initiates a time series model.

        Parameters
        ----------
        oseries: pd.Series
            pandas Series object containing the dependent time series. The
            observation can be non-equidistant.
        xy: Optional[tuple]
            XY location of the oseries in lat-lon format.
        metadata: Optional[dict]
            Dictionary containing metadata of the model.
        freq: Optional[str]
            String containing the desired frequency. By default freq=None and the
            observations are used as they are. The required string format is found
            at http://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset
            -aliases
        fillnan: Optional[str or float]
            Methods or float number to fill nan-values. Default values is
            'drop'. Currently supported options are: 'interpolate', float,
            'mean' and, 'drop'. Interpolation is performed with a standard linear
            interpolation.

        """
        self.oseries = check_oseries(oseries, freq, fillnan)
        self.xy = xy
        self.metadata = metadata
        self.odelt = self.oseries.index.to_series().diff() / np.timedelta64(1, 'D')
        # delt converted to days
        self.tserieslist = []
        self.noisemodel = None

    def addtseries(self, tseries):
        """
        adds a time series model component to the Model.

        """
        self.tserieslist.append(tseries)

    def addnoisemodel(self, noisemodel):
        """
        Adds a noise model to the time series Model.

        """
        self.noisemodel = noisemodel

    def simulate(self, parameters=None, tmin=None, tmax=None, freq='D'):
        """

        Parameters
        ----------
        t: Optional[pd.series.index]
            Time indices to use for the simulation of the time series model.
        p: Optional[array]
            Array of the parameters used in the time series model.
        noise:

        Returns
        -------
        Pandas Series object containing the simulated time series.

        """

        # Default option when not tmin and tmax is provided
        if tmin is None:
            tmin = self.tmin
        if tmax is None:
            tmax = self.tmax

        tindex = pd.date_range(tmin, tmax, freq=freq)

        if parameters is None:
            parameters = self.parameters
        h = pd.Series(data=0, index=tindex)
        istart = 0  # Track parameters index to pass to ts object
        for ts in self.tserieslist:
            h += ts.simulate(tindex, parameters[istart: istart + ts.nparam])
            istart += ts.nparam
        return h

    def residuals(self, parameters=None, tmin=None, tmax=None, solvemethod='lmfit',
                  noise=False):
        """
        Method that is called by the solve function to calculate the residuals.

        """
        if tmin is None:
            tmin = self.oseries.index.min()
        if tmax is None:
            tmax = self.oseries.index.max()
        tindex = self.oseries[tmin: tmax].index  # times used for calibration

        if isinstance(parameters, np.ndarray):
            p = parameters
        elif isinstance(parameters, lmfit.parameter.Parameters):  # probably needs to be a function call
            p = np.array([p.value for p in parameters.values()])
        elif parameters is None:
            p = self.parameters

        # h_observed - h_simulated
        r = self.oseries[tindex] - self.simulate(p, tmin, tmax)[tindex]
        if noise and (self.noisemodel is not None):
            r = self.noisemodel.simulate(r, self.odelt[tindex], tindex,
                                         p[-self.noisemodel.nparam])
        if np.isnan(sum(r ** 2)):
            print 'nan problem in residuals'  # quick and dirty check
        return r

    def sse(self, parameters=None, tmin=None, tmax=None, solvemethod='lmfit',
                  noise=False):
        res = self.residuals(parameters, tmin=tmin, tmax=tmax,
                             solvemethod=solvemethod, noise=noise)
        return sum(res ** 2)

    def solve(self, tmin=None, tmax=None, solvemethod='lmfit', report=True,
              noise=True, initialize=False, solve=True):
        """
        Methods to solve the time series model.

        Parameters
        ----------
        tmin: Optional[str]
            String with a start date for the simulation period (E.g. '1980')
        tmax: Optional[str]
            String with an end date for the simulation period (E.g. '2010')
        solvemethod: Optional[str]
            Methods used to solve the time series model. Only 'lmfit' is currently
            supported.
        report: Boolean
            Print a report to the screen after optimization finished.
        noise: Boolean
            Use the nose model (True) or not (False).
        initialize: Boolean
            Reset initial parameteres.

        """
        if noise and (self.noisemodel is None):
            print 'Warning, solution with noise model while noise model is not ' \
                  'defined. No noise model is used'
        self.solvemethod = solvemethod
        self.nparam = sum(ts.nparam for ts in self.tserieslist)
        if self.noisemodel is not None:
            self.nparam += self.noisemodel.nparam

        # Check series with tmin, tmax
        tmin, tmax = self.check_series(tmin, tmax)

        # Initialize parameters
        if initialize is True:
            for ts in self.tserieslist:
                ts.set_init_parameters()
            if self.noisemodel: self.noisemodel.set_init_parameters()

        #TODO: the initialization should probably be a separate function and a pandas parmeter dataframe should be stored
        if solve:
            if self.solvemethod == 'lmfit':
                parameters = lmfit.Parameters()
                for ts in self.tserieslist:
                    for k in ts.parameters.index:
                        p = ts.parameters.loc[k]
                        # needed because lmfit doesn't take nan as input
                        pvalues = np.where(np.isnan(p.values), None, p.values)
                        parameters.add(k, value=pvalues[0], min=pvalues[1],
                                       max=pvalues[2], vary=pvalues[3])
                if self.noisemodel is not None:
                    for k in self.noisemodel.parameters.index:
                        p = self.noisemodel.parameters.loc[k]
                        pvalues = np.where(np.isnan(p.values), None,
                                           p.values)  # needed because lmfit doesn't
                        # take nan as input
                        parameters.add(k, value=pvalues[0], min=pvalues[1],
                                       max=pvalues[2], vary=pvalues[3])
                self.lmfit_params = parameters
                self.fit = lmfit.minimize(fcn=self.residuals, params=parameters,
                                          ftol=1e-3, epsfcn=1e-4,
                                          args=(tmin, tmax, self.solvemethod, noise))
                if report: print lmfit.fit_report(self.fit)
                self.parameters = np.array([p.value for p in self.fit.params.values()])
                self.paramdict = self.fit.params.valuesdict()
                # Return parameters to tseries
                for ts in self.tserieslist:
                    for k in ts.parameters.index:
                        ts.parameters.loc[k].value = self.paramdict[k]
                if self.noisemodel is not None:
                    for k in self.noisemodel.parameters.index:
                        self.noisemodel.parameters.loc[k].value = self.paramdict[k]

                # Make the Statistics class available after optimization
                self.stats = Statistics(self)

    def check_series(self, tmin=None, tmax=None):
        """
        Function to check if the dependent and independent time series match.

        - tmin and tmax are in oseries.index for optimization.
        - at least one stress is available for simulation between tmin and tmax.
        -

        Parameters
        ----------
        tmin
        tmax

        Returns
        -------

        """

        # Store tmax and tmin. If none is provided, use oseries to set them.
        if tmin is None:
            tmin = self.oseries.index.min()
        else:
            tmin = pd.tslib.Timestamp(tmin)
        if tmax is None:
            tmax = self.oseries.index.max()
        else:
            tmax = pd.tslib.Timestamp(tmax)

        # Check tmin and tmax compared to oseries and raise warning.
        if tmin not in self.oseries.index:
            print 'Warning, given tmin is outside of the oseries. First valid ' \
                  'index is %s' % self.oseries.first_valid_index()
        if tmax not in self.oseries.index:
            print 'Warning, given tmax is outside of the oseries. Last valid ' \
                  'index is %s' % self.oseries.last_valid_index()

        # Get maximum simulation period.
        tstmin = self.tserieslist[0].tmin
        tstmax = self.tserieslist[0].tmax

        for ts in self.tserieslist:
            if isinstance(ts, Constant):  # Check if it is not a constant tseries.
                pass
            else:
                if ts.tmin < tstmin:
                    tstmin = ts.tmin
                if ts.tmax > tstmax:
                    tstmax = ts.tmax

        self.tmin = tmin
        self.tmax = tmax

        # Check if chosen period is within or outside the maximum period.
        if tstmin > tmin:
            tmin = tstmin
        if tstmax < tmax:
            tmax = tstmax

        return tmin, tmax

    def plot(self, tmin=None, tmax=None, oseries=True):
        """

        Parameters
        ----------
        oseries: Boolean
            True to plot the observed time series.

        Returns
        -------
        Plot of the simulated and optionally the observed time series

        """
        h = self.simulate(tmin, tmax)
        plt.figure()
        h.plot()
        if oseries:
            self.oseries.plot(linestyle='', marker='.', color='k', markersize=3)
        plt.show()

    def plot_results(self, tmin=None, tmax=None, savefig=False):
        """

        Parameters
        ----------
        tmin/tmax: str
            start and end time for plotting
        savefig: Optional[Boolean]
            True to save the figure, False is default. Figure is saved in the
            current working directory when running your python scripts.

        Returns
        -------

        """
        plt.figure('Model Results', facecolor='white')
        gs = plt.GridSpec(3, 4, wspace=0.2)

        # Plot the Groundwater levels
        h = self.simulate(tmin=tmin, tmax=tmax)
        ax1 = plt.subplot(gs[:2, :-1])
        h.plot(label='modeled head')
        self.oseries.plot(linestyle='', marker='.', color='k', markersize=3,
                          label='observed head')
        # ax1.xaxis.set_visible(False)
        plt.legend(loc=(0, 1), ncol=3, frameon=False, handlelength=3)
        plt.ylabel('Head [m]')

        # Plot the residuals and innovations
        residuals = self.residuals(tmin=tmin, tmax=tmax)
        ax2 = plt.subplot(gs[2, :-1])  # , sharex=ax1)
        residuals.plot(color='k', label='residuals')
        if self.noisemodel is not None:
            innovations = self.noisemodel.simulate(residuals, self.odelt)
            innovations.plot(label='innovations')
        plt.legend(loc=(0, 1), ncol=3, frameon=False, handlelength=3)
        plt.ylabel('Error [m]')
        plt.xlabel('Time [Years]')

        # Plot the Impulse Response Function
        ax3 = plt.subplot(gs[0, -1])
        n = 0
        for ts in self.tserieslist:
            p = self.parameters[n:n + ts.nparam]
            n += ts.nparam
            if "rfunc" in dir(ts):
                plt.plot(ts.rfunc.block(p))
        ax3.set_xticks(ax3.get_xticks()[::2])
        ax3.set_yticks(ax3.get_yticks()[::2])
        plt.title('Block Response')

        # Plot the Model Parameters (Experimental)
        ax4 = plt.subplot(gs[1:2, -1])
        ax4.xaxis.set_visible(False)
        ax4.yaxis.set_visible(False)
        text = np.vstack((self.paramdict.keys(), [round(float(i), 4) for i in
                                                  self.paramdict.values()])).T
        colLabels = ("Parameter", "Value")
        ytable = ax4.table(cellText=text, colLabels=colLabels, loc='center')
        ytable.scale(1, 1.1)

        # Table of the numerical diagnostic statistics.
        ax5 = plt.subplot(gs[2, -1])
        ax5.xaxis.set_visible(False)
        ax5.yaxis.set_visible(False)
        plt.text(0.05, 0.8, 'AIC: %.2f' % self.fit.aic)
        plt.text(0.05, 0.6, 'BIC: %.2f' % self.fit.bic)
        plt.show()
        if savefig:
            plt.savefig('.eps' % (self.name), bbox_inches='tight')
<|endoftext|>


<commit_before>#! /usr/bin/env python3

import sys, time
from time import sleep
from quick2wire.parts.pcf8591 import *
from quick2wire.i2c import I2CMaster
#from vis import volt_plot
from writefile import *
from tkinter import *

class adc_reader():

    def __init__(self):

        self.address = int(sys.argv[1]) if len(sys.argv) > 1 else BASE_ADDRESS
        self.pin_index1 = int(sys.argv[2]) if len(sys.argv) > 2 else 0
        self.pin_index2 = int(sys.argv[3]) if len(sys.argv) > 3 else 1
        self.record = False

    def run(filename):
        with I2CMaster() as i2c:
            adc = PCF8591(i2c, THREE_DIFFERENTIAL)
            pin1 = adc.differential_input(1)

            #pin2 = adc.single_ended_input(pin_index2)
            # root = Tk()
            # def key(event):
            #     print(event.char)
            #     if event.char == 'a':
            #         subvocal = 'Y'
            #         voltage = pin1.value * 3.3
            #         print("read: {} : {}".format(count, voltage))
            #         current = time.clock() - start
            #         write_file('test.csv', current, voltage, subvocal)
            #     else:
            #         subvocal = "N"
            #         voltage = pin1.value * 3.3
            #         print("read: {} : {}".format(count, voltage))
            #         current = time.clock() - start
            #         write_file('test.csv', current, voltage, subvocal)

            # frame = Frame(root, width=300, height=300)
            # frame.bind("<Key>", key)
            # frame.pack()
            # root.mainloop()
            #data = {}
            count = 0
            start = time.clock()

            with open(filename, 'w') as csvfile:

                fieldnames = ['time', 'count', 'voltage']
                writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
                writer.writeheader()
                count = 1
                while self.record:
                    voltage = pin1.value * 3.3
                    strength = ['-' for i in range(int(pin1.value//16))]
                    reading += [bar for bar in strength]
                    print (reading)
                    #sleep(0.1)
                    count += 1
                    current = time.clock() - start
                    #data[count] = pin1.raw_value
                    #volt_plot(count, data)
                    writer.writerow({'time': current, 'count': count, 'voltage': voltage})
            current += 1
<commit_msg>fix: Reflex class syntax<commit_after>#! /usr/bin/env python3

import sys, time
from time import sleep
from quick2wire.parts.pcf8591 import *
from quick2wire.i2c import I2CMaster
#from vis import volt_plot
from writefile import *
from tkinter import *

class adc_reader():

    def __init__(self):

        self.address = int(sys.argv[1]) if len(sys.argv) > 1 else BASE_ADDRESS
        self.pin_index1 = int(sys.argv[2]) if len(sys.argv) > 2 else 0
        self.pin_index2 = int(sys.argv[3]) if len(sys.argv) > 3 else 1
        self.record = False

    def run(self, filename):
        with I2CMaster() as i2c:
            adc = PCF8591(i2c, THREE_DIFFERENTIAL)
            pin1 = adc.differential_input(1)

            #pin2 = adc.single_ended_input(pin_index2)
            # root = Tk()
            # def key(event):
            #     print(event.char)
            #     if event.char == 'a':
            #         subvocal = 'Y'
            #         voltage = pin1.value * 3.3
            #         print("read: {} : {}".format(count, voltage))
            #         current = time.clock() - start
            #         write_file('test.csv', current, voltage, subvocal)
            #     else:
            #         subvocal = "N"
            #         voltage = pin1.value * 3.3
            #         print("read: {} : {}".format(count, voltage))
            #         current = time.clock() - start
            #         write_file('test.csv', current, voltage, subvocal)

            # frame = Frame(root, width=300, height=300)
            # frame.bind("<Key>", key)
            # frame.pack()
            # root.mainloop()
            #data = {}
            count = 0
            start = time.clock()

            with open(filename, 'w') as csvfile:

                fieldnames = ['time', 'count', 'voltage']
                writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
                writer.writeheader()
                count = 1
                while self.record:
                    reading = ''
                    voltage = pin1.value * 3.3
                    strength = ['-' for i in range(int(pin1.value//16))]
                    reading += [bar for bar in strength]
                    print (reading)
                    #sleep(0.1)
                    count += 1
                    current = time.clock() - start
                    #data[count] = pin1.raw_value
                    #volt_plot(count, data)
                    writer.writerow({'time': current, 'count': count, 'voltage': voltage})
            current += 1
<|endoftext|>


<commit_before>#!/usr/bin/env python

import i3
import re
import subprocess
import getopt
import sys
import os

def find_parent(window_id):
    """
        Find the parent of a given window id
    """
    root_window = i3.get_tree()
    result = [None]

    def finder(n, p=None):
        if result[0] is not None:
            return
        for node in n:
            if node['id'] == window_id:
                result[0] = p
                return
            if len(node['nodes']):
                finder(node['nodes'], node)

    finder(root_window['nodes'])
    return result[0]

def set_layout():
    """
        Set the layout/split for the currently
        focused window to either vertical or
        horizontal, depending on its width/height
    """
    current_win = i3.filter(nodes=[], focused=True)
    for win in current_win:
        parent = find_parent(win['id'])

        if parent and "rect" in parent and parent['layout'] != 'tabbed':
            height = parent['rect']['height']
            width = parent['rect']['width']

            if height > width:
                new_layout = 'vertical'
            else:
                new_layout = 'horizontal'

            i3.split(new_layout)

def print_help():
    print("Usage: " + sys.argv[0] + " [-p path/to/pid.file]")
    print("")
    print("Options:")
    print("    -p path/to/pid.file   Saves the PID for this program in the filename specified")
    print("")

def main():
    """
        Main function - listen for window focus
        changes and call set_layout when focus
        changes
    """
    opt_list, args = getopt.getopt(sys.argv[1:], 'hp:')
    pid_file = None
    for opt in opt_list:
        if opt[0] == "-h":
            print_help()
            sys.exit()
        if opt[0] == "-p":
            pid_file = opt[1]

    if pid_file:
        with open(pid_file, 'w') as f:
            f.write(str(os.getpid()))

    process = subprocess.Popen(
        ['xprop', '-root', '-spy'],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    regex = re.compile(b'^_NET_CLIENT_LIST_STACKING|^_NET_ACTIVE_WINDOW')

    last_line = ""
    while True:
        line = process.stdout.readline()
        if line == b'': #X is dead
            break
        if line == last_line:
            continue
        if regex.match(line):
            set_layout()
        last_line = line

    process.kill()
    sys.exit()

if __name__ == "__main__":
    main()
<commit_msg>Prevents splitting when on stacked layout<commit_after>#!/usr/bin/env python

import i3
import re
import subprocess
import getopt
import sys
import os

def find_parent(window_id):
    """
        Find the parent of a given window id
    """
    root_window = i3.get_tree()
    result = [None]

    def finder(n, p=None):
        if result[0] is not None:
            return
        for node in n:
            if node['id'] == window_id:
                result[0] = p
                return
            if len(node['nodes']):
                finder(node['nodes'], node)

    finder(root_window['nodes'])
    return result[0]

def set_layout():
    """
        Set the layout/split for the currently
        focused window to either vertical or
        horizontal, depending on its width/height
    """
    current_win = i3.filter(nodes=[], focused=True)
    for win in current_win:
        parent = find_parent(win['id'])

        if (parent and "rect" in parent
                   and parent['layout'] != 'tabbed'
                   and parent['layout'] != 'stacked'):
            height = parent['rect']['height']
            width = parent['rect']['width']

            if height > width:
                new_layout = 'vertical'
            else:
                new_layout = 'horizontal'

            i3.split(new_layout)

def print_help():
    print("Usage: " + sys.argv[0] + " [-p path/to/pid.file]")
    print("")
    print("Options:")
    print("    -p path/to/pid.file   Saves the PID for this program in the filename specified")
    print("")

def main():
    """
        Main function - listen for window focus
        changes and call set_layout when focus
        changes
    """
    opt_list, args = getopt.getopt(sys.argv[1:], 'hp:')
    pid_file = None
    for opt in opt_list:
        if opt[0] == "-h":
            print_help()
            sys.exit()
        if opt[0] == "-p":
            pid_file = opt[1]

    if pid_file:
        with open(pid_file, 'w') as f:
            f.write(str(os.getpid()))

    process = subprocess.Popen(
        ['xprop', '-root', '-spy'],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    regex = re.compile(b'^_NET_CLIENT_LIST_STACKING|^_NET_ACTIVE_WINDOW')

    last_line = ""
    while True:
        line = process.stdout.readline()
        if line == b'': #X is dead
            break
        if line == last_line:
            continue
        if regex.match(line):
            set_layout()
        last_line = line

    process.kill()
    sys.exit()

if __name__ == "__main__":
    main()
<|endoftext|>