https://d226lax1qjow5r.cloudfront.net/blog/blogposts/build-turkey-timer-laravel-facebook-messenger-dr/Blog_Timer-Lavavel-FB_1200x600.png

Bau eines Truthahn-Timers mit Laravel, Facebook Messenger und Vonage

Zuletzt aktualisiert am May 21, 2021

Lesedauer: 6 Minuten

Dieses Jahr wurde ich von meiner Schwiegermutter gebeten, ihr beim Kochen des Weihnachtsessens für die Familie zu helfen. Ich freue mich schon sehr darauf, aber mit einem neuen Welpen im Haus und einem kleinen Neffen kann es passieren, dass ich mich ablenken lasse und vergesse, die Kartoffeln rechtzeitig in den Ofen zu schieben!

Um dabei zu helfen, habe ich beschlossen, eine kleine Laravel-Anwendung zu schreiben, die eine Sammlung von Rezepten verwaltet. Man schickt ihr eine Nachricht mit dem Namen eines Rezepts über WhatsApp, Facebook oder Viber. Sie ruft die Liste der Schritte ab, die für jedes Rezept erforderlich sind, und schickt Ihnen den nächsten Schritt, wenn es an der Zeit ist, ihn auszuführen. Sie können sich entspannen, denn Sie wissen, dass alles in der Küche unter Kontrolle ist, und wenn es Zeit für einen menschlichen Eingriff ist, werden Sie benachrichtigt!

Hier sehen Sie die Anwendung in Aktion:

Turkey Timer DemoTurkey Timer Demo

In diesem Beitrag werde ich mit Facebook arbeiten, aber es ist einfach, es auch auf WhatsApp und Viber zu erweitern, da wir das Vonage laravel-notification Paket.

Laravel und Vonage-Projekt einrichten

Für dieses Projekt sind ziemlich viele Einstellungen erforderlich. Damit Sie nicht bis Neujahr brauchen, um das zu lesen, bin ich in diesem Beitrag direkt zum Vonage-spezifischen Code übergegangen. Wenn Sie interessiert sind, hier ist der Prozess, den ich durchlief, um die Anwendung einzurichten (jeder Punkt verlinkt auf ein Commit, das eine längere Beschreibung der geleisteten Arbeit enthält):

Es handelt sich um eine recht einfache Anwendung, die eine Benutzerverwaltung und die Möglichkeit bietet, ein Rezept und die dazugehörigen Zeitangaben anzuzeigen. Es handelt sich um eine eigenständige Anwendung, die im Moment nicht von Vonage abhängig ist. Wir möchten jedoch in der Lage sein, Nachrichten auf unserer Facebook-Seite zu empfangen, also muss ich ein wenig mehr konfigurieren. Damit die Anwendung funktioniert, muss ich meine Facebook-Seite mit einem Vonage Account verknüpfen, eine Anwendung erstellen und konfigurieren damit Vonage weiß, wohin die Webhook-Anfragen zu senden sind und meine Anwendung mit ngrok dem Internet aussetzen so dass Vonage sie erreichen kann.

Wenn Sie versuchen möchten, dies selbst zu bauen, treten Sie dem Vonage Community Slack Workspace bei und wir können die erforderlichen Schritte gemeinsam durchgehen

Im weiteren Verlauf dieses Beitrags werden wir die Möglichkeit hinzufügen, dass Benutzer eine Nachricht mit dem Namen eines Rezepts an uns senden können und dass die Anwendung mit den erforderlichen Aktionen zum richtigen Zeitpunkt antwortet.

Umgang mit eingehenden Facebook-Nachrichten

Als ich meine Vonage-Anwendung erstellt habe, musste ich zwei URLs bereitstellen: eine, die aufgerufen wird, wenn ich eine Nachricht von einem Benutzer erhalte, und eine weitere, die Statusaktualisierungen von Vonage empfängt. Ich habe gewählt /webhooks/inbound-message für den Empfang von Nachrichten und /webhooks/message-status für die Statusaktualisierungen. Da Vonage eine Anfrage von außerhalb der Anwendung senden wird, musste ich die CSRF Prüfung in app/Http/Middleware/VerifyCsrfToken.php:

