Facebook w aplikacjach Django dzięki małym pozytywnym modułom

Tworzenie aplikacji facebookowych, czy integrowanie serwisów internetowych z Facebookiem nie jest tematem nowym, ani specjalnie trudnym. W przypadku Django powszechnie znany jest duży pakiet django-facebook. Od paru dni dostępne są także na Githubie małe aplikacje używane do tej pory wewnętrznie w Pozytywnie.pl. W tym artykule przedstawię ich możliwości.

Repozytoria znajdują się na githubie. Część aplikacji nie jest jeszcze dostępna na pypi - trzeba je instalować z repozytorium. Przykładowy projekt wykorzystujący te aplikacje dostępny jest w moim repozytorium django-examples - fragmenty będą w tym artykule.

Przykładowy projekt

Gotowy projekt Django można pobrać z repozytorium. W requirements.txt są wszystkie zależności, a w bazie sqlite przykładowe dane dla social-metadata. W settingsach należy podać ID i sekret aplikacji Facebookowej (co i jak podam poniżej). Adres kanwy jaki trzeba podać w aplikacji facebookowej to https://localhost:8000/canvas/. Na potrzeby social-metadata wystarczy odpalić aplikację za pomocą runserver, a dla /canvas/ za pomocą runsslserver (gdy chcesz otworzyć aplikację w facebookowej ramce/kanwie).

Projekt wykorzystuje wszystkie zaprezentowane tu aplikacje (za wyjątkiem notyfikacji). Celery jest przerzucone na Django żeby nie wymagać rabbit-mq. Debugowanie tokenów będzie działać jeżeli włączysz celery (manage.py celery worker) - choć nie jest to potrzebne do działania przykładowego widoku.

django-social-metadata

django-social-metadata to miksin z szablonem pozwalającym dodać do widoków (DetailView) zestaw tagów społecznościowych Facebooka i Google+ (og:image, tytuł, opis, link itd.). Dzięki tym tagom można wpływać na wygląd linków opublikowanych na tych serwisach.

Importujemy miksin, dodajemy go do wybranego DetailView i ustawiamy pożądane dane pod atrybutami używanymi przez mixin, albo przeciążamy metody:

import social_metadata.views


class PostView(social_metadata.views.SocialDataMixin, generic.DetailView):
    model = models.Post

    def get_social_title(self):
        return self.object.title

    def get_social_images(self):
        yield self.object.cover_image.url

    def get_social_description(self):
        return truncatewords(striptags(self.object.text), 50)


post_view = PostView.as_view()

Należy podać pełne adresy URL do zdjęć (jeżeli MEDIA_URL jest linkiem a nie ścieżką to wystarczy to dla obiektów z ImageField). Potrzebny jest też adres URL samego obiektu. Domyślnie wołana jest metoda get_absolute_url modelu więc trzeba zadbać żeby zwracała nie ścieżkę z reverse, a pełen URL (używając domenę z modelu Site, czy innym sposobem).

W szablonie widoku do sekcji HEAD należy wstawić szablon social_metadata/default_tags.html, np (zakładając istnienie bloku extrahead):

{% block extrahead %}
    {% include "social_metadata/default_tags.html" %}
{% endblock %}
W efekcie w sekcji HEAD pojawią się wspomniane tagi, np:
<meta property="og:title" content="Lorem ipsum dolor sit amet2"/> 
<meta itemprop="name" content="Lorem ipsum dolor sit amet2"> 

<meta property="og:description" content="Lorem ipsum dolor sit amet,..."/> 
<meta itemprop="description" content="Lorem ipsum dolor sit amet, Lorem..."> 

<meta property="og:image" content="http://localhost:8000/media/covers/eesp8266.jpg"/> 
<meta itemprop="image" content="http://localhost:8000/media/covers/eesp8266.jpg">  

<meta property="og:url" content="http://localhost:8000/post/2/"/>

Mając gotowe tagi społecznościowe na stronie można jest sprawdzić za pomocą debugera Facebooka. Wklejając link do strony z takimi tagami powinniśmy zobaczyć jak Facebook wykorzystuje podane tam informacje (szczególnie zdjęcie - o ile nie będzie za małe).

facebook-auth i facebook-javascript-authentication

django-facebook-auth to backendowy moduł obsługujący autoryzację użytkowników Facebookowych - zawiera model FacebookUser oraz odpowiednie AUTH_BACKENDy. Jest wykorzystywane przez pozostałe pozytywne aplikacje. Korzysta z celery do debugowania facebookowych tokenów.

facebook-javascript-sdk to prosta aplikacja, która pozwala tagiem wstawić do szablonu wklejkę dla JavaScriptowego SDK Facebooka i podpiąć się pod jego inicjalizację.

facebook-javascript-authentication to aplikacja pozwalająca zautoryzować w Django użytkownika, który zaloguje się Facebookiem w naszej aplikacji korzystając z JavaScriptowego SDK (przesyła ajaksem token, a dostaje w odpowiedzi dane użytkownika o ile wszystko się powiedzie).

Te trzy aplikacje znajdą zastosowanie w aplikacjach na Facebooku, czy zewnętrznych serwisach chcących zintegrować logowanie Facebookiem na swojej stronie.

Jak tego użyć?

Na początek potrzebować będziemy aplikację Facebookową. Zakładamy ją na developers.facebook.com. Po stworzeniu aplikacji kopiujemy do settingsów Django ID i sekret tejże aplikacji:

FACEBOOK_APP_SECRET = 'SECRET_HERE'
FACEBOOK_APP_ID = 'APP_ID_HERE'

Do INSTALLED_APPS dodajemy aplikacje:

'facebook_auth',
'facebook_javascript_sdk',
'facebook_javascript_authentication',
'javascript_settings',

Aplikacja javascript_settings wystawia w JS URL do widoku autoryzacji, z czego korzysta facebook_javascript_authentication.

Dodajemy backendy autoryzacji:

AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'facebook_auth.backends.FacebookBackend',
'facebook_auth.backends.FacebookJavascriptBackend',
)

Do urls.py dodajemy:

url(r'^facebook_javascript_authentication/', include('facebook_javascript_authentication.urls')),

W szablonie dodajemy javascript_settings (można też użyć opcji z finderem STATICFILES) i skrypt z facebook_javascript_authentication:

<script type="text/javascript">{% javascript_settings %}</script>
<script type="text/javascript" src="{% static 'facebook_javascript_authentication/script.js' %}"></script>

Mając wszystko gotowe można zaimplementować prostą autoryzację jak w tym przykładzie. W uproszczeniu może wyglądać to tak:

$(function() {
    $('.SOME_LOGIN_LINK').click(authenticateWithFacebook);
});

function authenticateWithFacebook() {
    loginDialog(successCallback);

    function successCallback(response) {
        if (response.status == 'ok') {
            alert('ok');
        } else {
            alert('error');
        }
    }
}

Funkcja loginDialog wywoła autoryzację Facebooka i jeżeli się powiedzie wykona żądanie AJAX do backendu autoryzując użytkownika w Django. Gdy dostanie informację zwrotną wywoła funkcję JS podaną jako callback.

W facebook_javascript_authentication dostępne są dwie funkcje. loginDialog(onSuccess, scope) już znamy, ale jest też login(access_token, onSuccess), która się przyda gdy już mamy token z Facebooka.

Aplikacje facebookowej/javascriptowe z RESTowym API autoryzowane tokenem

W przypadku aplikacji napisanych we frameworkach takich jak ember.js, czy angular frontend komunikuje się z backendem po RESTowym API. Można wtedy wykorzystać autoryzowanie żądań z wykorzystaniem tokenów. Django Rest Framework obsługuje taką formę autoryzacji. facebook-javascript-authentication nie zwróci nam tokena, jak i będzie logował użytkownika tworząc sesję (czyli też i ciastko). To może być niepożądane w aplikacjach chcących używać tokenów. Także ustawienie ciastka sesji może się nie udać jeżeli żądanie przyszło z innej domeny (ramka facebookowa, lub inna domena z API itd.).

Na takie przypadki wystarczy stworzyć własny widok autoryzacji dziedziczący facebook_javascript_authentication.views.AuthenticateFacebookUser. Do metody _get_response_data można dodać token, a podając własną funkcję logowania w metodzie post możemy wyłączyć logowanie sesją (widok wywoła djangowskie authenticate, ale już nie login).

