Slack-Status als "Busy Indicator" verwenden 

Julia
14.07.2022 0 11:16 min

Was ist sipgate.io?

SMS oder Faxe senden und empfangen, den Anrufverlauf abrufen, Anrufe initiieren und manipulieren – das alles kann sipgate.io ! Mit unseren APIs können Sie unsere Telekommunikationsfunktionen flexibel in Ihren Projekten integrieren. Unsere Library und Tutorials unterstützen Sie dabei, Ihre Telefonie möglichst bequem zu gestalten.

In diesem Tutorial

Erfahren Sie in dieser Schritt-für-Schritt Anleitung, wie Sie einen Slack-Status automatisch ändern können. Slack ist eine bekannte Plattform für interne Kommunikation in einem Unternehmen. Mehr darüber können Sie gerne auf der offiziellen Slack-Website erfahren.
Die automatische Slack-Status-Änderung ist somit eine gute Möglichkeit, Ihre Verfügbarkeit bei Slack zu signalisieren und die Zusammenarbeit mit Ihren Kolleg:innen zu vereinfachen.
Das vollständige Projekt finden Sie in unserem GitHub-Repository .

Voraussetzungen

  • Bevor wir uns mit dem Code auseinandersetzten, richten Sie sich ein sipgate-Konto für sipgate.io ein. Wie das geht, erfahren Sie in unserem Get-Started Guide.
  • Für dieses Tutorial brauchen Sie mindestens ein Slack Standard-Plan-Abo. In unserem Beispiel verwenden wir ein OAuth-Access-Token, um die Statusmeldung von Ihren Mitarbeiter:innen zu ändern. Dafür erstellen wir eine Custom Slack-App.

🗒Anmerkung: es gibt vier Rollen auf der Slack-Plattform: Primary Owner >
Workspace Owner > Workspace Admin > Full Member. 

Der Umfang der Personen, deren Status geändert werden kann, hängt von der Rolle des Erstellers der Slack-App ab. Wir empfehlen deswegen, dass der App-Ersteller ein Primary Owner ist. Dadurch erreichen wir die größtmögliche Anzahl an Mitarbeiter:innen, die die Slack-Integration benutzen können.

Custom Slack-App

  • Erstellen Sie eine Custom Slack-App und folgen Sie dem Pfad OAuth & Permissions (linkes Menü)- User Token Scopes. Fügen Sie die OAuth Scopes users.profile:read und users.profile:write hinzu.
  • Gehen Sie auf Install to workspace (unter OAuth & Permissions) und installieren Sie die App.
    Sie erhalten das OAuth-Access-Token zur Authentifizierung bei der Slack-API. Um das Token für die spätere Verwendung zu speichern, erstellen wir eine .env -Datei im Stammverzeichnis unseres Projekts und speichern sie wie folgt:
export SLACK_TOKEN=<YOUR_OAUTH_ACCESS_TOKEN>

Aufsetzen des Projekts

  • Jetzt, wo die Slack-App fertig eingerichtet ist, können wir das Projekt aufsetzen. Um unser Projekt zu initialisieren, führen wir npm init -y, aus. Dieser Befehl erstellt eine package.json-Datei, in der wir unsere Abhängigkeiten definieren.
  • Für dieses Projekt werden wir die sipgate.io Node.js-Bibliothek verwenden, die die Arbeit mit der sipgate-APIs viel vereinfacht und gleichzeitig eine Gelegenheit bietet, einen Webhook-Server einzurichten. Um die Library zu unserem Projekt hinzuzufügen, führen Sie npm install sipgateioaus.
  • Da wir in diesem Projekt typescript verwenden, müssen wir es mitnpm install -D typescript ts-node @types/nodezu unseren Dev-Abhängigkeiten hinzufügen. Wir fügen auch den scripts-Abschnitt in der package.json hinzu, sodass wir npm start verwenden können, um die Anwendung zu starten.
  "start": "ts-node src/main.ts",

Los geht’s mit dem Coding!

In unserem Startskript haben wir src/main.ts als Einstiegspunkt für die Anwendung angegeben, also müssen wir sie erstellen.

Empfangen von Webhook-Events

Um Webhook-Events von sipgate zu empfangen, benötigen wir einen Webserver, der öffentlich zugänglich ist.

