prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Webhook data does not have event id
  Webhook data contains issue id only. It would be nice to have event id as well.
  
  Discussed with @mattrobenolt on IRC. Documenting it here with this issue.
  
  </issue>
  <code>
  [start of src/sentry/plugins/sentry_webhooks/plugin.py]
  1 from __future__ import absolute_import
  2 
  3 import logging
  4 import six
  5 import sentry
  6 
  7 from django import forms
  8 from django.conf import settings
  9 from django.utils.translation import ugettext_lazy as _
  10 
  11 from sentry.exceptions import PluginError
  12 from sentry.plugins.bases import notify
  13 from sentry.http import is_valid_url, safe_urlopen
  14 from sentry.utils.safe import safe_execute
  15 
  16 
  17 def validate_urls(value, **kwargs):
  18     output = []
  19     for url in value.split('\n'):
  20         url = url.strip()
  21         if not url:
  22             continue
  23         if not url.startswith(('http://', 'https://')):
  24             raise PluginError('Not a valid URL.')
  25         if not is_valid_url(url):
  26             raise PluginError('Not a valid URL.')
  27         output.append(url)
  28     return '\n'.join(output)
  29 
  30 
  31 class WebHooksOptionsForm(notify.NotificationConfigurationForm):
  32     urls = forms.CharField(
  33         label=_('Callback URLs'),
  34         widget=forms.Textarea(attrs={
  35             'class': 'span6', 'placeholder': 'https://sentry.io/callback/url'}),
  36         help_text=_('Enter callback URLs to POST new events to (one per line).'))
  37 
  38     def clean_url(self):
  39         value = self.cleaned_data.get('url')
  40         return validate_urls(value)
  41 
  42 
  43 class WebHooksPlugin(notify.NotificationPlugin):
  44     author = 'Sentry Team'
  45     author_url = 'https://github.com/getsentry/sentry'
  46     version = sentry.VERSION
  47     description = "Integrates web hooks."
  48     resource_links = [
  49         ('Bug Tracker', 'https://github.com/getsentry/sentry/issues'),
  50         ('Source', 'https://github.com/getsentry/sentry'),
  51     ]
  52 
  53     slug = 'webhooks'
  54     title = 'WebHooks'
  55     conf_title = title
  56     conf_key = 'webhooks'
  57     # TODO(dcramer): remove when this is migrated to React
  58     project_conf_form = WebHooksOptionsForm
  59     timeout = getattr(settings, 'SENTRY_WEBHOOK_TIMEOUT', 3)
  60     logger = logging.getLogger('sentry.plugins.webhooks')
  61     user_agent = 'sentry-webhooks/%s' % version
  62 
  63     def is_configured(self, project, **kwargs):
  64         return bool(self.get_option('urls', project))
  65 
  66     def get_config(self, project, **kwargs):
  67         return [{
  68             'name': 'urls',
  69             'label': 'Callback URLs',
  70             'type': 'textarea',
  71             'help': 'Enter callback URLs to POST new events to (one per line).',
  72             'placeholder': 'https://sentry.io/callback/url',
  73             'validators': [validate_urls],
  74             'required': False
  75         }]
  76 
  77     def get_group_data(self, group, event):
  78         data = {
  79             'id': six.text_type(group.id),
  80             'project': group.project.slug,
  81             'project_name': group.project.name,
  82             'logger': event.get_tag('logger'),
  83             'level': event.get_tag('level'),
  84             'culprit': group.culprit,
  85             'message': event.get_legacy_message(),
  86             'url': group.get_absolute_url(),
  87         }
  88         data['event'] = dict(event.data or {})
  89         data['event']['tags'] = event.get_tags()
  90         return data
  91 
  92     def get_webhook_urls(self, project):
  93         urls = self.get_option('urls', project)
  94         if not urls:
  95             return ()
  96         return filter(bool, urls.strip().splitlines())
  97 
  98     def send_webhook(self, url, payload):
  99         return safe_urlopen(
  100             url=url,
  101             json=payload,
  102             timeout=self.timeout,
  103             verify_ssl=False,
  104         )
  105 
  106     def notify_users(self, group, event, fail_silently=False):
  107         payload = self.get_group_data(group, event)
  108         for url in self.get_webhook_urls(group.project):
  109             safe_execute(self.send_webhook, url, payload, _with_transaction=False)
  110
  [end of src/sentry/plugins/sentry_webhooks/plugin.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/src/sentry/plugins/sentry_webhooks/plugin.py b/src/sentry/plugins/sentry_webhooks/plugin.py
  --- a/src/sentry/plugins/sentry_webhooks/plugin.py
  +++ b/src/sentry/plugins/sentry_webhooks/plugin.py
  @@ -87,6 +87,8 @@
           }
           data['event'] = dict(event.data or {})
           data['event']['tags'] = event.get_tags()
  +        data['event']['event_id'] = event.event_id
  +        data['event']['id'] = event.id
           return data
   
       def get_webhook_urls(self, project):
  
