Skip to content

Commit 9f50056

Browse files
Kyle DelaneyKaiqb
authored andcommitted
Facebook handover (#70)
1 parent 5c67ab0 commit 9f50056

31 files changed

Lines changed: 2638 additions & 0 deletions
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.28803.452
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Primary", "Primary\Primary.csproj", "{065B80D0-7968-4E61-B0F6-D04165912FF6}"
7+
EndProject
8+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Secondary", "Secondary\Secondary.csproj", "{57786F2D-4C81-4FDF-9011-55652A78DF0B}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{065B80D0-7968-4E61-B0F6-D04165912FF6}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{57786F2D-4C81-4FDF-9011-55652A78DF0B}.Release|Any CPU.Build.0 = Release|Any CPU
24+
EndGlobalSection
25+
GlobalSection(SolutionProperties) = preSolution
26+
HideSolutionNode = FALSE
27+
EndGlobalSection
28+
GlobalSection(ExtensibilityGlobals) = postSolution
29+
SolutionGuid = {6876B9B2-5C7C-41B7-A624-EFB8D070BD4A}
30+
EndGlobalSection
31+
EndGlobal
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Newtonsoft.Json;
6+
7+
namespace FacebookModel
8+
{
9+
/// <summary>
10+
/// A Facebook thread control message, including appid of the new thread owner and an optional message to sent with the request
11+
/// <see cref="FacebookRequestThreadControl.Metadata"/>
12+
/// </summary>
13+
public class FacebookPassThreadControl
14+
{
15+
/// <summary>
16+
/// The app id of the new owner.
17+
/// </summary>
18+
/// <remarks>
19+
/// 263902037430900 for the page inbox.
20+
/// </remarks>
21+
[JsonProperty("new_owner_app_id")]
22+
public string NewOwnerAppId;
23+
24+
/// <summary>
25+
/// Message sent from the requester.
26+
/// </summary>
27+
/// <remarks>
28+
/// Example: "i want the control!"
29+
/// </remarks>
30+
[JsonProperty("metadata")]
31+
public string Metadata;
32+
}
33+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Newtonsoft.Json;
5+
6+
namespace FacebookModel
7+
{
8+
/// <summary>
9+
/// Simple version of the payload received from the Facebook channel.
10+
/// </summary>
11+
public class FacebookPayload
12+
{
13+
/// <summary>
14+
/// Gets or sets the sender of the message.
15+
/// </summary>
16+
[JsonProperty("sender")]
17+
public FacebookPsid Sender { get; set; }
18+
19+
/// <summary>
20+
/// Gets or sets the recipient of the message.
21+
/// </summary>
22+
[JsonProperty("recipient")]
23+
public FacebookPsid Recipient { get; set; }
24+
25+
/// <summary>
26+
/// Gets or sets the request_thread_control of the control request.
27+
/// </summary>
28+
[JsonProperty("request_thread_control")]
29+
public FacebookRequestThreadControl RequestThreadControl;
30+
31+
/// <summary>
32+
/// Gets or sets the pass_thread_control of the control request.
33+
/// </summary>
34+
[JsonProperty("pass_thread_control")]
35+
public FacebookPassThreadControl PassThreadControl;
36+
37+
/// <summary>
38+
/// Gets or sets the take_thread_control of the control request.
39+
/// </summary>
40+
[JsonProperty("take_thread_control")]
41+
public FacebookTakeThreadControl TakeThreadControl;
42+
}
43+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Newtonsoft.Json;
5+
6+
namespace FacebookModel
7+
{
8+
/// <summary>
9+
/// Defines a Facebook PSID.
10+
/// </summary>
11+
public class FacebookPsid
12+
{
13+
/// <summary>
14+
/// A Facebook page-scoped ID.
15+
/// </summary>
16+
[JsonProperty("id")]
17+
public string Id { get; set; }
18+
}
19+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Newtonsoft.Json;
6+
7+
namespace FacebookModel
8+
{
9+
/// <summary>
10+
/// A Facebook thread control message, including appid of requested thread owner and an optional message to send with the request
11+
/// <see cref="Metadata"/>
12+
/// </summary>
13+
public class FacebookRequestThreadControl
14+
{
15+
/// <summary>
16+
/// The app id of the requested owner.
17+
/// </summary>
18+
/// <remarks>
19+
/// 263902037430900 for the page inbox.
20+
/// </remarks>
21+
[JsonProperty("requested_owner_app_id")]
22+
public string RequestedOwnerAppId; // 263902037430900 for page
23+
24+
/// <summary>
25+
/// Message sent from the requester.
26+
/// </summary>
27+
/// <remarks>
28+
/// Example: "i want the control!"
29+
/// </remarks>
30+
[JsonProperty("metadata")]
31+
public string Metadata;
32+
}
33+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Newtonsoft.Json;
5+
6+
namespace FacebookModel
7+
{
8+
/// <summary>
9+
/// A Facebook stanby event payload definition.
10+
/// </summary>
11+
/// <remarks>See <see cref="https://developers.facebook.com/docs/messenger-platform/reference/webhook-events/standby/"> messaging standby Facebook documentation</see>
12+
/// for more information on standby.</remarks>
13+
public class FacebookStandbys
14+
{
15+
[JsonProperty("id")]
16+
public string Id;
17+
[JsonProperty("time")]
18+
public long Time;
19+
[JsonProperty("standBy")]
20+
public FacebookStandby[] Standbys;
21+
}
22+
23+
public class FacebookStandby
24+
{
25+
[JsonProperty("sender")]
26+
public FacebookPsid Sender;
27+
[JsonProperty("recipient")]
28+
public FacebookPsid Recipient;
29+
[JsonProperty("timestamp")]
30+
public long Timestamp;
31+
[JsonProperty("message")]
32+
public FacebookStandByMessage Message;
33+
}
34+
35+
public class FacebookStandByMessage
36+
{
37+
[JsonProperty("mid")]
38+
public string MId;
39+
[JsonProperty("seq")]
40+
public long Seq;
41+
[JsonProperty("text")]
42+
public string Text;
43+
}
44+
45+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
using Newtonsoft.Json;
6+
7+
namespace FacebookModel
8+
{
9+
/// <summary>
10+
/// A Facebook thread control message, including appid of the previous thread owner and an optional message sent with the request
11+
/// <see cref="FacebookRequestThreadControl.Metadata"/>
12+
/// </summary>
13+
public class FacebookTakeThreadControl
14+
{
15+
/// <summary>
16+
/// The app id of the previous owner.
17+
/// </summary>
18+
/// <remarks>
19+
/// 263902037430900 for the page inbox.
20+
/// </remarks>
21+
[JsonProperty("previous_owner_app_id")]
22+
public string PreviousOwnerAppId;
23+
24+
/// <summary>
25+
/// Message sent from the requester.
26+
/// </summary>
27+
/// <remarks>
28+
/// Example: "All yours!"
29+
/// </remarks>
30+
[JsonProperty("metadata")]
31+
public string Metadata;
32+
}
33+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Linq;
5+
using System.Net.Http;
6+
using System.Text;
7+
using System.Threading;
8+
using System.Threading.Tasks;
9+
using Microsoft.Bot.Builder;
10+
using Microsoft.Bot.Schema;
11+
using Newtonsoft.Json;
12+
using Newtonsoft.Json.Linq;
13+
14+
namespace FacebookModel
15+
{
16+
public static class FacebookThreadControlHelper
17+
{
18+
public const string GRAPH_API_BASE_URL = "https://graph.facebook.com/v3.3/me/{0}?access_token={1}";
19+
20+
private static readonly HttpClient _httpClient = new HttpClient();
21+
22+
private static async Task<bool> PostToFacebookAPIAsync(string postType, string pageToken, string content)
23+
{
24+
var requestPath = string.Format(GRAPH_API_BASE_URL, postType, pageToken);
25+
var stringContent = new StringContent(content, Encoding.UTF8, "application/json");
26+
27+
// Create HTTP transport objects
28+
using (var requestMessage = new HttpRequestMessage())
29+
{
30+
requestMessage.Method = new HttpMethod("POST");
31+
requestMessage.RequestUri = new Uri(requestPath);
32+
requestMessage.Content = stringContent;
33+
requestMessage.Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json; charset=utf-8");
34+
35+
// Make the Http call
36+
using (var response = await _httpClient.SendAsync(requestMessage, CancellationToken.None).ConfigureAwait(false))
37+
{
38+
// Return true if the call was successfull
39+
Debug.Print(await response.Content.ReadAsStringAsync().ConfigureAwait(false));
40+
return response.IsSuccessStatusCode;
41+
}
42+
}
43+
}
44+
45+
public static async Task<List<string>> GetSecondaryReceiversAsync(string pageToken)
46+
{
47+
var requestPath = string.Format(GRAPH_API_BASE_URL, "secondary_receivers", pageToken);
48+
49+
// Create HTTP transport objects
50+
using (var requestMessage = new HttpRequestMessage())
51+
{
52+
requestMessage.Method = new HttpMethod("GET");
53+
requestMessage.RequestUri = new Uri(requestPath);
54+
55+
// Make the Http call
56+
using (var response = await _httpClient.SendAsync(requestMessage, CancellationToken.None).ConfigureAwait(false))
57+
{
58+
// Interpret response
59+
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
60+
var responseObject = JObject.Parse(responseString);
61+
var responseData = responseObject["data"] as JArray;
62+
63+
return responseData.Select(receiver => receiver["id"].ToString()).ToList();
64+
}
65+
}
66+
}
67+
68+
public static async Task<bool> RequestThreadControlAsync(string pageToken, string userId, string message)
69+
{
70+
var content = new { recipient = new { id = userId }, metadata = message };
71+
return await PostToFacebookAPIAsync("request_thread_control", pageToken, JsonConvert.SerializeObject(content)).ConfigureAwait(false);
72+
}
73+
74+
public static async Task<bool> TakeThreadControlAsync(string pageToken, string userId, string message)
75+
{
76+
var content = new { recipient = new { id = userId }, metadata = message };
77+
return await PostToFacebookAPIAsync("take_thread_control", pageToken, JsonConvert.SerializeObject(content)).ConfigureAwait(false);
78+
}
79+
80+
public static async Task<bool> PassThreadControlAsync(string pageToken, string targetAppId, string userId, string message)
81+
{
82+
var content = new { recipient = new { id = userId }, target_app_id = targetAppId, metadata = message };
83+
return await PostToFacebookAPIAsync("pass_thread_control", pageToken, JsonConvert.SerializeObject(content)).ConfigureAwait(false);
84+
}
85+
86+
/// <summary>
87+
/// This extension method populates a turn context's activity with conversation and user information from a Facebook payload.
88+
/// This is necessary because a turn context needs that information to send messages to a conversation,
89+
/// and event activities don't necessarily come with that information already in place.
90+
/// </summary>
91+
public static void ApplyFacebookPayload(this ITurnContext turnContext, FacebookPayload facebookPayload)
92+
{
93+
var userId = facebookPayload.Sender.Id;
94+
var pageId = facebookPayload.Recipient.Id;
95+
var conversationId = string.Format("{0}-{1}", userId, pageId);
96+
97+
turnContext.Activity.From = new ChannelAccount(userId);
98+
turnContext.Activity.Recipient = new ChannelAccount(pageId);
99+
turnContext.Activity.Conversation = new ConversationAccount(id: conversationId);
100+
}
101+
}
102+
}

0 commit comments

Comments
 (0)