Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚀 Feature: Add WhatsApp with Vonage for PHP #206

Closed
6 tasks
gewenyu99 opened this issue Oct 1, 2023 · 10 comments · Fixed by #239
Closed
6 tasks

🚀 Feature: Add WhatsApp with Vonage for PHP #206

gewenyu99 opened this issue Oct 1, 2023 · 10 comments · Fixed by #239
Assignees
Labels
hacktoberfest Issues for Hacktoberfest 2023

Comments

@gewenyu99
Copy link

gewenyu99 commented Oct 1, 2023

Appwrite Functions allow you to extend and customize your Appwrite server functionality by executing your custom code. 🤩 You can learn more at our official Appwrite Functions docs.

Your task is to implement the WhatsApp with Vonage function in PHP. You can look at the existing Appwrite Functions Templates in another coding language.

Your function should behave and be implemented similarly to existing WhatsApp with Vonage Node.js template.

Tasks summary:

  • Fork & clone Appwrite's templates repository
  • Create a branch feat-implement-whatsapp-with-vonage-php
  • Write code for the function in folder php/whatsapp-with-vonage/.
  • Test the function using Appwrite, provide a video.
  • Write a README.md explaining what the function does, how to use it, and customize it. Here is an example.
  • Submit a pull request to our templates repository

If you need any help, contact us on our Discord server.

Are you ready to work on this issue? 🤔 Let us know, and we will assign it to you 😊

Happy coding!

@gewenyu99 gewenyu99 added the hacktoberfest Issues for Hacktoberfest 2023 label Oct 1, 2023
@SoNiC-HeRE
Copy link
Contributor

I'm interested in working on this issue, can i be assigned pls?

@loks0n
Copy link
Member

loks0n commented Oct 1, 2023

Hi @SoNiC-HeRE, I've assigned this issue to you! Thanks your interest in contributing to Appwrite! Happy Hacktoberfest 🎃

Notes:

  • Please update us with your progress every 3 days, so that we know that you are working on it.
  • Join us on Discord - https://appwrite.io/discord to chat about Hacktoberfest and Appwrite!

@SoNiC-HeRE
Copy link
Contributor

Hi @SoNiC-HeRE, I've assigned this issue to you! Thanks your interest in contributing to Appwrite! Happy Hacktoberfest 🎃

Notes:

* Please update us with your progress every 3 days, so that we know that you are working on it.

* Join us on Discord - https://appwrite.io/discord to chat about Hacktoberfest and Appwrite!

Thank you; I'll keep the notes in mind.

@SoNiC-HeRE
Copy link
Contributor

Progress:

  • I managed to create a web app using Appwrite in Php
  • Used a starter template for creating a function to implement the vonage function
  • Understood how appwrite functions work
  • Created a landing page for the function template

To do:

  • Integrate the Vonage Api demo in the current template

@monhelnog
Copy link

I would like to work on this issue

@Haimantika
Copy link

I would like to work on this issue

Hi, we are assigning issues on a first-come, first-serve basis, if @SoNiC-HeRE decides to drop off, we will assign it to you.

@SoNiC-HeRE
Copy link
Contributor

SoNiC-HeRE commented Oct 6, 2023


require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/utils.php');
use Firebase\JWT\JWT; // Import JWT from Firebase\JWT namespace
use GuzzleHttp\Client;

// Load environment variables from .env file
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

return function ($context) {

    if ($context->req->method === 'GET') {
        return $context->res->send(get_static_file('index.html'), 200, [
            'Content-Type' => 'text/html; charset=utf-8',
        ]);
    }

    // Obtain and decode the JWT token
    $headers = $context->req->headers;
    $token = explode(" ", ($headers["authorization"] ?? ""))[1] ?? "";

    try {
        $decoded = JWT::decode($token, $_ENV["VONAGE_API_SIGNATURE_SECRET"], ["HS256"]);
    } catch (Exception $e) {
        return $context->res->json(["ok" => false, "error" => $e->getMessage()], 401);
    }

    if (hash("sha256", $context->req->rawBody) !== $decoded->payload_hash) {
        return $context->res->json(["ok" => false, "error" => "Payload hash mismatch."], 401);
    }

    // Check for required fields in the request body
    $body = json_decode($context->req->rawBody, true);
    try {
        throw_if_missing($body, ["from", "text"]);
    } catch (Exception $e) {
        return $context->res->json(["ok" => false, "error" => $e->getMessage()], 400);
    }

    // Prepare and send the WhatsApp message
    $headers = [
        "Content-Type" => "application/json",
        "Accept" => "application/json",
    ];

    $data = [
        "from" => $_ENV["VONAGE_WHATSAPP_NUMBER"],
        "to" => $body["from"],
        "message_type" => "text",
        "text" => 'Hi there! You sent me: ' . $body["text"],
        "channel" => "whatsapp",
    ];

    $client = new Client();
    $url = "https://messages-sandbox.nexmo.com/v1/messages";

    try {
        $response = $client->post($url, [
            "headers" => $headers,
            "json" => $data,
            "auth" => [
                $_ENV["VONAGE_API_KEY"],
                $_ENV["VONAGE_API_SECRET"]
            ],
        ]);

        if ($response->getStatusCode() === 200) {
            $result = json_decode($response->getBody(), true);
            return $context->res->json(["ok" => true]);
        } else {
            return $context->error("Error " . $response->getBody());
        }
    } catch (Exception $e) {
        return $context->res->json(["ok" => false], 500);
    }
};
?>

