Skip to content

Commit

Permalink
Add check credentials view for Facebook and Instagram channels
Browse files Browse the repository at this point in the history
  • Loading branch information
norkans7 committed Nov 26, 2024
1 parent 499274e commit ace1e1a
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 18 deletions.
32 changes: 28 additions & 4 deletions temba/channels/types/facebookapp/type.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.urls import re_path
import requests

from django.conf import settings
Expand All @@ -7,7 +8,7 @@
from temba.triggers.models import Trigger

from ...models import Channel, ChannelType
from .views import ClaimView
from .views import ClaimView, CheckCredentials


class FacebookAppType(ChannelType):
Expand All @@ -32,9 +33,17 @@ class FacebookAppType(ChannelType):
) % {"link": '<a target="_blank" href="http://facebook.com">Facebook</a>'}
claim_view = ClaimView

menu_items = [
dict(label=_("Reconnect Facebook Page"), view_name="channels.types.facebookapp.claim", obj_view=False)
]
menu_items = [dict(label=_("Check Credentials"), view_name="channels.types.facebookapp.check_credentials")]

def get_urls(self):
return [
self.get_claim_url(),
re_path(
r"^(?P<uuid>[a-z0-9\-]+)/check_credentials/$",
CheckCredentials.as_view(channel_type=self),
name="check_credentials",
),
]

def deactivate(self, channel):
config = channel.config
Expand Down Expand Up @@ -81,3 +90,18 @@ def get_redact_values(self, channel) -> tuple: # pragma: needs cover

def get_error_ref_url(self, channel, code: str) -> str:
return "https://developers.facebook.com/docs/messenger-platform/error-codes"

def check_credentials(self, config: dict) -> bool:
return False
app_id = settings.FACEBOOK_APPLICATION_ID
app_secret = settings.FACEBOOK_APPLICATION_SECRET
url = "https://graph.facebook.com/v18.0/debug_token"
params = {
"access_token": f"{app_id}|{app_secret}",
"input_token": config[Channel.CONFIG_AUTH_TOKEN],
}
resp = requests.get(url, params=params)

if resp.status_code == 200:
return resp.json().get("data", dict()).get("is_valid", False)
return False
22 changes: 21 additions & 1 deletion temba/channels/types/facebookapp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
from django.urls import reverse
from django.utils.translation import gettext_lazy as _

from temba.orgs.views.base import BaseReadView
from temba.utils.text import truncate

from ...models import Channel
from ...views import ClaimViewMixin
from ...views import ClaimViewMixin, ChannelTypeMixin


class ClaimView(ClaimViewMixin, SmartFormView):
Expand Down Expand Up @@ -141,3 +142,22 @@ def form_valid(self, form):
)

return super().form_valid(form)


class CheckCredentials(ChannelTypeMixin, BaseReadView):
slug_url_kwarg = "uuid"
permission = "channels.channel_claim"
fields = ()
template_name = "channels/types/facebookapp/check_credentials.html"

def derive_menu_path(self):
return f"/settings/channels/{self.get_object().uuid}"

def get_queryset(self):
return self.request.org.channels.filter(is_active=True, channel_type=self.channel_type.code)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["update_token_url"] = reverse("channels.types.facebookapp.claim")
context["valid_token"] = self.object.type.check_credentials(self.object.config)
return context
32 changes: 28 additions & 4 deletions temba/channels/types/instagram/type.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.urls import re_path
import requests

from django.conf import settings
Expand All @@ -6,7 +7,7 @@
from temba.contacts.models import URN

from ...models import Channel, ChannelType
from .views import ClaimView
from .views import CheckCredentials, ClaimView


class InstagramType(ChannelType):
Expand All @@ -29,9 +30,17 @@ class InstagramType(ChannelType):
}
claim_view = ClaimView

menu_items = [
dict(label=_("Reconnect Business Account"), view_name="channels.types.instagram.claim", obj_view=False)
]
menu_items = [dict(label=_("Reconnect Business Account"), view_name="channels.types.instagram.check_credentials")]

def get_urls(self):
return [
self.get_claim_url(),
re_path(
r"^(?P<uuid>[a-z0-9\-]+)/check_credentials/$",
CheckCredentials.as_view(channel_type=self),
name="check_credentials",
),
]

def deactivate(self, channel):
config = channel.config
Expand All @@ -48,3 +57,18 @@ def get_redact_values(self, channel) -> tuple: # pragma: needs cover

def get_error_ref_url(self, channel, code: str) -> str:
return "https://developers.facebook.com/docs/instagram-api/reference/error-codes"

def check_credentials(self, config: dict) -> bool:
return True
app_id = settings.FACEBOOK_APPLICATION_ID
app_secret = settings.FACEBOOK_APPLICATION_SECRET
url = "https://graph.facebook.com/v18.0/debug_token"
params = {
"access_token": f"{app_id}|{app_secret}",
"input_token": config[Channel.CONFIG_AUTH_TOKEN],
}
resp = requests.get(url, params=params)

if resp.status_code == 200:
return resp.json().get("data", dict()).get("is_valid", False)
return False
24 changes: 22 additions & 2 deletions temba/channels/types/instagram/views.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import logging

import requests
from smartmin.views import SmartFormView
from smartmin.views import SmartFormView, SmartReadView

from django import forms
from django.conf import settings
from django.urls import reverse
from django.utils.translation import gettext_lazy as _

from temba.orgs.views.mixins import OrgObjPermsMixin
from temba.utils.text import truncate

from ...models import Channel
from ...views import ClaimViewMixin
from ...views import ClaimViewMixin, ChannelTypeMixin

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -172,3 +173,22 @@ def form_valid(self, form):
)

return super().form_valid(form)


class CheckCredentials(ChannelTypeMixin, OrgObjPermsMixin, SmartReadView):
slug_url_kwarg = "uuid"
permission = "channels.channel_claim"
fields = ()
template_name = "channels/types/instagram/check_credentials.html"

def derive_menu_path(self):
return f"/settings/channels/{self.get_object().uuid}"

def get_queryset(self):
return self.request.org.channels.filter(is_active=True, channel_type=self.channel_type.code)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["update_token_url"] = reverse("channels.types.instagram.claim")
context["valid_token"] = self.object.type.check_credentials(self.object.config)
return context
4 changes: 1 addition & 3 deletions temba/channels/types/whatsapp/type.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ class WhatsAppType(ChannelType):
claim_blurb = _("If you have an enterprise WhatsApp account, you can connect it to communicate with your contacts")
claim_view = ClaimView

menu_items = [
dict(label=_("Verify Number"), view_name="channels.types.whatsapp.request_code", obj_view=True),
]
menu_items = [dict(label=_("Verify Number"), view_name="channels.types.whatsapp.request_code")]

def get_urls(self):
return [
Expand Down
5 changes: 1 addition & 4 deletions temba/channels/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,10 +489,7 @@ def build_context_menu(self, menu):
obj = self.get_object()

for item in obj.type.menu_items:
menu.add_link(
item["label"],
reverse(item["view_name"], args=[obj.uuid]) if item["obj_view"] else reverse(item["view_name"]),
)
menu.add_link(item["label"], reverse(item["view_name"], args=[obj.uuid]))

if obj.type.config_ui:
menu.add_link(_("Configuration"), reverse("channels.channel_configuration", args=[obj.uuid]))
Expand Down
18 changes: 18 additions & 0 deletions templates/channels/types/facebookapp/check_credentials.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{% extends "smartmin/read.html" %}
{% load smartmin temba humanize channels i18n tz %}

{% block content %}
<div class="mt-4 card">
<p id="fb-status">
{% if not valid_token %}
{% trans "Error with token, you need to reconnect the Facebook page by clicking the button below" %}
{% else %}
{% trans "Everything looks good. No need to reconnect" %}
{% endif %}
</p>
<div class="mt-4">
<div onclick="javascript:history.go(-1)" class="button-light">{% trans "Go Back" %}</div>
<a class="button-primary mt-4 ml-2" href="{{ update_token_url }}">{% trans "Reconnect Facebook page" %}</a>
</div>
</div>
{% endblock content %}
18 changes: 18 additions & 0 deletions templates/channels/types/instagram/check_credentials.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{% extends "smartmin/read.html" %}
{% load smartmin temba humanize channels i18n tz %}

{% block content %}
<div class="mt-4 card">
<p id="fb-status">
{% if not valid_token %}
{% trans "Error with token, you need to reconnect the Instagram Business Account by clicking the button below" %}
{% else %}
{% trans "Everything looks good. No need to reconnect" %}
{% endif %}
</p>
<div class="mt-4">
<div onclick="javascript:history.go(-1)" class="button-light">{% trans "Go Back" %}</div>
<a class="button-primary mt-4 ml-2" href="{{ update_token_url }}">{% trans "Reconnect Instagram Business Account" %}</a>
</div>
</div>
{% endblock content %}

0 comments on commit ace1e1a

Please sign in to comment.