Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions blog-samples/CSharp/FacebookHandover/FacebookHandover.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28803.452
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Primary", "Primary\Primary.csproj", "{065B80D0-7968-4E61-B0F6-D04165912FF6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Secondary", "Secondary\Secondary.csproj", "{57786F2D-4C81-4FDF-9011-55652A78DF0B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Release|Any CPU.Build.0 = Release|Any CPU
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6876B9B2-5C7C-41B7-A624-EFB8D070BD4A}
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace FacebookModel
{
/// <summary>
/// A Facebook thread control message, including appid of the new thread owner and an optional message to sent with the request
/// <see cref="FacebookRequestThreadControl.Metadata"/>
/// </summary>
public class FacebookPassThreadControl
{
/// <summary>
/// The app id of the new owner.
/// </summary>
/// <remarks>
/// 263902037430900 for the page inbox.
/// </remarks>
[JsonProperty("new_owner_app_id")]
public string NewOwnerAppId;

/// <summary>
/// Message sent from the requester.
/// </summary>
/// <remarks>
/// Example: "i want the control!"
/// </remarks>
[JsonProperty("metadata")]
public string Metadata;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Newtonsoft.Json;

namespace FacebookModel
{
/// <summary>
/// Simple version of the payload received from the Facebook channel.
/// </summary>
public class FacebookPayload
{
/// <summary>
/// Gets or sets the sender of the message.
/// </summary>
[JsonProperty("sender")]
public FacebookPsid Sender { get; set; }

/// <summary>
/// Gets or sets the recipient of the message.
/// </summary>
[JsonProperty("recipient")]
public FacebookPsid Recipient { get; set; }

/// <summary>
/// Gets or sets the request_thread_control of the control request.
/// </summary>
[JsonProperty("request_thread_control")]
public FacebookRequestThreadControl RequestThreadControl;

/// <summary>
/// Gets or sets the pass_thread_control of the control request.
/// </summary>
[JsonProperty("pass_thread_control")]
public FacebookPassThreadControl PassThreadControl;

/// <summary>
/// Gets or sets the take_thread_control of the control request.
/// </summary>
[JsonProperty("take_thread_control")]
public FacebookTakeThreadControl TakeThreadControl;
}
}
19 changes: 19 additions & 0 deletions blog-samples/CSharp/FacebookHandover/FacebookModel/FacebookPsid.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Newtonsoft.Json;

namespace FacebookModel
{
/// <summary>
/// Defines a Facebook PSID.
/// </summary>
public class FacebookPsid
{
/// <summary>
/// A Facebook page-scoped ID.
/// </summary>
[JsonProperty("id")]
public string Id { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace FacebookModel
{
/// <summary>
/// A Facebook thread control message, including appid of requested thread owner and an optional message to send with the request
/// <see cref="Metadata"/>
/// </summary>
public class FacebookRequestThreadControl
{
/// <summary>
/// The app id of the requested owner.
/// </summary>
/// <remarks>
/// 263902037430900 for the page inbox.
/// </remarks>
[JsonProperty("requested_owner_app_id")]
public string RequestedOwnerAppId; // 263902037430900 for page

/// <summary>
/// Message sent from the requester.
/// </summary>
/// <remarks>
/// Example: "i want the control!"
/// </remarks>
[JsonProperty("metadata")]
public string Metadata;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using Newtonsoft.Json;

namespace FacebookModel
{
/// <summary>
/// A Facebook stanby event payload definition.
/// </summary>
/// <remarks>See <see cref="https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/standby/"> messaging standby Facebook documentation</see>
/// for more information on standby.</remarks>
public class FacebookStandbys
{
[JsonProperty("id")]
public string Id;
[JsonProperty("time")]
public long Time;
[JsonProperty("standBy")]
public FacebookStandby[] Standbys;
}

public class FacebookStandby
{
[JsonProperty("sender")]
public FacebookPsid Sender;
[JsonProperty("recipient")]
public FacebookPsid Recipient;
[JsonProperty("timestamp")]
public long Timestamp;
[JsonProperty("message")]
public FacebookStandByMessage Message;
}

public class FacebookStandByMessage
{
[JsonProperty("mid")]
public string MId;
[JsonProperty("seq")]
public long Seq;
[JsonProperty("text")]
public string Text;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace FacebookModel
{
/// <summary>
/// A Facebook thread control message, including appid of the previous thread owner and an optional message sent with the request
/// <see cref="FacebookRequestThreadControl.Metadata"/>
/// </summary>
public class FacebookTakeThreadControl
{
/// <summary>
/// The app id of the previous owner.
/// </summary>
/// <remarks>
/// 263902037430900 for the page inbox.
/// </remarks>
[JsonProperty("previous_owner_app_id")]
public string PreviousOwnerAppId;

/// <summary>
/// Message sent from the requester.
/// </summary>
/// <remarks>
/// Example: "All yours!"
/// </remarks>
[JsonProperty("metadata")]
public string Metadata;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace FacebookModel
{
public static class FacebookThreadControlHelper
{
public const string GRAPH_API_BASE_URL = "https://graph.facebook.com/v3.3/me/{0}?access_token={1}";

private static readonly HttpClient _httpClient = new HttpClient();

private static async Task<bool> PostToFacebookAPIAsync(string postType, string pageToken, string content)
{
var requestPath = string.Format(GRAPH_API_BASE_URL, postType, pageToken);
var stringContent = new StringContent(content, Encoding.UTF8, "application/json");

// Create HTTP transport objects
using (var requestMessage = new HttpRequestMessage())
{
requestMessage.Method = new HttpMethod("POST");
requestMessage.RequestUri = new Uri(requestPath);
requestMessage.Content = stringContent;
requestMessage.Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8");

// Make the Http call
using (var response = await _httpClient.SendAsync(requestMessage, CancellationToken.None).ConfigureAwait(false))
{
// Return true if the call was successfull
Debug.Print(await response.Content.ReadAsStringAsync().ConfigureAwait(false));
return response.IsSuccessStatusCode;
}
}
}

public static async Task<List<string>> GetSecondaryReceiversAsync(string pageToken)
{
var requestPath = string.Format(GRAPH_API_BASE_URL, "secondary_receivers", pageToken);

// Create HTTP transport objects
using (var requestMessage = new HttpRequestMessage())
{
requestMessage.Method = new HttpMethod("GET");
requestMessage.RequestUri = new Uri(requestPath);

// Make the Http call
using (var response = await _httpClient.SendAsync(requestMessage, CancellationToken.None).ConfigureAwait(false))
{
// Interpret response
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var responseObject = JObject.Parse(responseString);
var responseData = responseObject["data"] as JArray;

return responseData.Select(receiver => receiver["id"].ToString()).ToList();
}
}
}

public static async Task<bool> RequestThreadControlAsync(string pageToken, string userId, string message)
{
var content = new { recipient = new { id = userId }, metadata = message };
return await PostToFacebookAPIAsync("request_thread_control", pageToken, JsonConvert.SerializeObject(content)).ConfigureAwait(false);
}

public static async Task<bool> TakeThreadControlAsync(string pageToken, string userId, string message)
{
var content = new { recipient = new { id = userId }, metadata = message };
return await PostToFacebookAPIAsync("take_thread_control", pageToken, JsonConvert.SerializeObject(content)).ConfigureAwait(false);
}

public static async Task<bool> PassThreadControlAsync(string pageToken, string targetAppId, string userId, string message)
{
var content = new { recipient = new { id = userId }, target_app_id = targetAppId, metadata = message };
return await PostToFacebookAPIAsync("pass_thread_control", pageToken, JsonConvert.SerializeObject(content)).ConfigureAwait(false);
}

/// <summary>
/// This extension method populates a turn context's activity with conversation and user information from a Facebook payload.
/// This is necessary because a turn context needs that information to send messages to a conversation,
/// and event activities don't necessarily come with that information already in place.
/// </summary>
public static void ApplyFacebookPayload(this ITurnContext turnContext, FacebookPayload facebookPayload)
{
var userId = facebookPayload.Sender.Id;
var pageId = facebookPayload.Recipient.Id;
var conversationId = string.Format("{0}-{1}", userId, pageId);

turnContext.Activity.From = new ChannelAccount(userId);
turnContext.Activity.Recipient = new ChannelAccount(pageId);
turnContext.Activity.Conversation = new ConversationAccount(id: conversationId);
}
}
}
Loading