protected $except = [
    '/webhooks/*'
];

Jetzt, da Vonage auf meinen Webhook zugreifen kann, ist es an der Zeit, die eingehenden Anfragen zu bearbeiten. Ich habe make:controller um eine neue WebhooksController und aktualisierte routes/web.php um die obigen URLs auf diesen Controller zu verweisen:

Route::post('/webhooks/inbound-message', 'WebhooksController@inboundMessage')->name('webhooks.inbound');
Route::post('/webhooks/message-status', 'WebhooksController@messageStatus')->name('webhooks.status');

Als Letztes müssen Sie die Option WebhooksController. Im Moment protokolliere ich die eingehende Anfrage, damit ich das Format der Anfrage sehen kann, die Vonage sendet:

namespace App\Http\Controllers;
use Illuminate\Http\Request;

class WebhooksController extends Controller
{
    public function inboundMessage(Request $request) {
        \Log::debug('Inbound Message', $request->all());
    }

    public function messageStatus(Request $request) {
        \Log::debug('Message Status', $request->all());
    }
}

Nachdem ich diese Änderungen vorgenommen hatte, schickte ich eine Nachricht von meinem persönlichen Account an meine Facebook-Seite und der folgende Eintrag erschien in der Laravel-Logdatei:

{
  "message_uuid": "f4fcc665-7b71-4291-a079-505154e28c36",
  "to": {
    "id": "987654210987654",
    "type": "messenger"
  },
  "from": {
    "id": "123456789012345",
    "type": "messenger"
  },
  "timestamp": "2018-12-12T11:36:44.663Z",
  "direction": "inbound",
  "message": {
    "content": {
      "type": "text",
      "text": "Christmas Dinner"
    }
  }
}

Ausgezeichnet! Der Benutzer hat mir eine Nachricht geschickt und meine Anwendung hat sie wie vorgesehen empfangen. Jetzt, da wir Nachrichten empfangen können, ist es an der Zeit, Antworten zurückzusenden.

Die in diesem Abschnitt vorgenommenen Änderungen sind in diesem Commit

Erstellen einer Laravel-Benachrichtigung

Um Aktualisierungen zum richtigen Zeitpunkt an den Benutzer zurückzuschicken, werden wir die Laravel-Warteschlangensystem delay Funktionalität. Bevor wir das tun können, müssen wir die queue Funktionalität in Laravel aktivieren. Wir werden den database Treiber verwenden, da der Durchsatz nicht besonders hoch ist und die Verwendung der Datenbank zusätzliche Abhängigkeiten wie Redis überflüssig macht. Wir können diese Einstellung in der .env Datei konfigurieren:

QUEUE_CONNECTION=database

Sobald das erledigt ist, habe ich die Tabelle zum Speichern der Aufträge erstellt, indem ich php artisan queue:table && php artisan migrate.

Jetzt, wo die ganze Verwaltung erledigt ist, ist es an der Zeit, mit der Erstellung unserer Benachrichtigungen zu beginnen. Ich werde einen einfachen Satz senden müssen, wenn eine Bedingung ausgelöst wird. Ich hätte eine Benachrichtigung pro Nachricht erstellen können, aber im Interesse der Schnelligkeit habe ich eine einzige Benachrichtigung erstellt, die einen String bei app/Notifications/FreeText.php mit dem folgenden Inhalt akzeptiert:

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;

class FreeText extends Notification implements ShouldQueue
{
    use Queueable, ShouldQueue;

    protected $text;
    protected $channel;

    public function __construct($text, $channel)
    {
        $this->text = $text;
        $this->channel = $channel;
    }

    public function via($notifiable)
    {
        return [];
    }
}

