public static async Task <bool> DoExport(Options opts) { IBotDataStore <BotData> targetStore = null; StreamWriter outputFile = null; switch (opts.Destination.ToLower()) { case "cosmos": if (string.IsNullOrEmpty(opts.CosmosDbKey) || string.IsNullOrEmpty(opts.CosmosDbUrl)) { Console.WriteLine("Both CosmosDb Key and Url are required in order to copy to a new database"); return(false); } try { targetStore = new Microsoft.Bot.Builder.Azure.DocumentDbBotDataStore(new Uri(opts.CosmosDbUrl), opts.CosmosDbKey); } catch (Exception e) { Console.WriteLine($"Problem initializing cosmos DB: {e}"); throw; } break; case "file": if (string.IsNullOrEmpty(opts.FileName)) { Console.WriteLine("FileName must be specified."); return(false); } try { outputFile = new StreamWriter(opts.FileName); } catch { Console.WriteLine($"Error creating output file {opts.FileName}."); } outputFile.WriteLine("{\r\n"); break; case "table": if (string.IsNullOrEmpty(opts.ConnectionString)) { Console.WriteLine("ConnectionString must be set for Azure Storage Table"); return(false); } try { targetStore = new Microsoft.Bot.Builder.Azure.TableBotDataStore(opts.ConnectionString); } catch (Exception e) { Console.WriteLine($"Problem initializing Azure Storage Table: {e}"); throw; } break; default: Console.WriteLine($"undefined destination type: {opts.Destination}"); break; } if (opts.Destination.ToLower() == "cosmos") { if (string.IsNullOrEmpty(opts.CosmosDbKey) || string.IsNullOrEmpty(opts.CosmosDbUrl)) { Console.WriteLine("Both CosmosDb Key and Url are required in order to copy to a new database"); return(false); } try { targetStore = new Microsoft.Bot.Builder.Azure.DocumentDbBotDataStore(new Uri(opts.CosmosDbUrl), opts.CosmosDbKey); } catch (Exception e) { Console.WriteLine($"Problem initializing cosmos DB: {e}"); throw; } } else if (opts.Destination.ToLower() == "table") { if (string.IsNullOrEmpty(opts.ConnectionString)) { Console.WriteLine("ConnectionString must be set for Azure Storage Table"); return(false); } try { targetStore = new Microsoft.Bot.Builder.Azure.TableBotDataStore(opts.ConnectionString); } catch (Exception e) { Console.WriteLine($"Problem initializing Azure Storage Table: {e}"); throw; } } var credentials = new MicrosoftAppCredentials(opts.AppId, opts.AppPassword); var botId = opts.BotId; var stateUrl = new Uri(opts.StateUrl); var serviceUrl = "https://store.botframework.com"; MicrosoftAppCredentials.TrustServiceUrl(stateUrl.AbsoluteUri); string continuationToken = ""; var client = new StateClient(stateUrl, credentials); var state = client.BotState; BotStateDataResult stateResult = null; foreach (var channelId in KnownChannelsIds) { Console.WriteLine($"***{channelId}***"); continuationToken = ""; do { try { // should work with "directline", "facebook", or "kik" stateResult = await BotStateExtensions.ExportBotStateDataAsync(state, channelId, continuationToken).ConfigureAwait(false); foreach (var datum in stateResult.BotStateData) { if ((DateTime.UtcNow - datum.LastModified).HasValue && (DateTime.UtcNow - datum.LastModified).Value.Days < 1) { Console.WriteLine($"LastModified: {datum.LastModified}, UsserId: {datum.UserId}"); } if (datum.Data != "{}") { Console.WriteLine($"conversationID: {datum.ConversationId}\tuserId: {datum.UserId}\tdata:{datum.Data}\n"); if (targetStore != null) { var cancellationToken = new CancellationToken(); var address = new Microsoft.Bot.Builder.Dialogs.Address(botId, channelId, datum.UserId, datum.ConversationId, serviceUrl); var botStoreType = string.IsNullOrEmpty(datum.ConversationId) ? BotStoreType.BotUserData : BotStoreType.BotPrivateConversationData; var botData = new BotData { Data = datum.Data }; await targetStore.SaveAsync(address, botStoreType, botData, cancellationToken); } else if (outputFile != null) { var id = new StringBuilder(); id.Append($"{channelId}:"); if (!string.IsNullOrEmpty(datum.ConversationId)) { id.Append($"private{datum.ConversationId}:"); } id.Append(datum.UserId); var serializedData = JsonConvert.SerializeObject(datum.Data); var outputValue = $"\t{{\r\n\t\"id\": \"{id.ToString()}\",\r\n" + $"\t\t\"botId\": \"{botId}\",\r\n" + $"\t\t\"channelId\": \"{channelId}\",\r\n" + $"\t\t\"conversationId\": \"{datum.ConversationId}\",\r\n" + $"\t\t\"userId\": \"{datum.UserId}\",\r\n" + $"\t\t\"data\": {serializedData}\r\n\t}},\r\n"; outputFile.Write(outputValue); } } } continuationToken = stateResult.ContinuationToken; } catch (Exception e) { var errorException = e as ErrorResponseException; if (errorException?.Body?.Error?.Message?.ToLower() == "channel not configured for bot") { continue; } Console.WriteLine(e); } } while (!string.IsNullOrEmpty(continuationToken)); } Console.Write("Press Enter key to continue:"); Console.Read(); if (outputFile != null) { outputFile.WriteLine("}\r\n"); outputFile.Flush(); outputFile.Close(); } // TODO: Do I need to flush the targetStore? If so, what Address should I use? return(true); }
public static async Task <bool> DoExport() { // REPLACE with REAL APPID and PASSWORD var credentials = new MicrosoftAppCredentials("MsAppId", "MsAppPassword"); StringBuilder outputMessage = new StringBuilder(); string continuationToken = ""; // REPLACE with bot framework API var stateUrl = new Uri("https://intercom-api-scratch.azurewebsites.net"); MicrosoftAppCredentials.TrustServiceUrl(stateUrl.AbsoluteUri); var client = new StateClient(stateUrl, credentials); var state = client.BotState; BotStateDataResult stateResult = null; do { try { // should work with "directline", "facebook", or "kik" stateResult = await BotStateExtensions.ExportBotStateDataAsync(state, "directline", continuationToken).ConfigureAwait(false); foreach (var datum in stateResult.BotStateData) { outputMessage.Append($"conversationID: {datum.ConversationId}\tuserId: {datum.UserId}\tdata:{datum.Data}\n"); // If you were exporting into a new bot state store, here is where you would write the data //if (string.IsNullOrEmpty(datum.ConversationId)) //{ // // use SetUserData(datum.UserId, data.Data); //} //else //{ // SetPrivateConversationData(datum.UserId, datum.ConversationId, datum.Data); //} } continuationToken = stateResult.ContinuationToken; } catch (Exception e) { Console.WriteLine(e); } } while (!string.IsNullOrEmpty(continuationToken)); Console.WriteLine(outputMessage.ToString()); continuationToken = null; outputMessage = new StringBuilder(); // REPLACE with channel's URL. var connectionsUrl = new Uri("http://ic-directline-scratch.azurewebsites.net"); MicrosoftAppCredentials.TrustServiceUrl(connectionsUrl.AbsoluteUri); var connectorClient = new ConnectorClient(connectionsUrl, credentials); var conversations = connectorClient.Conversations; ConversationsResult conversationResults = null; do { try { conversationResults = await conversations.GetConversationsAsync(continuationToken).ConfigureAwait(false); if (conversationResults == null) { outputMessage.Append("Internal error, conversation results was empty"); } else if (conversationResults.Conversations == null) { outputMessage.Append("No conversations found for this bot in this channel"); } else { outputMessage.Append($"Here is a batch of {conversationResults.Conversations.Count} conversations:\n"); foreach (var conversationMembers in conversationResults.Conversations) { string members = string.Join(", ", conversationMembers.Members.Select(member => member.Id)); outputMessage.Append($"Conversation: {conversationMembers.Id} members: {members}\n"); } } } catch (Exception e) { Console.WriteLine(e); } continuationToken = conversationResults?.Skip; // should be ContinuationToken (this version is built on an old library } while (!string.IsNullOrEmpty(continuationToken)); Console.WriteLine(outputMessage.ToString()); return(true); }