I'm not sure what potentially am i doing wrong here since I'm getting no errors while deploying the page and when i try to send message (from a whitelisted and approved number) to the sandbox account i get no response

@loks0n
Copy link
Member

loks0n commented Oct 11, 2023

I'm not sure what potentially am i doing wrong here since I'm getting no errors while deploying the page and when i try to send message (from a whitelisted and approved number) to the sandbox account i get no response

Do you see anything helpful in the execution logs? Is Vonage calling your function?
Try to add logging to understand how far in the execution flow the function is reaching

@SoNiC-HeRE
Copy link
Contributor

I'm not sure what potentially am i doing wrong here since I'm getting no errors while deploying the page and when i try to send message (from a whitelisted and approved number) to the sandbox account i get no response

Do you see anything helpful in the execution logs? Is Vonage calling your function? Try to add logging to understand how far in the execution flow the function is reaching

Ah,yes I tried logging as well, in the execution tab my GET requests are successfully completed while POST requests are failing with an error An internal curl error has occurred within the executor! Error Msg: Operation timed out\nError Code: 500

Further I tried using cURL for making POST requests as well but nothing seems to work.

Should i open a draft pr for this?

@SoNiC-HeRE
Copy link
Contributor

SoNiC-HeRE commented Oct 13, 2023

I'm not sure what potentially am i doing wrong here since I'm getting no errors while deploying the page and when i try to send message (from a whitelisted and approved number) to the sandbox account i get no response

Do you see anything helpful in the execution logs? Is Vonage calling your function? Try to add logging to understand how far in the execution flow the function is reaching

I've updated the code as

<?php

require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/utils.php');

use \Firebase\JWT\JWT;
use GuzzleHttp\Client;

return function ($context) {
    $context->log('Authentication');

    throw_if_missing($_ENV, [
        'VONAGE_API_KEY',
        'VONAGE_API_SECRET',
        'VONAGE_API_SIGNATURE_SECRET',
        'VONAGE_WHATSAPP_NUMBER',
    ]);

    if ($context->req->method === 'GET') {
        return $context->res->send(get_static_file('index.html'), 200, [
            'Content-Type' => 'text/html; charset=utf-8',
        ]);
    }

    $body = $context->req->body;
    $headers = $context->req->headers;
    $token = (isset($headers["Authorization"])) ? explode(" ", $headers["Authorization"])[1] : "";

    try {
        $decoded = JWT::decode($token, $_ENV['VONAGE_API_SIGNATURE_SECRET'], ['HS256']);
        $context->log($decoded);
    } catch (Exception $e) {
        return $context->res->json([
          'ok'=> false,
          'error'=> $e->getMessage(),
        ]);
    }

    if (hash('sha256', $context->req->bodyRaw) !== $decoded['payload_hash']) {
        return $context->res->json([
            'ok' => false,
            'error' => 'Payload hash mismatch'
        ]);
    }

    try {
        throwIfMissing($context->req->body, ['from', 'text']);
    } catch (Exception $e) {
        return $context->res->json(["ok" => false, "error" => $e->getMessage()], 400);
    }

    $vonageApiKey = $_ENV['VONAGE_API_KEY'];
    $vonageAccountSecret = $_ENV['VONAGE_API_SECRET'];

    $basicAuthToken = base64_encode("$vonageApiKey:$vonageAccountSecret");
    $headers = [
        'Content-Type: application/json',
        'Accept: application/json',
        'Authorization: Basic ' . $basicAuthToken,
    ];

    $data = [
        'from' => $_ENV['VONAGE_WHATSAPP_NUMBER'],
        'to' => $context->req->body['from'],
        'message-type' => 'text',
        'text' => 'Hi there! You sent me: ' . $context->req->body['text'],
        'channel' => 'whatsapp',
    ];
    $client = new Client();
    $url = "https://messages-sandbox.nexmo.com/v1/messages";

    try {
        $response = $client->post($url, [
            "headers" => $headers,
            "json" => $data,
        ]);

        if ($response->getStatusCode() === 200) {
            $result = json_decode($response->getBody(), true);
            return $context->res->json(["ok" => true]);
        } else {
            $context->error("Error: " . $response->getBody());
            return $context->res->json(["ok" => false, "error" => "Internal server error"], 500);
        }
    } catch (Exception $e) {
        $context->error("Error: " . $e->getMessage());
        return $context->res->json(["ok" => false, "error" => "Internal server error"], 500);
    }
}

In the executions tab my GET requests are working where as POST requests are failing with following error:
An internal curl error has occurred within the executor! Error Msg: Operation timed out\nError Code: 500
I increased the timeout and the error changed to:
Operation timed out after 30001 milliseconds with 0 bytes received with status code 0\nError Code: 0

Issue Resolved ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hacktoberfest Issues for Hacktoberfest 2023
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants