Skip to content

Commit

Permalink
Flow message support
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrieldwight committed Nov 4, 2023
1 parent e41c9e0 commit a6094c7
Show file tree
Hide file tree
Showing 11 changed files with 535 additions and 7 deletions.
109 changes: 109 additions & 0 deletions Samples/WhatsAppBusinessCloudAPI.Web/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,64 @@ public async Task<IActionResult> SendWhatsAppInteractiveMessage(SendInteractiveM
}
}

public IActionResult SendWhatsAppFlowMessage()
{
SendFlowMessageViewModel sendFlowMessageViewModel = new SendFlowMessageViewModel();
sendFlowMessageViewModel.FlowAction = new List<SelectListItem>()
{
new SelectListItem(){ Text = "Navigate", Value = "navigate" },
new SelectListItem(){ Text = "Data Exchange", Value = "data_exchange" }
};
sendFlowMessageViewModel.Mode = new List<SelectListItem>()
{
new SelectListItem(){ Text = "Draft", Value = "Draft" },
new SelectListItem(){ Text = "Published", Value = "Published" }
};
return View(sendFlowMessageViewModel);
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SendWhatsAppFlowMessage(SendFlowMessageViewModel sendFlowMessageViewModel)
{
try
{
FlowMessageRequest flowMessageRequest = new FlowMessageRequest();
flowMessageRequest.To = sendFlowMessageViewModel.RecipientPhoneNumber;
flowMessageRequest.Interactive = new FlowMessageInteractive();

flowMessageRequest.Interactive.Header = new FlowMessageHeader();
flowMessageRequest.Interactive.Header.Type = "text";
flowMessageRequest.Interactive.Header.Text = "Header flow";

flowMessageRequest.Interactive.Body = new FlowMessageBody();
flowMessageRequest.Interactive.Body.Text = "Body flow";

flowMessageRequest.Interactive.Footer = new FlowMessageFooter();
flowMessageRequest.Interactive.Footer.Text = "Footer flow";

flowMessageRequest.Interactive.Action = new FlowMessageAction();
flowMessageRequest.Interactive.Action.Parameters = new FlowMessageParameters();
flowMessageRequest.Interactive.Action.Parameters.FlowToken = sendFlowMessageViewModel.FlowToken;
flowMessageRequest.Interactive.Action.Parameters.FlowId = sendFlowMessageViewModel.FlowId;
flowMessageRequest.Interactive.Action.Parameters.FlowCta = sendFlowMessageViewModel.FlowButtonText;
flowMessageRequest.Interactive.Action.Parameters.FlowAction = sendFlowMessageViewModel.SelectedFlowAction;
flowMessageRequest.Interactive.Action.Parameters.IsInDraftMode = (sendFlowMessageViewModel.SelectedMode.Equals("Draft", StringComparison.OrdinalIgnoreCase));

flowMessageRequest.Interactive.Action.Parameters.FlowActionPayload = new FlowActionPayload();
flowMessageRequest.Interactive.Action.Parameters.FlowActionPayload.Screen = sendFlowMessageViewModel.ScreenId;

var results = await _whatsAppBusinessClient.SendFlowMessageAsync(flowMessageRequest);

return RedirectToAction(nameof(Index)).WithSuccess("Success", "Successfully sent flow message");
}
catch (WhatsappBusinessCloudAPIException ex)
{
_logger.LogError(ex, ex.Message);
return RedirectToAction(nameof(SendWhatsAppFlowMessage)).WithDanger("Error", ex.Message);
}
}

public IActionResult SendWhatsAppTemplateMessage()
{
return View();
Expand Down Expand Up @@ -1156,6 +1214,57 @@ public async Task<IActionResult> SendWhatsAppLimitedTimeOfferTemplateMessage(Sen
}
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SendWhatsAppFlowTemplateMessage(SendTemplateMessageViewModel sendTemplateMessageViewModel)
{
try
{
FlowTemplateMessageRequest flowTemplateMessageRequest = new FlowTemplateMessageRequest();
flowTemplateMessageRequest.To = sendTemplateMessageViewModel.RecipientPhoneNumber;
flowTemplateMessageRequest.Template = new();
flowTemplateMessageRequest.Template.Name = sendTemplateMessageViewModel.TemplateName;
flowTemplateMessageRequest.Template.Language = new();
flowTemplateMessageRequest.Template.Language.Code = LanguageCode.English_US;
flowTemplateMessageRequest.Template.Components = new List<FlowMessageComponent>()
{
new FlowMessageComponent()
{
Type = "button",
SubType = "flow",
Index = 0,
Parameters = new List<FlowTemplateMessageParameter>()
{
new FlowTemplateMessageParameter()
{
Type = "action",
Action = new FlowTemplateMessageAction()
{
FlowToken = "",
}
}
}
}
};

var results = await _whatsAppBusinessClient.SendFlowMessageTemplateAsync(flowTemplateMessageRequest);

if (results != null)
{
return RedirectToAction(nameof(Index)).WithSuccess("Success", "Successfully sent flow template message");
}
else
{
return RedirectToAction(nameof(SendWhatsAppTemplateMessage));
}
}
catch (WhatsappBusinessCloudAPIException ex)
{
_logger.LogError(ex, ex.Message);
return RedirectToAction(nameof(SendWhatsAppTemplateMessage)).WithDanger("Error", ex.Message);
}
}

public IActionResult SendWhatsAppContactMessage()
{
return View();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Microsoft.AspNetCore.Mvc.Rendering;

namespace WhatsAppBusinessCloudAPI.Web.ViewModel
{
public class SendFlowMessageViewModel
{
public string RecipientPhoneNumber { get; set; }
public List<SelectListItem> FlowAction { get; set; }
public string SelectedFlowAction { get; set; }
public List<SelectListItem> Mode { get; set; }
public string SelectedMode { get; set; }
public string ScreenId { get; set; }
public string FlowToken { get; set; }
public string FlowId { get; set; }
public string FlowButtonText { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
@model SendFlowMessageViewModel
@{
ViewData["Title"] = "Send WhatsApp Flow Message Page";
ViewData["CurrentPage"] = "Send WhatsApp Flow Message";
Layout = "~/Views/Shared/AdminLTE/_AdminLayout.cshtml";
ViewData["ControllerName"] = nameof(HomeController).Replace("Controller", "");
ViewData["ActionName"] = nameof(HomeController.SendWhatsAppTextMessage);
}

<section class="content">
<div class="row">
<div class="col-12">
<div class="card card-info">
<div class="card-header">
<h3 class="card-title">Send WhatsApp Text Message</h3>
</div> <!--/. card-header -->
<!--Form start -->
<form asp-action="SendWhatsAppTextMessage">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="card-body">
<div class="form-group">
<label class="control-label">Recipient Phone Number</label>
<input asp-for="RecipientPhoneNumber" class="form-control" />
<span asp-validation-for="RecipientPhoneNumber" class="form-control" />
</div>
<div class="form-group">
<label class="control-label">Flow Action</label>
<select class="form-control form-select form-select-lg mb-3" asp-for="SelectedFlowAction" asp-items="@Model.FlowAction"></select>
<span asp-validation-for="SelectedFlowAction" class="form-control" />
</div>
<div class="form-group">
<label class="control-label">Mode</label>
<select class="form-control form-select form-select-lg mb-3" asp-for="SelectedMode" asp-items="@Model.Mode"></select>
<span asp-validation-for="SelectedMode" class="form-control" />
</div>
<div class="form-group">
<label class="control-label">Screen Name or Id</label>
<input asp-for="ScreenId" class="form-control" />
<span asp-validation-for="ScreenId" class="form-control" />
</div>
<div class="form-group">
<label class="control-label">Flow Token</label>
<input asp-for="FlowToken" class="form-control" />
<span asp-validation-for="FlowToken" class="form-control" />
</div>
<div class="form-group">
<label class="control-label">Flow Id</label>
<input asp-for="FlowId" class="form-control" />
<span asp-validation-for="FlowId" class="form-control" />
</div>
<div class="form-group">
<label class="control-label">Flow Button Text</label>
<input asp-for="FlowButtonText" class="form-control" />
<span asp-validation-for="FlowButtonText" class="form-control" />
</div>
</div> <!--/. card-body -->
<div class="card-footer">
<button type="submit" name="submit" class="btn btn-primary">Send Message</button>
</div>
</form>
</div> <!-- /.card -->
</div>
</div>
</section>

@section Scripts {
@{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@
<button asp-action="SendWhatsAppCatalogueTemplateMessage" asp-controller="Home" class="btn btn-primary">Send Catalogue Template Message</button>
<button asp-action="SendWhatsAppCarouselTemplateMessage" asp-controller="Home" class="btn btn-primary">Send Carousel Template Message</button>
<button asp-action="SendWhatsAppCouponCodeTemplateMessage" asp-controller="Home" class="btn btn-primary">Send Coupon Code Template Message</button>
<button asp_action="SendWhatsAppLimitedTimeOfferTemplateMessage" asp-controller="Home" class="btn btn-primary">Send Limited Time Offer Message</button>
<button asp_action="SendWhatsAppLimitedTimeOfferTemplateMessage" asp-controller="Home" class="btn btn-primary">Send Limited Time Offer Template Message</button>
<button asp_action="SendWhatsAppFlowTemplateMessage" asp-controller="Home" class="btn btn-primary">Send Flow Template Message</button>
</div>
</div>
</form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.11" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="7.0.13" />
</ItemGroup>

<ItemGroup>
Expand Down
38 changes: 37 additions & 1 deletion WhatsappBusiness.CloudApi/Interfaces/IWhatsAppBusinessClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,43 @@ public interface IWhatsAppBusinessClient
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>WhatsAppResponse</returns>
WhatsAppResponse SendLimitedTimeOfferMessageTemplate(LimitedTimeOfferTemplateMessageRequest limitedTimeOfferTemplateMessageRequest, WhatsAppBusinessCloudApiConfig? cloudApiConfig = null, CancellationToken cancellationToken = default);
#endregion

/// <summary>
/// Send Whatsapp Flow Messages
/// </summary>
/// <param name="flowMessageRequest">FlowMessageRequest object</param>
/// <param name="cloudApiConfig">Custom WhatsAppBusinessCloudApiConfig</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>FlowMessageResponse</returns>
Task<FlowMessageResponse> SendFlowMessageAsync(FlowMessageRequest flowMessageRequest, WhatsAppBusinessCloudApiConfig? cloudApiConfig = null, CancellationToken cancellationToken = default);

/// <summary>
/// Send Whatsapp Flow Messages
/// </summary>
/// <param name="flowMessageRequest">FlowMessageRequest object</param>
/// <param name="cloudApiConfig">Custom WhatsAppBusinessCloudApiConfig</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>FlowMessageResponse</returns>
FlowMessageResponse SendFlowMessage(FlowMessageRequest flowMessageRequest, WhatsAppBusinessCloudApiConfig? cloudApiConfig = null, CancellationToken cancellationToken = default);

/// <summary>
/// Send Whatsapp Flow Template Messages
/// </summary>
/// <param name="flowTemplateMessageRequest">FlowTemplateMessageRequest object</param>
/// <param name="cloudApiConfig">Custom WhatsAppBusinessCloudApiConfig</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>WhatsAppResponse</returns>
Task<WhatsAppResponse> SendFlowMessageTemplateAsync(FlowTemplateMessageRequest flowTemplateMessageRequest, WhatsAppBusinessCloudApiConfig? cloudApiConfig = null, CancellationToken cancellationToken = default);

/// <summary>
/// Send Whatsapp Flow Template Messages
/// </summary>
/// <param name="flowTemplateMessageRequest">FlowTemplateMessageRequest object</param>
/// <param name="cloudApiConfig">Custom WhatsAppBusinessCloudApiConfig</param>
/// <param name="cancellationToken">Cancellation token</param>
/// <returns>WhatsAppResponse</returns>
WhatsAppResponse SendFlowMessageTemplate(FlowTemplateMessageRequest flowTemplateMessageRequest, WhatsAppBusinessCloudApiConfig? cloudApiConfig = null, CancellationToken cancellationToken = default);
#endregion

#region Two step verification code function
/// <summary>
Expand Down
117 changes: 117 additions & 0 deletions WhatsappBusiness.CloudApi/Messages/Requests/FlowMessageRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using Newtonsoft.Json;

namespace WhatsappBusiness.CloudApi.Messages.Requests
{
public class FlowMessageRequest
{
[JsonProperty("recipient_type")]
public string RecipientType { get; private set; } = "individual";

[JsonProperty("messaging_product")]
public string MessagingProduct { get; private set; } = "whatsapp";

[JsonProperty("to")]
public string To { get; set; }

[JsonProperty("type")]
public string Type { get; private set; } = "interactive";

[JsonProperty("interactive")]
public FlowMessageInteractive Interactive { get; set; }
}

public class FlowMessageInteractive
{
[JsonProperty("type")]
public string Type { get; private set; } = "flow";

[JsonProperty("header")]
public FlowMessageHeader Header { get; set; }

[JsonProperty("body")]
public FlowMessageBody Body { get; set; }

[JsonProperty("footer")]
public FlowMessageFooter Footer { get; set; }

[JsonProperty("action")]
public FlowMessageAction Action { get; set; }
}

public class FlowMessageAction
{
[JsonProperty("name")]
public string Name { get; private set; } = "flow";

[JsonProperty("parameters")]
public FlowMessageParameters Parameters { get; set; }
}

public class FlowMessageParameters
{
[JsonProperty("flow_message_version")]
public string FlowMessageVersion { get; private set; } = "3";

[JsonProperty("flow_token")]
public string FlowToken { get; set; }

[JsonProperty("flow_id")]
public string FlowId { get; set; }

[JsonProperty("flow_cta")]
public string FlowCta { get; set; }

[JsonProperty("flow_action")]
public string FlowAction { get; set; }

[JsonProperty("flow_action_payload")]
public FlowActionPayload FlowActionPayload { get; set; }

[JsonIgnore]
public bool IsInDraftMode { get; set; }

[JsonProperty("mode", NullValueHandling = NullValueHandling.Ignore)]
public string Mode { get; set; }

public bool ShouldSerializeMode()
{
// Only to be used for sending flows that have draft mode do not set this property when sending published flow messages
return IsInDraftMode;
}

public bool ShouldSerializeFlowActionPayload()
{
return FlowAction.Equals("navigate", System.StringComparison.OrdinalIgnoreCase);
}
}

public class FlowActionPayload
{
[JsonProperty("screen")]
public string Screen { get; set; }

[JsonProperty("data")]
public object Data { get; set; }
}

public class FlowMessageBody
{
[JsonProperty("text")]
public string Text { get; set; }
}

public class FlowMessageFooter
{
[JsonProperty("text")]
public string Text { get; set; }
}

public class FlowMessageHeader
{
[JsonProperty("type")]
public string Type { get; set; }

[JsonProperty("text")]
public string Text { get; set; }
}
}
Loading

0 comments on commit a6094c7

Please sign in to comment.