Damit wird eine Benachrichtigung definiert, aber unsere Anwendung weiß noch nicht, wie sie gesendet werden soll. Wir müssen die via Methode und implementieren alle to* Methoden für die Benachrichtigung implementieren. Um diese Benachrichtigungen zu senden, werden wir die nexmo/laravel-notification Paket, das es uns erlaubt, die folgenden Methoden in unserer Benachrichtigung zu implementieren:

  • toNexmoWhatsApp

  • toNexmoFacebook

  • toNexmoViberServiceMessage

  • toNexmoSms

Wir werden und implementieren toNexmoFacebook indem wir der Meldung Folgendes hinzufügen:

public function toNexmoFacebook($notifiable)
{
    return (new \Nexmo\Notifications\Message\Text)
        ->content($this->text);
}

Zusätzlich zur Implementierung dieser Methoden müssen wir Laravel mitteilen, wie die Nachricht weitergeleitet werden soll. Normalerweise verwendet man die $notifiable Entität, die an die Methode übergeben wird, um zu bestimmen, wie der Benutzer kontaktiert werden möchte. In diesem Fall werden wir auf dem Kanal antworten, auf dem wir die Nachricht erhalten haben. Dieser Kanal wird an den Konstruktor der Benachrichtigung übergeben. So sieht meine via Methode mit diesen Änderungen so aus:

public function via($notifiable)
{
    return [$this->channel];
}

Bevor das Ganze funktioniert, müssen Sie noch einige Vonage-Authentifizierungsdaten und die Konfiguration für den Versand über Messenger bereitstellen. Wenn Sie dasselbe tun möchten, erstellen Sie eine Anwendung auf dem Vonage-Dashboard und fügen Sie die folgende Datei zu Ihrer .env Datei hinzu:

NEXMO_APPLICATION_ID="YOUR_APPLICATION_ID"
NEXMO_PRIVATE_KEY=./private.key
NEXMO_FROM_MESSENGER="FACEBOOK_PAGE_ID"

Die in diesem Abschnitt vorgenommenen Änderungen sind in diesem Commit

Senden von Updates an Facebook

Nachdem wir nun all die harte Arbeit erledigt haben, müssen wir als Letztes die Aktionen senden, die zum Kochen des Rezepts ausgeführt werden müssen.

Wenn wir eine Nachricht von einem Benutzer erhalten, müssen wir den Kanal, über den die Nachricht gesendet wurde, und die ID des Benutzers, der uns die Nachricht geschickt hat, extrahieren. Sobald wir das haben, können wir eine neue On-Demand-Benachrichtigung mit diesen Informationen erstellen:

// The incoming message contains the platform + contact details that
// we need to reply with, so configure a notification route with those
// details
$from = $request->input('from');

// The Vonage Messages API returns messenger, but our channel names are all prefixed with nexmo-
$channel = 'nexmo-' . $from['type'];
$sender = Notification::route($channel, $from['id']);

An dieser Stelle können wir dem Benutzer einen beliebigen Text senden. Als Erstes müssen wir prüfen, ob die Nachricht, die er uns geschickt hat, einen Rezeptnamen enthält. Ist dies nicht der Fall, senden wir eine Nachricht, dass wir das Rezept nicht finden konnten.

// Try and find the recipe name that was sent to us
$recipeName = $request->input('message.content.text');
$recipe = \App\Recipe::where('name', $recipeName)->first();
if (!$recipe) {
    $sender->notify(new FreeText(
        "I couldn't find that recipe",
        $channel
    ));
    return;
}

Wenn wir diesen Codeblock überwinden, haben wir ein gültiges Rezept, und es ist an der Zeit, einige Benachrichtigungen zu planen! Jeder Satz von Zeitangaben in einem Rezept hat eine action und eine start_time in Sekunden, beginnend bei Null. Glücklicherweise erlaubt uns Laravel, eine Benachrichtigung um eine Anzahl von Sekunden von jetzt an zu verzögern, was für unseren Anwendungsfall perfekt passt.

Der letzte Teil unserer inboundMessage Methode muss über jede timing durchlaufen und eine neue Benachrichtigung planen:

