webhooks: Remove the Facebook integration.

Rishi and I decided that it makes sense to get rid of the Facebook
integration for a few reasons, some of which are:

* The setup process is too complicated on Facebook's end. The users
  will surely have to browse Facebook's huge API reference before even
  having a vague idea of what they want.
* Slack chooses not to have a Facebook integration, but relies on
  Zapier for it. Zaps that integrate with Facebook are much more
  streamlined and the setup process isn't as much of a pain. Zapier's
  Facebook Zaps are much more fine-tuned and there are different Zaps
  for different parts of the FB API, a luxury that would likely span
  2K+ lines of code on our end if we were to implement it from
  scratch. So, I think we should relegate integration with Facebook to
  Zapier as well!
* After thoroughly testing the setup process, we concluded that the
  person who submitted the FB integration didn't really test it
  thoroughly because there were some gaping holes in the docs (missing
  steps, user permissions, etc.).
This commit is contained in:
Eeshan Garg 2018-02-19 20:58:10 -03:30 committed by Rishi Gupta
parent 5ddf2614f0
commit 3e0eb9530c
22 changed files with 0 additions and 464 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 B

View File

@ -373,7 +373,6 @@ WEBHOOK_INTEGRATIONS = [
WebhookIntegration('zendesk', ['customer-support']), WebhookIntegration('zendesk', ['customer-support']),
WebhookIntegration('gci', ['misc'], display_name='Google Code-in', WebhookIntegration('gci', ['misc'], display_name='Google Code-in',
stream_name='gci'), stream_name='gci'),
WebhookIntegration('facebook', ['communication'], display_name='Facebook')
] # type: List[WebhookIntegration] ] # type: List[WebhookIntegration]
INTEGRATIONS = { INTEGRATIONS = {

View File

@ -1,75 +0,0 @@
{!create-stream.md!}
Next, on your {{ settings_html|safe }},
[create a bot](/help/add-a-bot-or-integration) for
{{ integration_display_name }}. Make sure that you select
**Incoming webhook** as the **Bot type**:
![](/static/images/help/bot_types.png)
The API key for an incoming webhook bot cannot be used to read messages out
of Zulip. Thus, using an incoming webhook bot lowers the security risk of
exposing the bot's API key to a third-party service.
Construct the URL for the {{ integration_display_name }}
bot using the bot's API key and the desired stream name:
`{{ api_url }}{{ integration_url }}?api_key=abcdefgh&stream={{ recommended_stream_name }}&token=sampletoken`
Modify the parameters of the URL above, where `api_key` is the API key
of your Zulip bot, and `stream` is the stream name you want the
notifications sent to.
`token` is an arbitrary string of your choosing that can be used to confirm to your
server that the request is valid. This string will be included in Facebook's
incoming payloads each time they send your server a verification request.
{!append-stream-name.md!}
### Configuring the webhook
Sign In to the following URL: <https://developers.facebook.com/apps/>
Next, click on **+ Add a New App** button.
![](/static/images/integrations/facebook/001.png)
Then, fill in the following form to create a new Facebook app:
![](/static/images/integrations/facebook/002.png)
Next, under **Webhooks**, click on **Set up**:
![](/static/images/integrations/facebook/003.png)
Choose a category for the webhook:
![](/static/images/integrations/facebook/004.png)
This guide explains how to subscribe to a "feed" in the **User** category.
Select the **User** category, and click on **Subscribe to this topic**.
Fill in the **Edit User Subscription** form as follows:
1. **Callback URL**: enter the webhook URL created above.
2. **Verify Token**: enter the token you chose above. For instance, in this example you may enter **sampletoken**
3. Activate the **Include Values** option.
4. Click on **Verify and Save**.
The resulting form would look like:
![](/static/images/integrations/facebook/005.png)
Finally, click **Subscribe** and **Test** in the **feed** row, like so:
![](/static/images/integrations/facebook/006.png)
Click on **Send to My Server** and a test message will be sent to your Zulip server.
![](/static/images/integrations/facebook/007.png)
{!congrats.md!}
![](/static/images/integrations/facebook/008.png)
**This integration is not created by, affiliated with, or supported by Facebook, Inc.**

View File

@ -1,23 +0,0 @@
{
"entry":[
{
"changes":[
{
"field":"plugin_comment",
"value":{
"created_time":"2018-01-02T16:53:38+0000",
"message":"Test Comment",
"from":{
"name":"Test User",
"id":"4444444444"
},
"id":"4444444444_4444444444"
}
}
],
"id":"0",
"time":1514912018
}
],
"object":"application"
}

View File

@ -1,32 +0,0 @@
{
"entry":[
{
"changes":[
{
"field":"plugin_comment_reply",
"value":{
"created_time":"2018-01-03T10:45:42+0000",
"message":"Test Comment",
"from":{
"name":"Test User",
"id":"4444444444"
},
"id":"4444444444_4444444444",
"parent":{
"created_time":"2017-12-22T20:59:02+0000",
"message":"Test Parent Comment",
"from":{
"name":"Test User 1",
"id":"4444444444"
},
"id":"4444444444_44444444"
}
}
}
],
"id":"0",
"time":1514976343
}
],
"object":"application"
}

View File

@ -1,18 +0,0 @@
{
"entry":[
{
"changes":[
{
"field":"conversations",
"value":{
"thread_id":"t_mid.14833205540:9182a4e489",
"page_id":4444444
}
}
],
"id":"0",
"time":1514911876
}
],
"object":"page"
}

View File

@ -1,14 +0,0 @@
{
"entry":[
{
"changes":[
{
"field":"website"
}
],
"id":"0",
"time":1514911950
}
],
"object":"page"
}

View File

@ -1,22 +0,0 @@
{
"entry": [
{
"changes": [
{
"field": "ads_management",
"value": {
"target_ids": [
"123123123123123",
"321321321321321"
],
"verb": "granted"
}
}
],
"id": "0",
"time": 1515252883,
"uid": "0"
}
],
"object": "permissions"
}

View File

@ -1,22 +0,0 @@
{
"entry": [
{
"changes": [
{
"field": "manage_pages",
"value": {
"target_ids": [
"123123123123123",
"321321321321321"
],
"verb": "granted"
}
}
],
"id": "0",
"time": 1515254831,
"uid": "0"
}
],
"object": "permissions"
}

View File

@ -1,16 +0,0 @@
{
"entry":[
{
"time":1514911552,
"changes":[
{
"field":"email",
"value":"example_email@facebook.com"
}
],
"id":"0",
"uid":"0"
}
],
"object":"user"
}

View File

@ -1,15 +0,0 @@
{
"entry":[
{
"time":1514911601,
"changes":[
{
"field":"feed"
}
],
"id":"0",
"uid":"0"
}
],
"object":"user"
}

View File

@ -1,110 +0,0 @@
from typing import Optional, Text
from zerver.lib.test_classes import WebhookTestCase
class FacebookTests(WebhookTestCase):
STREAM_NAME = 'Facebook'
URL_TEMPLATE = "/api/v1/external/facebook?api_key={api_key}&stream={stream}&token=aaaa"
FIXTURE_DIR_NAME = 'facebook'
def test_application_plugin_comment(self) -> None:
expected_subject = u'application notification'
expected_message = u'**plugin_comment** received'\
u'\n**Test User:**'\
u'\n```quote'\
u'\nTest Comment'\
u'\n```'
self.send_and_test_stream_message('application_plugin_comment',
expected_subject, expected_message)
def test_application_plugin_comment_reply(self) -> None:
expected_subject = u'application notification'
expected_message = u'**plugin_comment_reply** received'\
u'\n**Test User 1:** (Parent)'\
u'\n```quote'\
u'\nTest Parent Comment'\
u'\n```'\
u'\n**Test User:**'\
u'\n```quote'\
u'\n```quote'\
u'\nTest Comment'\
u'\n```'\
u'\n```'
self.send_and_test_stream_message('application_plugin_comment_reply',
expected_subject, expected_message)
def test_page_conversations(self) -> None:
expected_subject = u'page notification'
expected_message = u'Updated **conversations**'\
u'\n[Open conversations...](https://www.facebook.com/'\
u'4444444/t_mid.14833205540:9182a4e489)'
self.send_and_test_stream_message('page_conversations',
expected_subject, expected_message)
def test_page_website_test(self) -> None:
expected_subject = u'page notification'
expected_message = u'Changed **website**'
self.send_and_test_stream_message('page_website',
expected_subject, expected_message)
def test_permissions_ads_management(self) -> None:
expected_subject = u'permissions notification'
expected_message = u'**ads_management permission** changed'\
u'\n* granted'\
u'\n * 123123123123123'\
u'\n * 321321321321321'
self.send_and_test_stream_message('permissions_ads_management',
expected_subject, expected_message)
def test_permissions_manage_pages(self) -> None:
expected_subject = u'permissions notification'
expected_message = u'**manage_pages permission** changed'\
u'\n* granted'\
u'\n * 123123123123123'\
u'\n * 321321321321321'
self.send_and_test_stream_message('permissions_manage_pages',
expected_subject, expected_message)
def test_user_email(self) -> None:
expected_subject = u'user notification'
expected_message = u'Changed **email**'\
u'\nTo: *example_email@facebook.com*'
self.send_and_test_stream_message('user_email',
expected_subject, expected_message)
def test_user_feed(self) -> None:
expected_subject = u'user notification'
expected_message = u'Changed **feed**'
self.send_and_test_stream_message('user_feed',
expected_subject, expected_message)
def test_webhook_verify_request(self) -> None:
self.subscribe(self.test_user, self.STREAM_NAME)
get_params = {'stream_name': self.STREAM_NAME,
'hub.challenge': '9B2SVL4orbt5DxLMqJHI6pOTipTqingt2YFMIO0g06E',
'api_key': self.test_user.api_key,
'hub.mode': 'subscribe',
'hub.verify_token': 'aaaa',
'token': 'aaaa'}
result = self.client_get(self.url, get_params)
self.assert_in_response('9B2SVL4orbt5DxLMqJHI6pOTipTqingt2YFMIO0g06E', result)
def test_error_webhook_verify_request_wrong_token(self) -> None:
self.subscribe(self.test_user, self.STREAM_NAME)
get_params = {'stream_name': self.STREAM_NAME,
'hub.challenge': '9B2SVL4orbt5DxLMqJHI6pOTipTqingt2YFMIO0g06E',
'api_key': self.test_user.api_key,
'hub.mode': 'subscribe',
'hub.verify_token': 'aaaa',
'token': 'wrong_token'}
result = self.client_get(self.url, get_params)
self.assert_in_response('Error: Token is wrong', result)
def test_error_webhook_verify_request_unsupported_method(self) -> None:
self.subscribe(self.test_user, self.STREAM_NAME)
get_params = {'stream_name': self.STREAM_NAME,
'api_key': self.test_user.api_key,
'hub.mode': 'unsupported_method',
'token': 'aaaa'}
result = self.client_get(self.url, get_params)
self.assert_in_response('Error: Unsupported method', result)

View File

@ -1,116 +0,0 @@
from typing import Any, Dict, Optional, Text
from django.http import HttpRequest, HttpResponse, QueryDict
from django.utils.translation import ugettext as _
from zerver.decorator import api_key_only_webhook_view
from zerver.lib.actions import check_send_stream_message, create_stream_if_needed
from zerver.lib.request import REQ, has_request_variables
from zerver.lib.response import json_success, json_error
from zerver.models import UserProfile
import json
class UnknownEventType(Exception):
pass
def user_event(payload: Dict[Text, Any]) -> Text:
field = payload['entry'][0]['changes'][0]['field']
message = "Changed **{field}**".format(field=field)
if field == "email":
if payload['entry'][0]['changes'][0]['value'] is not None:
message = message + '\nTo: *{email}*'.format(
email=payload['entry'][0]['changes'][0]['value']
)
return message
def page_event(payload: Dict[Text, Any]) -> Text:
field = payload['entry'][0]['changes'][0]['field']
message = ''
if field == 'conversations':
message = message + 'Updated **conversations**'
message = message + '\n[Open conversations...](https://www.facebook.com/'\
'{page_id}/{thread_id})'.format(
page_id=payload['entry'][0]['changes'][0]['value']['page_id'],
thread_id=payload['entry'][0]['changes'][0]['value']['thread_id']
)
elif field == 'website':
message = message + 'Changed **website**'
return message
def permissions_event(payload: Dict[Text, Any]) -> Text:
field = payload['entry'][0]['changes'][0]['field']
message = '**{field} permission** changed'.format(field=field)
if field == 'ads_management':
message = message + '\n* {verb}'.format(
verb=payload['entry'][0]['changes'][0]['value']['verb']
)
for id in payload['entry'][0]['changes'][0]['value']['target_ids']:
message = message + '\n * {id}'.format(id=id)
elif field == 'manage_pages':
message = message + '\n* {verb}'.format(
verb=payload['entry'][0]['changes'][0]['value']['verb']
)
for id in payload['entry'][0]['changes'][0]['value']['target_ids']:
message = message + '\n * {id}'.format(id=id)
return message
def application_event(payload: Dict[Text, Any]) -> Text:
field = payload['entry'][0]['changes'][0]['field']
message = '**{field}** received'.format(field=field)
if field == 'plugin_comment':
message = message + '\n**{msg_user}:**\n```quote\n{message}\n```'.format(
msg_user=payload['entry'][0]['changes'][0]['value']['from']['name'],
message=payload['entry'][0]['changes'][0]['value']['message']
)
if field == 'plugin_comment_reply':
message = message + '\n**{prt_msg_user}:** (Parent)\n'\
'```quote\n{prt_message}\n```'.format(
prt_msg_user=payload['entry'][0]['changes'][0]['value']['parent']['from']['name'],
prt_message=payload['entry'][0]['changes'][0]['value']['parent']['message']
)
message = message + '\n**{cld_msg_user}:**\n```quote\n'\
'```quote\n{cld_message}\n```\n```'.format(
cld_msg_user=payload['entry'][0]['changes'][0]['value']['from']['name'],
cld_message=payload['entry'][0]['changes'][0]['value']['message']
)
return message
@api_key_only_webhook_view("Facebook")
@has_request_variables
def api_facebook_webhook(request: HttpRequest, user_profile: UserProfile,
stream: Text=REQ(default='Facebook'), token: Text=REQ()) -> HttpResponse:
if request.method == 'GET': # facebook webhook verify
if request.GET.get("hub.mode") == 'subscribe':
if request.GET.get('hub.verify_token') == token:
return HttpResponse(request.GET.get('hub.challenge'))
else:
return json_error(_('Error: Token is wrong'))
return json_error(_('Error: Unsupported method'))
payload = json.loads(request.body.decode("UTF-8"))
event = get_event(payload)
if event is not None:
body = get_body_based_on_event(event)(payload)
subject = event + " notification"
check_send_stream_message(user_profile, request.client,
stream, subject, body)
return json_success()
# This integration doesn't support instant_workflow, instagram
# and certificate_transparency event.
EVENTS_FUNCTION_MAPPER = {
'user': user_event,
'page': page_event,
'permissions': permissions_event,
'application': application_event
}
def get_event(payload: Dict[Text, Any]) -> Optional[Text]:
event = payload['object']
if event in EVENTS_FUNCTION_MAPPER:
return event
raise UnknownEventType(u"OEvent '{}' is unknown and cannot be handled".format(event)) # nocoverage
def get_body_based_on_event(event: Text) -> Any:
return EVENTS_FUNCTION_MAPPER[event]