verification_info: {"golden_diff": "diff --git a/src/sentry/plugins/sentry_webhooks/plugin.py b/src/sentry/plugins/sentry_webhooks/plugin.py\n--- a/src/sentry/plugins/sentry_webhooks/plugin.py\n+++ b/src/sentry/plugins/sentry_webhooks/plugin.py\n@@ -87,6 +87,8 @@\n         }\n         data['event'] = dict(event.data or {})\n         data['event']['tags'] = event.get_tags()\n+        data['event']['event_id'] = event.event_id\n+        data['event']['id'] = event.id\n         return data\n \n     def get_webhook_urls(self, project):\n", "issue": "Webhook data does not have event id\nWebhook data contains issue id only. It would be nice to have event id as well.\r\n\r\nDiscussed with @mattrobenolt on IRC. Documenting it here with this issue.\n", "before_files": [{"content": "from __future__ import absolute_import\n\nimport logging\nimport six\nimport sentry\n\nfrom django import forms\nfrom django.conf import settings\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom sentry.exceptions import PluginError\nfrom sentry.plugins.bases import notify\nfrom sentry.http import is_valid_url, safe_urlopen\nfrom sentry.utils.safe import safe_execute\n\n\ndef validate_urls(value, **kwargs):\n    output = []\n    for url in value.split('\\n'):\n        url = url.strip()\n        if not url:\n            continue\n        if not url.startswith(('http://', 'https://')):\n            raise PluginError('Not a valid URL.')\n        if not is_valid_url(url):\n            raise PluginError('Not a valid URL.')\n        output.append(url)\n    return '\\n'.join(output)\n\n\nclass WebHooksOptionsForm(notify.NotificationConfigurationForm):\n    urls = forms.CharField(\n        label=_('Callback URLs'),\n        widget=forms.Textarea(attrs={\n            'class': 'span6', 'placeholder': 'https://sentry.io/callback/url'}),\n        help_text=_('Enter callback URLs to POST new events to (one per line).'))\n\n    def clean_url(self):\n        value = self.cleaned_data.get('url')\n        return validate_urls(value)\n\n\nclass WebHooksPlugin(notify.NotificationPlugin):\n    author = 'Sentry Team'\n    author_url = 'https://github.com/getsentry/sentry'\n    version = sentry.VERSION\n    description = \"Integrates web hooks.\"\n    resource_links = [\n        ('Bug Tracker', 'https://github.com/getsentry/sentry/issues'),\n        ('Source', 'https://github.com/getsentry/sentry'),\n    ]\n\n    slug = 'webhooks'\n    title = 'WebHooks'\n    conf_title = title\n    conf_key = 'webhooks'\n    # TODO(dcramer): remove when this is migrated to React\n    project_conf_form = WebHooksOptionsForm\n    timeout = getattr(settings, 'SENTRY_WEBHOOK_TIMEOUT', 3)\n    logger = logging.getLogger('sentry.plugins.webhooks')\n    user_agent = 'sentry-webhooks/%s' % version\n\n    def is_configured(self, project, **kwargs):\n        return bool(self.get_option('urls', project))\n\n    def get_config(self, project, **kwargs):\n        return [{\n            'name': 'urls',\n            'label': 'Callback URLs',\n            'type': 'textarea',\n            'help': 'Enter callback URLs to POST new events to (one per line).',\n            'placeholder': 'https://sentry.io/callback/url',\n            'validators': [validate_urls],\n            'required': False\n        }]\n\n    def get_group_data(self, group, event):\n        data = {\n            'id': six.text_type(group.id),\n            'project': group.project.slug,\n            'project_name': group.project.name,\n            'logger': event.get_tag('logger'),\n            'level': event.get_tag('level'),\n            'culprit': group.culprit,\n            'message': event.get_legacy_message(),\n            'url': group.get_absolute_url(),\n        }\n        data['event'] = dict(event.data or {})\n        data['event']['tags'] = event.get_tags()\n        return data\n\n    def get_webhook_urls(self, project):\n        urls = self.get_option('urls', project)\n        if not urls:\n            return ()\n        return filter(bool, urls.strip().splitlines())\n\n    def send_webhook(self, url, payload):\n        return safe_urlopen(\n            url=url,\n            json=payload,\n            timeout=self.timeout,\n            verify_ssl=False,\n        )\n\n    def notify_users(self, group, event, fail_silently=False):\n        payload = self.get_group_data(group, event)\n        for url in self.get_webhook_urls(group.project):\n            safe_execute(self.send_webhook, url, payload, _with_transaction=False)\n", "path": "src/sentry/plugins/sentry_webhooks/plugin.py"}]}