Własny widok wystawiamy w urlsach i wystawiamy go w javascript-settings, dla ułatwienia pod tym samym kluczem co oryginał:

def javascript_settings():
    return {
        'authenticate': reverse('nasz-własny-widok-autoryzacji')
    }

Dzięki temu configuration['nasza_aplikacja'] można użyć by nadpisać configuration['facebook_javascript_authentication'] i tym samym sprawić że kod JS facebook-javascript-authentication wyśle żądanie do widoku:

configuration['facebook_javascript_authentication'] = configuration['moja_aplikacja'];

To rozwiązanie nie jest najlepsze. Jest duża szansa że pojawi się niebawem w facebook-javascript-authentication opcja podawania własnego URLa do widoku autoryzacji bez nadpisywania zmiennych w configuration javascript-settings.

facebook-signed-request

facebook-signed-request obsługuje żądania jakie facebook wysyła do aplikacji facebookowej (dokumentacja), gdy użytkownik ją otwiera. Weryfikuje to żądanie i wyciąga dane. Middleware przypisuje je do request.facebook. Ta aplikacja przyda się gdy tworzymy aplikacje facebookowe w kanwie, czy aplikacje w zakładkach na fanpage.

Do INSTALLED_APPS dodajemy facebook_signed_request, a do MIDDLEWARE_CLASSES:

'facebook_javascript_authentication.middlewares.P3PMiddleware',
'facebook_signed_request.middleware.SignedRequestMiddleware',

'facebook_signed_request.middleware.FacebookLoginMiddleware',

Pierwsz dwa najlepiej dać za CommonMiddleware, a ostatni gdzieś pod koniec. W efekcie jeżeli otworzymy jakiś widok naszej aplikacji Django w ramce aplikacji facebookowej, to signed request zostanie obsłużony przez to middleware, a widok dostanie dane w request.facebook.

Żeby otworzyć aplikację w ramce facebookowej musimy podać URL w Facebook Canvas. Facebook wymaga używania linków HTTPS więc bez certyfikatu SSL nie zrobimi aplikacji facebookowej, ani zakładki. W przykładkowej aplikacji podałem https://localhost:8000/canvas/ jako adres URL dla aplikacji w ramce (kanwie). Serwer deweloperski Django nie obsługuje połączeń HTTPS, ale dewelopersko użyć możemy django-sslserver. Wystarczy uruchomoć aplikację za pomocą runsslserver i potwierdzić wyjątek bezpieczeństwa w przeglądarce.

facebook-notifications

facebook-notifications to aplikacja do wysyłania Facebookowych powiadomień. Dostępne są one na desktopowej wersji Facebooka (dokumentacja). Można użyć ich do powiadamiania użytkowników aplikacji Facebookowej o jakiś zdarzeniach (np. w konkursach). Domyślnie są to powiadomienia aplikacji facebookowej, ale na upartego można je wykorzystać do powiadamiania o zdarzeniach na stronie internetowej (wtedy fragment wystawiony jako aplikacja Facebookowa musi przekierowywać z Facebooka na stronę, lub po prostu wyświetlać stronę w ramce facebooka).

Do działania potrzebuje pakietu facepy, oraz danych aplikacji facebookowej.

django-facebook-datastore

django-facebook-datastore to aplikacja, która odpytuje się API facebooka o dane o użytkowniku. Do niektórych potrzeba dodatkowych uprawnień, które Facebook musi zatwierdzić. Dostępne są trzy modele - FacebookUserProfile, FacebookUserLike i FacebookFriend przechowujące pobrane dane.

Żeby aplikacja działała wystarczy stworzyć (najlepiej) task, który odpali się po zalogowaniu się użytkownika (potrzebny jest ważny token). Dla przykładu zrobiłem to na sygnale post_save.

Na zakończenie

Mam nadzieję że zaprezentowane aplikacje są ciekawe. Zachęcam wszystkich do przejrzenia kodu, forkowania i nadsyłania pull requestów. Niebawem pewnie pojawi się jeszcze jedna aplikacja do obsługi akcji opengrafowych (jednego sposobu ich użycia) i to by było na tyle - zestaw małych aplikacji pozwalających wybrać tylko to co jest potrzebne.

RkBlog

Django, 26 February 2015

Comment article
Comment article RkBlog main page Search RSS Contact