prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Error with AWX 7.0.0
  Hello.
  I'm testing integration between **AWX 7.0.0** (Ansible Tower) by sending notifications in **Zulip 2.0.4**.
  During testing, I encounter an error from Ansible :
  
  ![image](https://user-images.githubusercontent.com/2016950/66895321-c5baf980-eff2-11e9-8649-06e5f2433133.png)
  
  And I immediatly receive an email warning from Zulip with the following content :
  
  ```Logger root, from module zerver.middleware line 291:
  Error generated by Ansible (user42@zulip.******.**) on zulip.******.** deployment
  
  Traceback (most recent call last):
    File "/srv/zulip-venv-cache/ebe617662f96425113e5a75344bbe5a0593f634a/zulip-py3-venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
      response = wrapped_callback(request, *callback_args, **callback_kwargs)
    File "/srv/zulip-venv-cache/ebe617662f96425113e5a75344bbe5a0593f634a/zulip-py3-venv/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 58, in wrapped_view
      return view_func(*args, **kwargs)
    File "./zerver/lib/request.py", line 289, in _wrapped_view_func
      return view_func(request, *args, **kwargs)
    File "./zerver/decorator.py", line 375, in _wrapped_func_arguments
      raise err
    File "./zerver/decorator.py", line 361, in _wrapped_func_arguments
      return view_func(request, user_profile, *args, **kwargs)
    File "./zerver/lib/request.py", line 289, in _wrapped_view_func
      return view_func(request, *args, **kwargs)
    File "./zerver/webhooks/ansibletower/view.py", line 27, in api_ansibletower_webhook
      body = get_body(payload)
    File "./zerver/webhooks/ansibletower/view.py", line 34, in get_body
      if (payload['friendly_name'] == 'Job'):
  KeyError: 'friendly_name'
  
  
  Deployed code:
  - git: 2.0.0-2546-ga1fa0b011
  - ZULIP_VERSION: 2.0.4+git
  
  
  Request info:
  - path: /api/v1/external/ansibletower
  - POST: {}
  - REMOTE_ADDR: "['10.10.36.6']"
  - QUERY_STRING: "['api_key=******&topic=******&stream=******&topic=******"
  - SERVER_NAME: "['']"
  ```
  
  I have already disable the "Disable SSL checking" but it seems also that the new version of AWX (the 7.0.0) contains new options for webhook like "HTTP Headers" and "HTTP Method".
  
  ![image](https://user-images.githubusercontent.com/2016950/66895546-5db8e300-eff3-11e9-9954-8e1df5485e17.png)
  
  Note that I have already notifications from GitLab so the notification service works in my self-hosted Zulip configuration.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `zerver/webhooks/ansibletower/view.py`
  Content:
  ```
  1 import operator
  2 from typing import Any, Dict, List
  3 
  4 from django.http import HttpRequest, HttpResponse
  5 
  6 from zerver.decorator import REQ, api_key_only_webhook_view, \
  7     has_request_variables
  8 from zerver.lib.response import json_success
  9 from zerver.lib.webhooks.common import check_send_webhook_message
  10 from zerver.models import UserProfile
  11 
  12 ANSIBLETOWER_DEFAULT_MESSAGE_TEMPLATE = "{friendly_name}: [#{id} {name}]({url}) {status}."
  13 
  14 
  15 ANSIBLETOWER_JOB_MESSAGE_TEMPLATE = """
  16 {friendly_name}: [#{id} {name}]({url}) {status}:
  17 {hosts_final_data}
  18 """.strip()
  19 
  20 ANSIBLETOWER_JOB_HOST_ROW_TEMPLATE = '* {hostname}: {status}\n'
  21 
  22 @api_key_only_webhook_view('Ansibletower')
  23 @has_request_variables
  24 def api_ansibletower_webhook(request: HttpRequest, user_profile: UserProfile,
  25                              payload: Dict[str, Any]=REQ(argument_type='body')) -> HttpResponse:
  26 
  27     body = get_body(payload)
  28     subject = payload['name']
  29 
  30     check_send_webhook_message(request, user_profile, subject, body)
  31     return json_success()
  32 
  33 def get_body(payload: Dict[str, Any]) -> str:
  34     if (payload['friendly_name'] == 'Job'):
  35         hosts_list_data = payload['hosts']
  36         hosts_data = []
  37         for host in payload['hosts']:
  38             if (hosts_list_data[host].get('failed') is True):
  39                 hoststatus = 'Failed'
  40             elif (hosts_list_data[host].get('failed') is False):
  41                 hoststatus = 'Success'
  42             hosts_data.append({
  43                 'hostname': host,
  44                 'status': hoststatus
  45             })
  46 
  47         if (payload['status'] == "successful"):
  48             status = 'was successful'
  49         else:
  50             status = 'failed'
  51 
  52         return ANSIBLETOWER_JOB_MESSAGE_TEMPLATE.format(
  53             name=payload['name'],
  54             friendly_name=payload['friendly_name'],
  55             id=payload['id'],
  56             url=payload['url'],
  57             status=status,
  58             hosts_final_data=get_hosts_content(hosts_data)
  59         )
  60 
  61     else:
  62 
  63         if (payload['status'] == "successful"):
  64             status = 'was successful'
  65         else:
  66             status = 'failed'
  67 
  68         data = {
  69             "name": payload['name'],
  70             "friendly_name": payload['friendly_name'],
  71             "id": payload['id'],
  72             "url": payload['url'],
  73             "status": status
  74         }
  75 
  76         return ANSIBLETOWER_DEFAULT_MESSAGE_TEMPLATE.format(**data)
  77 
  78 def get_hosts_content(hosts_data: List[Dict[str, Any]]) -> str:
  79     hosts_data = sorted(hosts_data, key=operator.itemgetter('hostname'))
  80     hosts_content = ''
  81     for host in hosts_data:
  82         hosts_content += ANSIBLETOWER_JOB_HOST_ROW_TEMPLATE.format(
  83             hostname=host.get('hostname'),
  84             status=host.get('status')
  85         )
  86     return hosts_content
  87
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/zerver/webhooks/ansibletower/view.py b/zerver/webhooks/ansibletower/view.py
  --- a/zerver/webhooks/ansibletower/view.py
  +++ b/zerver/webhooks/ansibletower/view.py
  @@ -30,8 +30,19 @@
       check_send_webhook_message(request, user_profile, subject, body)
       return json_success()
   
  +def extract_friendly_name(payload: Dict[str, Any]) -> str:
  +    tentative_job_name = payload.get("friendly_name", "")
  +    if not tentative_job_name:
  +        url = payload["url"]
  +        segments = url.split("/")
  +        tentative_job_name = segments[-3]
  +        if tentative_job_name == "jobs":
  +            tentative_job_name = "Job"
  +    return tentative_job_name
  +
   def get_body(payload: Dict[str, Any]) -> str:
  -    if (payload['friendly_name'] == 'Job'):
  +    friendly_name = extract_friendly_name(payload)
  +    if (friendly_name == 'Job'):
           hosts_list_data = payload['hosts']
           hosts_data = []
           for host in payload['hosts']:
  @@ -51,7 +62,7 @@
   
           return ANSIBLETOWER_JOB_MESSAGE_TEMPLATE.format(
               name=payload['name'],
  -            friendly_name=payload['friendly_name'],
  +            friendly_name=friendly_name,
               id=payload['id'],
               url=payload['url'],
               status=status,
  @@ -67,7 +78,7 @@
   
           data = {
               "name": payload['name'],
  -            "friendly_name": payload['friendly_name'],
  +            "friendly_name": friendly_name,
               "id": payload['id'],
               "url": payload['url'],
               "status": status
  
verification_info: {"golden_diff": "diff --git a/zerver/webhooks/ansibletower/view.py b/zerver/webhooks/ansibletower/view.py\n--- a/zerver/webhooks/ansibletower/view.py\n+++ b/zerver/webhooks/ansibletower/view.py\n@@ -30,8 +30,19 @@\n     check_send_webhook_message(request, user_profile, subject, body)\n     return json_success()\n \n+def extract_friendly_name(payload: Dict[str, Any]) -> str:\n+    tentative_job_name = payload.get(\"friendly_name\", \"\")\n+    if not tentative_job_name:\n+        url = payload[\"url\"]\n+        segments = url.split(\"/\")\n+        tentative_job_name = segments[-3]\n+        if tentative_job_name == \"jobs\":\n+            tentative_job_name = \"Job\"\n+    return tentative_job_name\n+\n def get_body(payload: Dict[str, Any]) -> str:\n-    if (payload['friendly_name'] == 'Job'):\n+    friendly_name = extract_friendly_name(payload)\n+    if (friendly_name == 'Job'):\n         hosts_list_data = payload['hosts']\n         hosts_data = []\n         for host in payload['hosts']:\n@@ -51,7 +62,7 @@\n \n         return ANSIBLETOWER_JOB_MESSAGE_TEMPLATE.format(\n             name=payload['name'],\n-            friendly_name=payload['friendly_name'],\n+            friendly_name=friendly_name,\n             id=payload['id'],\n             url=payload['url'],\n             status=status,\n@@ -67,7 +78,7 @@\n \n         data = {\n             \"name\": payload['name'],\n-            \"friendly_name\": payload['friendly_name'],\n+            \"friendly_name\": friendly_name,\n             \"id\": payload['id'],\n             \"url\": payload['url'],\n             \"status\": status\n", "issue": "Error with AWX 7.0.0\nHello.\r\nI'm testing integration between **AWX 7.0.0** (Ansible Tower) by sending notifications in **Zulip 2.0.4**.\r\nDuring testing, I encounter an error from Ansible :\r\n\r\n![image](https://user-images.githubusercontent.com/2016950/66895321-c5baf980-eff2-11e9-8649-06e5f2433133.png)\r\n\r\nAnd I immediatly receive an email warning from Zulip with the following content :\r\n\r\n```Logger root, from module zerver.middleware line 291:\r\nError generated by Ansible (user42@zulip.******.**) on zulip.******.** deployment\r\n\r\nTraceback (most recent call last):\r\n  File \"/srv/zulip-venv-cache/ebe617662f96425113e5a75344bbe5a0593f634a/zulip-py3-venv/lib/python3.7/site-packages/django/core/handlers/base.py\", line 185, in _get_response\r\n    response = wrapped_callback(request, *callback_args, **callback_kwargs)\r\n  File \"/srv/zulip-venv-cache/ebe617662f96425113e5a75344bbe5a0593f634a/zulip-py3-venv/lib/python3.7/site-packages/django/views/decorators/csrf.py\", line 58, in wrapped_view\r\n    return view_func(*args, **kwargs)\r\n  File \"./zerver/lib/request.py\", line 289, in _wrapped_view_func\r\n    return view_func(request, *args, **kwargs)\r\n  File \"./zerver/decorator.py\", line 375, in _wrapped_func_arguments\r\n    raise err\r\n  File \"./zerver/decorator.py\", line 361, in _wrapped_func_arguments\r\n    return view_func(request, user_profile, *args, **kwargs)\r\n  File \"./zerver/lib/request.py\", line 289, in _wrapped_view_func\r\n    return view_func(request, *args, **kwargs)\r\n  File \"./zerver/webhooks/ansibletower/view.py\", line 27, in api_ansibletower_webhook\r\n    body = get_body(payload)\r\n  File \"./zerver/webhooks/ansibletower/view.py\", line 34, in get_body\r\n    if (payload['friendly_name'] == 'Job'):\r\nKeyError: 'friendly_name'\r\n\r\n\r\nDeployed code:\r\n- git: 2.0.0-2546-ga1fa0b011\r\n- ZULIP_VERSION: 2.0.4+git\r\n\r\n\r\nRequest info:\r\n- path: /api/v1/external/ansibletower\r\n- POST: {}\r\n- REMOTE_ADDR: \"['10.10.36.6']\"\r\n- QUERY_STRING: \"['api_key=******&topic=******&stream=******&topic=******\"\r\n- SERVER_NAME: \"['']\"\r\n```\r\n\r\nI have already disable the \"Disable SSL checking\" but it seems also that the new version of AWX (the 7.0.0) contains new options for webhook like \"HTTP Headers\" and \"HTTP Method\".\r\n\r\n![image](https://user-images.githubusercontent.com/2016950/66895546-5db8e300-eff3-11e9-9954-8e1df5485e17.png)\r\n\r\nNote that I have already notifications from GitLab so the notification service works in my self-hosted Zulip configuration.\n", "before_files": [{"content": "import operator\nfrom typing import Any, Dict, List\n\nfrom django.http import HttpRequest, HttpResponse\n\nfrom zerver.decorator import REQ, api_key_only_webhook_view, \\\n    has_request_variables\nfrom zerver.lib.response import json_success\nfrom zerver.lib.webhooks.common import check_send_webhook_message\nfrom zerver.models import UserProfile\n\nANSIBLETOWER_DEFAULT_MESSAGE_TEMPLATE = \"{friendly_name}: [#{id} {name}]({url}) {status}.\"\n\n\nANSIBLETOWER_JOB_MESSAGE_TEMPLATE = \"\"\"\n{friendly_name}: [#{id} {name}]({url}) {status}:\n{hosts_final_data}\n\"\"\".strip()\n\nANSIBLETOWER_JOB_HOST_ROW_TEMPLATE = '* {hostname}: {status}\\n'\n\n@api_key_only_webhook_view('Ansibletower')\n@has_request_variables\ndef api_ansibletower_webhook(request: HttpRequest, user_profile: UserProfile,\n                             payload: Dict[str, Any]=REQ(argument_type='body')) -> HttpResponse:\n\n    body = get_body(payload)\n    subject = payload['name']\n\n    check_send_webhook_message(request, user_profile, subject, body)\n    return json_success()\n\ndef get_body(payload: Dict[str, Any]) -> str:\n    if (payload['friendly_name'] == 'Job'):\n        hosts_list_data = payload['hosts']\n        hosts_data = []\n        for host in payload['hosts']:\n            if (hosts_list_data[host].get('failed') is True):\n                hoststatus = 'Failed'\n            elif (hosts_list_data[host].get('failed') is False):\n                hoststatus = 'Success'\n            hosts_data.append({\n                'hostname': host,\n                'status': hoststatus\n            })\n\n        if (payload['status'] == \"successful\"):\n            status = 'was successful'\n        else:\n            status = 'failed'\n\n        return ANSIBLETOWER_JOB_MESSAGE_TEMPLATE.format(\n            name=payload['name'],\n            friendly_name=payload['friendly_name'],\n            id=payload['id'],\n            url=payload['url'],\n            status=status,\n            hosts_final_data=get_hosts_content(hosts_data)\n        )\n\n    else:\n\n        if (payload['status'] == \"successful\"):\n            status = 'was successful'\n        else:\n            status = 'failed'\n\n        data = {\n            \"name\": payload['name'],\n            \"friendly_name\": payload['friendly_name'],\n            \"id\": payload['id'],\n            \"url\": payload['url'],\n            \"status\": status\n        }\n\n        return ANSIBLETOWER_DEFAULT_MESSAGE_TEMPLATE.format(**data)\n\ndef get_hosts_content(hosts_data: List[Dict[str, Any]]) -> str:\n    hosts_data = sorted(hosts_data, key=operator.itemgetter('hostname'))\n    hosts_content = ''\n    for host in hosts_data:\n        hosts_content += ANSIBLETOWER_JOB_HOST_ROW_TEMPLATE.format(\n            hostname=host.get('hostname'),\n            status=host.get('status')\n        )\n    return hosts_content\n", "path": "zerver/webhooks/ansibletower/view.py"}], "after_files": [{"content": "import operator\nfrom typing import Any, Dict, List\n\nfrom django.http import HttpRequest, HttpResponse\n\nfrom zerver.decorator import REQ, api_key_only_webhook_view, \\\n    has_request_variables\nfrom zerver.lib.response import json_success\nfrom zerver.lib.webhooks.common import check_send_webhook_message\nfrom zerver.models import UserProfile\n\nANSIBLETOWER_DEFAULT_MESSAGE_TEMPLATE = \"{friendly_name}: [#{id} {name}]({url}) {status}.\"\n\n\nANSIBLETOWER_JOB_MESSAGE_TEMPLATE = \"\"\"\n{friendly_name}: [#{id} {name}]({url}) {status}:\n{hosts_final_data}\n\"\"\".strip()\n\nANSIBLETOWER_JOB_HOST_ROW_TEMPLATE = '* {hostname}: {status}\\n'\n\n@api_key_only_webhook_view('Ansibletower')\n@has_request_variables\ndef api_ansibletower_webhook(request: HttpRequest, user_profile: UserProfile,\n                             payload: Dict[str, Any]=REQ(argument_type='body')) -> HttpResponse:\n\n    body = get_body(payload)\n    subject = payload['name']\n\n    check_send_webhook_message(request, user_profile, subject, body)\n    return json_success()\n\ndef extract_friendly_name(payload: Dict[str, Any]) -> str:\n    tentative_job_name = payload.get(\"friendly_name\", \"\")\n    if not tentative_job_name:\n        url = payload[\"url\"]\n        segments = url.split(\"/\")\n        tentative_job_name = segments[-3]\n        if tentative_job_name == \"jobs\":\n            tentative_job_name = \"Job\"\n    return tentative_job_name\n\ndef get_body(payload: Dict[str, Any]) -> str:\n    friendly_name = extract_friendly_name(payload)\n    if (friendly_name == 'Job'):\n        hosts_list_data = payload['hosts']\n        hosts_data = []\n        for host in payload['hosts']:\n            if (hosts_list_data[host].get('failed') is True):\n                hoststatus = 'Failed'\n            elif (hosts_list_data[host].get('failed') is False):\n                hoststatus = 'Success'\n            hosts_data.append({\n                'hostname': host,\n                'status': hoststatus\n            })\n\n        if (payload['status'] == \"successful\"):\n            status = 'was successful'\n        else:\n            status = 'failed'\n\n        return ANSIBLETOWER_JOB_MESSAGE_TEMPLATE.format(\n            name=payload['name'],\n            friendly_name=friendly_name,\n            id=payload['id'],\n            url=payload['url'],\n            status=status,\n            hosts_final_data=get_hosts_content(hosts_data)\n        )\n\n    else:\n\n        if (payload['status'] == \"successful\"):\n            status = 'was successful'\n        else:\n            status = 'failed'\n\n        data = {\n            \"name\": payload['name'],\n            \"friendly_name\": friendly_name,\n            \"id\": payload['id'],\n            \"url\": payload['url'],\n            \"status\": status\n        }\n\n        return ANSIBLETOWER_DEFAULT_MESSAGE_TEMPLATE.format(**data)\n\ndef get_hosts_content(hosts_data: List[Dict[str, Any]]) -> str:\n    hosts_data = sorted(hosts_data, key=operator.itemgetter('hostname'))\n    hosts_content = ''\n    for host in hosts_data:\n        hosts_content += ANSIBLETOWER_JOB_HOST_ROW_TEMPLATE.format(\n            hostname=host.get('hostname'),\n            status=host.get('status')\n        )\n    return hosts_content\n", "path": "zerver/webhooks/ansibletower/view.py"}]}