foreach ($recipe->timings()->get() as $t) {
    $sender->notify((new FreeText(
        $t->action,
        $channel
    ))->delay($t->start_time));
}

Wenn man alles zusammenfasst, sieht unsere inboundMessage Methode wie folgt aus:

public function inboundMessage(Request $request) {
    \Log::debug('Inbound Message', $request->all());

    $from = $request->input('from');

    // The Vonage API returns messenger, but our channel names are all prefixed with nexmo-
    $channel = 'nexmo-' . $from['type'];
    $sender = Notification::route($channel, $from['id']);

    // Try and find the recipe name that was sent to us
    $recipeName = $request->input('message.content.text');
    $recipe = \App\Recipe::where('name', $recipeName)->first();
    if (!$recipe) {
        $sender->notify(new FreeText(
            "I couldn't find that recipe",
            $channel
        ));
        return;
    }

    // If we get this far, we have a recipe! Time to schedule some notifications
    foreach ($recipe->timings()->get() as $t) {
        $sender->notify((new FreeText(
            $t->action,
            $channel
        ))->delay($t->start_time));
    }
}

Die in diesem Abschnitt vorgenommenen Änderungen sind in diesem Commit

Ausführen der Anwendung

Jetzt, wo alles gebaut ist, ist es an der Zeit, die endgültige Anwendung zu starten! Hier ist eine kurze Checkliste mit allem, was ich tun musste, um die Dinge zum Laufen zu bringen:

  1. ausführen. php artisan serve

  2. Stellen Sie sicher, dass ngrok http 8000 ausgeführt wird, damit Vonage Anrufe an meine Anwendung tätigen kann

  3. ausführen php artisan queue:work um zu beobachten, ob Aufträge in die Datenbank eingefügt werden

  4. Besuchen Sie meine Facebook-Seite und senden Sie ihr ein Rezept (in diesem Fall, Christmas Dinner!)

  5. Sich zurücklehnen und entspannen, weil ich weiß, dass ich eine Nachricht erhalte, wenn es etwas zu tun gibt

Wenn Sie das komplette Projekt für diesen Beitrag sehen möchten, können Sie es finden Sie es auf Github. Wenn du es selbst ausführen willst, musst du das tun:

  1. Verknüpfen Sie eine Facebook-Seite mit Vonage

  2. Erstellen Sie eine neue Vonage-Anwendung und verknüpfen Sie Ihre Seite mit dieser Anwendung

  3. Konfigurieren Sie Ihre Webhooks

  4. Klonen Sie das Projektarchiv

  5. Aktualisieren Sie .env mit Ihren Vonage-Anmeldedaten

  6. ausführen. composer install

  7. ausführen. php artisan migrate && php artisan db:seed

  8. Führen Sie aus. php artisan serve und php artisan queue:work in getrennten Terminals

  9. Senden Sie Ihrer Facebook-Seite eine Nachricht

Wie geht es weiter?

Nun, das hat Spaß gemacht! Ich konnte nicht nur die Vonage Messages API ausprobieren, sondern ich habe auch viel über Laravel-Benachrichtigungen gelernt (u. a. wie man neue Kanäle). Als zusätzlichen Bonus werde ich sogar einen kleinen Helfer haben, der mich daran erinnert, wenn am ersten Weihnachtsfeiertag etwas passieren muss!

Teilen Sie:

https://a.storyblok.com/f/270183/384x384/1c8825919c/mheap.png
Michael HeapVonage Ehemalige

Michael ist ein polyglotter Software-Ingenieur, der sich dafür einsetzt, die Komplexität von Systemen zu reduzieren und sie berechenbarer zu machen. Er arbeitet mit einer Vielzahl von Sprachen und Tools und gibt sein technisches Fachwissen auf Benutzergruppen und Konferenzen in der ganzen Welt weiter. Im Alltag ist Michael ein ehemaliger Developer Advocate bei Vonage, wo er seine Zeit damit verbrachte, über alle Arten von Technologie zu lernen, zu lehren und zu schreiben.