Wenn Sie Webhooks in der Live-Umgebung verwenden, müssen Sie Ihren Code auf einem geeigneten Webserver mit einer geeigneten Adresse ausführen. Für Entwicklungszwecke empfehlen wir jedoch die Nutzung eines Dienstes, der Ihre lokale Umgebung über das Internet zugänglich macht. Dies erleichtert erheblich das Testen Ihres geschriebenen Codes. Es gibt verschiedene kostenlose Dienste, die dafür genutzt werden können. Einige Beispiele sind localhost.run oder ngrok.
Beide stellen Ihnen eine öffentliche URL zur Verfügung, mit der Sie Webhooks von sipgate.io empfangen können. Achten Sie darauf, dass Sie den richtigen Port weiterleiten (in diesem Tutorial Port 8080) und dass der von Ihnen gewählte Anbieter sichere Verbindungen über HTTPS bietet.

Wenn Sie localhost.run verwenden, um Ihren lokalen Port 8080 auf eine öffentliche Adresse weiterzuleiten, führen Sie den folgenden Befehl aus. Kopieren Sie dabei die URL, die Ihnen ausgegeben wird.

ssh -R 80:localhost:8080 ssh.localhost.run

Um sipgate mitzuteilen, wohin die Webhooks gesendet werden sollen, hinterlegen wir die Webhook-URLs aus dem vorherigen Schritt im Console-Dashboard. Achten Sie darauf, dass Sie bei der Adresse https:// angeben, da localhost.run dies nicht in die Ausgabe einbezieht.
Außerdem müssen wir die Serveradresse in einer Umgebungsvariablen speichern. Wir können einfach eine neue Variable zu unsere .env-Datei hinzufügen, etwa so:

export SIPGATE_WEBHOOK_SERVER_ADDRESS=<YOUR_SERVER_ADDRESS>

Nun wollen wir einen Webserver erstellen. Dazu können wir die sipgate.io-Library verwenden.

import { createWebhookModule, AnswerEvent, HangUpEvent } from "sipgateio";

const webhookModule = createWebhookModule();

const webhookServerPort = 8080;
const webhookServerAddress = process.env.SIPGATE_WEBHOOK_SERVER_ADDRESS;

if (!webhookServerAddress) {
  throw new Error(
    "SIPGATE_WEBHOOK_SERVER_ADDRESS environment variable not set"
  );
}

webhookModule
  .createServer({
    port: webhookServerPort,
    serverAddress: webhookServerAddress,
  })
  .then((server) => {
    console.log("Listening on port", webhookServerPort);

    server.onAnswer(handleAnswer);

    server.onHangUp(handleHangUp);
  });

async function handleAnswer(answerEvent: AnswerEvent) {
  console.log(answerEvent);
}

async function handleHangUp(hangUpEvent: HangUpEvent) {
  console.log(hangUpEvent);
}

Der Code erstellt einen Webhook-Server auf dem Port 8080 und bietet mehrere Funktionen zum Empfang von Events (AnswerEvent und HangUpEvent).

Identifizierung von Telefonnummern

Der nächste Schritt besteht darin, den Slack-Status tatsächlich zu ändern. Dafür benötigen wir eine Möglichkeit, eine Telefonnummer mit einer Slack-Mitgliedsnummer zu verknüpfen. Wir haben diese Aufgabenstellung gelöst, indem wir eine mappings.json-Datei bereitgestellt haben, die wie folgt aussieht:

{
  "+4912345678": {
    "slackMemberId": "U01Jxxxxxx"
  }
}

Sie können die Mitglieds-IDs von Slack-Benutzer:innen in deren Profilen abrufen. Öffnen Sie ein Mitgliedsprofil und gehen Sie auf „mehr“. Dort sollten Sie die benötigte Mitgliedsnummer finden. Die Telefonnummern sollten  wie im Code-Snippet gezeigtes Format  haben.

Um auf die Verknüpfung in unserem Code zugreifen zu können, müssen wir die Datei importieren. Die slackMemberId bekommt mit der Schnittstelle SlackUserInfo eine eigene Typisierung. Fügen Sie den folgenden Code nach dem Import ein:

interface SlackUserInfo {
  slackMemberId: string;
}

const MAPPINGS: Record<string, SlackUserInfo> = require("../mappings.json");

