<commit_before>#       Licensed to the Apache Software Foundation (ASF) under one
#       or more contributor license agreements.  See the NOTICE file
#       distributed with this work for additional information
#       regarding copyright ownership.  The ASF licenses this file
#       to you under the Apache License, Version 2.0 (the
#       "License"); you may not use this file except in compliance
#       with the License.  You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#       Unless required by applicable law or agreed to in writing,
#       software distributed under the License is distributed on an
#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
#       KIND, either express or implied.  See the License for the
#       specific language governing permissions and limitations
#       under the License.

import logging
import json
import hmac
import hashlib

import requests
from bson import ObjectId
from tg import expose, validate, redirect
from tg.decorators import with_trailing_slash
from pylons import tmpl_context as c
from formencode import validators as fev, schema
from ming.odm import session

from allura.controllers import BaseController
from allura.lib import helpers as h
from allura.lib.decorators import require_post, task
from allura.lib.utils import DateJSONEncoder
from allura import model as M


log = logging.getLogger(__name__)


class WebhookCreateForm(schema.Schema):
    def __init__(self, hook):
        super(WebhookCreateForm, self).__init__()
        self.triggered_by = [ac for ac in c.project.app_configs
                             if ac.tool_name.lower() in hook.triggered_by]
        self.add_field('app', fev.OneOf(
            [unicode(ac._id) for ac in self.triggered_by]))

    url = fev.URL(not_empty=True)
    secret = fev.UnicodeString()


class WebhookControllerMeta(type):
    def __call__(cls, hook, *args, **kw):
        """Decorate the `create` post handler with a validator that references
        the appropriate webhook sender for this controller.
        """
        if hasattr(cls, 'create'):
            cls.create = validate(
                cls.create_form(hook),
                error_handler=cls.index.__func__,
            )(cls.create)
        return type.__call__(cls, hook, *args, **kw)


class WebhookController(BaseController):
    __metaclass__ = WebhookControllerMeta
    create_form = WebhookCreateForm

    def __init__(self, hook):
        super(WebhookController, self).__init__()
        self.webhook = hook

    @with_trailing_slash
    @expose('jinja:allura:templates/webhooks/create_form.html')
    def index(self, **kw):
        return {'webhook': self.webhook,
                'form': self.create_form(self.webhook)}

    @expose()
    @require_post()
    def create(self, url, app, secret=None):
        if not secret:
            secret = h.cryptographic_nonce(20)
        # TODO: catch DuplicateKeyError
        wh = M.Webhook(
            hook_url=url,
            secret=secret,
            app_config_id=ObjectId(app),
            type=self.webhook.type)
        session(wh).flush(wh)
        redirect(c.project.url() + 'admin/webhooks/')

<commit_msg>[#4542] ticket:714 Audit log of webhooks added<commit_after>#       Licensed to the Apache Software Foundation (ASF) under one
#       or more contributor license agreements.  See the NOTICE file
#       distributed with this work for additional information
#       regarding copyright ownership.  The ASF licenses this file
#       to you under the Apache License, Version 2.0 (the
#       "License"); you may not use this file except in compliance
#       with the License.  You may obtain a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#       Unless required by applicable law or agreed to in writing,
#       software distributed under the License is distributed on an
#       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
#       KIND, either express or implied.  See the License for the
#       specific language governing permissions and limitations
#       under the License.

import logging
import json
import hmac
import hashlib

import requests
from bson import ObjectId
from tg import expose, validate, redirect
from tg.decorators import with_trailing_slash
from pylons import tmpl_context as c
from formencode import validators as fev, schema
from ming.odm import session

from allura.controllers import BaseController
from allura.lib import helpers as h
from allura.lib.decorators import require_post, task
from allura.lib.utils import DateJSONEncoder
from allura import model as M


log = logging.getLogger(__name__)


class WebhookCreateForm(schema.Schema):
    def __init__(self, hook):
        super(WebhookCreateForm, self).__init__()
        self.triggered_by = [ac for ac in c.project.app_configs
                             if ac.tool_name.lower() in hook.triggered_by]
        self.add_field('app', fev.OneOf(
            [unicode(ac._id) for ac in self.triggered_by]))

    url = fev.URL(not_empty=True)
    secret = fev.UnicodeString()


class WebhookControllerMeta(type):
    def __call__(cls, hook, *args, **kw):
        """Decorate the `create` post handler with a validator that references
        the appropriate webhook sender for this controller.
        """
        if hasattr(cls, 'create'):
            cls.create = validate(
                cls.create_form(hook),
                error_handler=cls.index.__func__,
            )(cls.create)
        return type.__call__(cls, hook, *args, **kw)


class WebhookController(BaseController):
    __metaclass__ = WebhookControllerMeta
    create_form = WebhookCreateForm

    def __init__(self, hook):
        super(WebhookController, self).__init__()
        self.webhook = hook

    @with_trailing_slash
    @expose('jinja:allura:templates/webhooks/create_form.html')
    def index(self, **kw):
        return {'webhook': self.webhook,
                'form': self.create_form(self.webhook)}

    @expose()
    @require_post()
    def create(self, url, app, secret=None):
        if not secret:
            secret = h.cryptographic_nonce(20)
        # TODO: catch DuplicateKeyError
        wh = M.Webhook(
            hook_url=url,
            secret=secret,
            app_config_id=ObjectId(app),
            type=self.webhook.type)
        session(wh).flush(wh)
        M.AuditLog.log('add webhook %s %s %s',
                       wh.type, wh.hook_url, wh.app_config.url())
        redirect(c.project.url() + 'admin/webhooks/')


{'fraction_non_alphanumeric': 0.08302919708029197, 'fraction_numerical': 0.002889294403892944, 'mean_word_length': 2.792964244521338, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6854379', 'n_tokens_mistral': 1864, 'n_tokens_neox': 1829, 'n_words': 600}