Nachdem wir nun Zugang zu der Verknüpfung haben, arbeiten wir mit der Funktion handleAnswer. Ein AnswerEvententhält die Richtung des Anrufs, d.h. ob es sich um einen eingehenden oder ausgehenden Anruf handelt, die Nummer des Anrufers/Abonnenten und einige weitere Metadaten. Durch die Überprüfung der Anrufrichtung können wir herausfinden, welche slackMemberId zu der Telefonnummer gehört und folglich den Slack-Status setzen. Im Falle eines ausgehenden Anrufs benötigen wir die Nummer des Anrufenden und für einen eingehenden Anruf die Nummer des Angerufenen.
Dafür schreiben wir jetzt eine Funktion, die diese Nummer aus einem AnswerEvent extrahiert.

function getRelevantNumber(answerEvent: AnswerEvent | HangUpEvent): string {
  return answerEvent.direction === "out"
    ? answerEvent.from
    : answerEvent.answeringNumber;
}

Wir können diese Funktion in handleAnswer verwenden. Zunächst sind die Voicemail-Anrufe in diesem Beispiel für uns nicht relevant, also sollen wir überprüfen, ob es sich um einen solchen Anruf handelt.

Im nächsten Schritt verwenden wir die Variable relevantNumber, um die Telefonnummer aus dem vorherigen Code und die Slack-Benutzerinformationen aus der Mapping-Datei zu erhalten. Dann überprüfen wir, ob eine Zuordnung bereits vorhanden ist oder nicht.

async function handleAnswer(answerEvent: AnswerEvent) {
  if (answerEvent.user === "voicemail") return;

  const relevantNumber = getRelevantNumber(answerEvent);
  const slackUserInfo: SlackUserInfo | undefined = MAPPINGS[relevantNumber];

  if (!slackUserInfo) {
    console.warn(
      `[answerEvent] No slack user mapped for number ${relevantNumber}`
    );
    return;
  }

  // set status
}

Die Funktion handleHangUpsieht ziemlich ähnlich zu dem vorher gezeigten Beispiel aus. Hier ignorieren wir alle weitergeleiteten HangUps.

async function handleHangUp(hangUpEvent: HangUpEvent) {
  if (hangUpEvent.cause === HangUpCause.FORWARDED) return;

  const relevantNumber = getRelevantNumber(hangUpEvent);
  const slackUserInfo: SlackUserInfo | undefined = MAPPINGS[relevantNumber];

  if (!slackUserInfo) {
    console.warn(
      `[hangupEvent] No slack user mapped for number ${relevantNumber}`
    );
    return;
  }

  // reset status
}

Verbinden mit der Slack-API

Um mit der Slack Web-API zu kommunizieren, verwenden wir das offizielle Slack-Node-Paket:

npm install @slack/web-api

Erstellen Sie imsrc-Verzeichnis eine slack.ts-Datei und fügen Sie folgenden Code-Abschnitt ein:

import { WebClient } from "@slack/web-api";

const token = process.env.SLACK_TOKEN;
if (!token) throw new Error("SLACK_TOKEN environment variable not set!");

const web = new WebClient(token);

Dieser Code-Abschnitt erstellt einen Slack-WebClient mit dem Token aus der zuvor konfigurierten Umgebungsvariablen.Jetzt sind wir autorisiert und können mit der API kommunizieren. Im nächsten Schritt erstellen wir eine Funktion, die den Status ändern:

export interface Status {
  status_text: string;
  status_emoji: string;
}

export async function setStatus(
  slackMemberId: string,
  status: Status
): Promise<void> {
  const response = await web.users.profile.set({
    user: slackMemberId,
    profile: JSON.stringify(status),
  });

  if (!response.ok) throw Error(response.error);
}

Die Funktion beinhaltet eine Slack-Mitglieds-ID und ein Status-Objekt. Dieses Objekt enthält die Informationen, auf die der Status geändert werden soll. Um den Status eines Slack-Mitglieds zu speichern, bevor es aktualisiert wird, benötigen wir eine Funktion, die den aktuellen Status abfragt. Wir werden den Status später wieder auf seinen vorherigen Zustand zurücksetzen. Wie es im folgenden Code-Snippet gezeigt wird, gibt diese Funktion ein Status-Objekt zurück.

export async function getStatus(slackMemberId: string): Promise<Status> {
  const response = await web.users.profile.get({ user: slackMemberId });
  if (!response.ok) throw Error(response.error);

  const profile = response.profile as Status;
  return {
    status_text: profile.status_text,
    status_emoji: profile.status_emoji,
  };
}

Die Slack-Logik implementieren

Zurzeit haben wir die notwendigen Funktionen erstellt, die den Slack-Status konfigurieren und aktualisieren. In diesem Abschnitt implementieren wir die restliche Logik unseres Event-Handler in src/main.ts. Dazu importieren wir zunächst die Funktionen aus slack.ts und erstellen ein Objekt, das den vorherigen Status speichert.

Wenn ein Anruf angenommen wird, speichern wir den alten Status in
slack.ts, bevor wir den neuen Status einfügen.

import { Status, getStatus, setStatus } from "./slack";

// map from slackUserId to status before AnswerEvent
const previousStatuses: Record<string, Status> = {};

// ...

async function handleAnswer(answerEvent: AnswerEvent): Promise<void> {
  // ...

  if (previousStatuses[slackUserInfo.slackMemberId]) {
    console.warn(`[answerEvent] Status of ${relevantNumber} was already set.`);
    return;
  }

  const previousStatus = await getStatus(slackUserInfo.slackMemberId);
  previousStatuses[slackUserInfo.slackMemberId] = previousStatus;

  const inCallStatus = {
    status_emoji: ":phone:",
    status_text: "Currently in a call",
  };
  await setStatus(slackUserInfo.slackMemberId, inCallStatus);

  console.log(
    `[answerEvent] setting status of ${relevantNumber} to ${inCallStatus}`
  );
}

Wir haben die Funktion handleAnswer erweitert, um zu prüfen, ob ein vorheriger Status vorliegt.

Der nächste Schritt besteht darin, den aktuellen Status zu speichern, damit wir ihn beim Auflegen des Anrufs wiederherstellen können. Nach dem Speichern ändern wir den Status, sodass jede:r sehen kann, dass die Person gerade im Gespräch ist. Um den Status bei einem HangUpEvent wiederherzustellen, müssen wir auch die FunktionhandleHangUp anpassen.
Diese Funktion prüft, ob ein Status eines Slack-Mitglieds vorhanden war oder nicht.
Wenn ein vorheriger Status existiert, wird er wiederhergestellt und der Eintrag im previousStatuses-Datensatz gelöscht.

async function handleHangUp(hangUpEvent: HangUpEvent): Promise<void> {
  // ...

  const previousStatus: Status | undefined =
    previousStatuses[slackUserInfo.slackMemberId];

  if (!previousStatus) return;

  console.log(
    `[hangupEvent] setting status of ${relevantNumber} back to ${previousStatus}`
  );

  await setStatus(slackUserInfo.slackMemberId, previousStatus);
  delete previousStatuses[slackUserInfo.slackMemberId];
}

Den Server starten

Unser Code ist bereit zur Ausführung. Stellen Sie sicher, dass Sie die richtige Verknüpfung in der mappings.json konfiguriert haben. Führen Sie dann npm start aus, um den Code zu testen.

Sie sollten nun ein Protokoll wie dieses sehen:

Listening on port 8080

Dies ist ein gutes Zeichen. Der Server ist jetzt bereit für Anrufe. Wenn Sie einen Anruf erhalten oder selbst jemanden anrufen, sollten Sie folgenden Hinweis in der Konsole sehen:

[answerEvent] setting status of +491234xxxx to { status_text: 'Currently in a call', status_emoji: ':phone:' }

Sie können nun zu Slack gehen und überprüfen, ob der Status richtig gesetzt wurde. Wenn der Anruf aufgelegt wird, sollte diesen Hinweis in der Konsole erscheinen:

[hangupEvent] setting status of +491234xxxx back to { status_text: '', status_emoji: '' }

Jetzt sollte der Status wiederhergestellt sein.

Fazit

In diesem Tutorial haben Sie gelernt, wie Sie Ihren Slack-Status als “Busy Indicator” verwenden und automatisch einrichten können.

Das vollständige Projekt finden Sie in unserem GitHub-Repository .

Wenn Sie mehr über die Möglichkeiten unserer sipgate.io-Library erfahren möchten, schauen Sie sich die anderen Tutorials in unserem Blog an.

 

Keine Kommentare


Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.