diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator.sln b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator.sln new file mode 100644 index 0000000000..5fd28ae3bb --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.2041 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotFileCreator", "BotFileCreator\BotFileCreator.csproj", "{90E69D82-3623-4AE8-9F25-3E4BB7362508}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {90E69D82-3623-4AE8-9F25-3E4BB7362508}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90E69D82-3623-4AE8-9F25-3E4BB7362508}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90E69D82-3623-4AE8-9F25-3E4BB7362508}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90E69D82-3623-4AE8-9F25-3E4BB7362508}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {63432931-989E-4E26-9D1B-F9C39DF3BD91} + EndGlobalSection +EndGlobal diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BaseDialogWindow.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BaseDialogWindow.cs new file mode 100644 index 0000000000..c7ab47d17a --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BaseDialogWindow.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace BotFileCreator +{ + using Microsoft.VisualStudio.PlatformUI; + + public class BaseDialogWindow : DialogWindow + { + public BaseDialogWindow() + { + this.HasMaximizeButton = true; + this.HasMinimizeButton = true; + } + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreator.csproj b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreator.csproj new file mode 100644 index 0000000000..237f65efc0 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreator.csproj @@ -0,0 +1,265 @@ + + + + + + 15.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + true + + + + true + + + Key.snk + + + + Debug + AnyCPU + 2.0 + {82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + {90E69D82-3623-4AE8-9F25-3E4BB7362508} + Library + Properties + BotFileCreator + BotFileCreator + v4.6.1 + true + true + true + true + true + false + Program + $(DevEnvDir)devenv.exe + /rootsuffix Exp + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + BotFileCreator.ruleset + SA1652, SA1124 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + BotFileCreator.ruleset + SA1652, SA1124 + + + + + + + + + + + + BotConfigurationView.xaml + + + + + True + True + GeneralSettings.settings + + + + + + + SettingsSingleFileGenerator + GeneralSettings1.Designer.cs + + + + Designer + + + + Designer + + + + + Menus.ctmenu + Designer + + + + Always + true + + + Always + true + + + + + + + + False + + + False + + + False + + + False + + + ..\packages\Microsoft.Bot.Configuration.4.2.2\lib\netstandard2.0\Microsoft.Bot.Configuration.dll + + + + + False + + + ..\packages\Microsoft.VisualStudio.CoreUtility.15.0.26228\lib\net45\Microsoft.VisualStudio.CoreUtility.dll + + + ..\packages\Microsoft.VisualStudio.Imaging.15.0.26228\lib\net45\Microsoft.VisualStudio.Imaging.dll + + + ..\packages\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.14.3.25408\lib\net20\Microsoft.VisualStudio.Imaging.Interop.14.0.DesignTime.dll + True + + + ..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6071\lib\Microsoft.VisualStudio.OLE.Interop.dll + + + ..\packages\Microsoft.VisualStudio.Shell.15.0.15.0.26228\lib\Microsoft.VisualStudio.Shell.15.0.dll + + + ..\packages\Microsoft.VisualStudio.Shell.Framework.15.0.26228\lib\net45\Microsoft.VisualStudio.Shell.Framework.dll + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.10.0.10.0.30319\lib\Microsoft.VisualStudio.Shell.Interop.10.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.11.0.11.0.61030\lib\Microsoft.VisualStudio.Shell.Interop.11.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.12.0.12.0.30110\lib\Microsoft.VisualStudio.Shell.Interop.12.0.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.14.3.25407\lib\Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll + True + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.Shell.Interop.8.0.dll + + + ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll + + + ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6070\lib\Microsoft.VisualStudio.TextManager.Interop.dll + + + ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.TextManager.Interop.8.0.dll + + + ..\packages\Microsoft.VisualStudio.Threading.15.0.240\lib\net45\Microsoft.VisualStudio.Threading.dll + + + ..\packages\Microsoft.VisualStudio.Utilities.15.0.26228\lib\net46\Microsoft.VisualStudio.Utilities.dll + + + ..\packages\Microsoft.VisualStudio.Validation.15.0.82\lib\net45\Microsoft.VisualStudio.Validation.dll + + + ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + + + + False + + + + + + + ..\packages\System.Threading.Tasks.Extensions.4.4.0\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + + + + + + + + + + + + + + + true + VSPackage + + + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreator.ruleset b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreator.ruleset new file mode 100644 index 0000000000..5d21abc2a7 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreator.ruleset @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreatorCommand.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreatorCommand.cs new file mode 100644 index 0000000000..99b04b4ac2 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreatorCommand.cs @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace BotFileCreator +{ + using System; + using System.ComponentModel.Design; + using System.Runtime.InteropServices; + using EnvDTE; + using Microsoft.VisualStudio; + using Microsoft.VisualStudio.Shell; + using Microsoft.VisualStudio.Shell.Interop; + using Task = System.Threading.Tasks.Task; + + /// + /// Command handler + /// + internal sealed class BotFileCreatorCommand + { + /// + /// Command ID. + /// + public const int CommandId = 0x0100; + + /// + /// Command menu group (command set GUID). + /// + public static readonly Guid CommandSet = new Guid("d217be97-bc71-44be-ae8e-9a297f2af054"); + + /// + /// VS Package that provides this command, not null. + /// + private readonly AsyncPackage package; + + /// + /// Initializes a new instance of the class. + /// Adds our command handlers for menu (commands must exist in the command table file) + /// + /// Owner package, not null. + /// Command service to add command to, not null. + private BotFileCreatorCommand(AsyncPackage package, OleMenuCommandService commandService) + { + this.package = package ?? throw new ArgumentNullException(nameof(package)); + commandService = commandService ?? throw new ArgumentNullException(nameof(commandService)); + + var menuCommandID = new CommandID(CommandSet, CommandId); + var menuItem = new MenuCommand(this.Execute, menuCommandID); + commandService.AddCommand(menuItem); + } + + /// + /// Gets the instance of the command. + /// + public static BotFileCreatorCommand Instance + { + get; + private set; + } + + /// + /// Gets the service provider from the owner package. + /// + private Microsoft.VisualStudio.Shell.IAsyncServiceProvider ServiceProvider + { + get + { + return this.package; + } + } + + /// + /// Initializes the singleton instance of the command. + /// + /// Owner package, not null. + public static async Task InitializeAsync(AsyncPackage package) + { + // Switch to the main thread - the call to AddCommand in BotFileCreatorCommand's constructor requires + // the UI thread. + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); + + OleMenuCommandService commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; + Instance = new BotFileCreatorCommand(package, commandService); + } + + /// + /// This function is the callback used to execute the command when the menu item is clicked. + /// See the constructor to see how the menu item is associated with this function using + /// OleMenuCommandService service and MenuCommand class. + /// + /// Event sender. + /// Event args. + private void Execute(object sender, EventArgs e) + { + ThreadHelper.ThrowIfNotOnUIThread(); + + /* + * This code gets the Project's name from where the Wizard/Visual Studio Extension is being called + * Is necessary to call these methods from the main thread + */ + IntPtr hierarchyPointer, selectionContainerPointer; + object selectedObject = null; + IVsMultiItemSelect multiItemSelect; + uint projectItemId; + + IVsMonitorSelection monitorSelection = (IVsMonitorSelection)Package.GetGlobalService(typeof(SVsShellMonitorSelection)); + + monitorSelection.GetCurrentSelection(out hierarchyPointer, out projectItemId, out multiItemSelect, out selectionContainerPointer); + + IVsHierarchy selectedHierarchy = Marshal.GetTypedObjectForIUnknown(hierarchyPointer, typeof(IVsHierarchy)) as IVsHierarchy; + + if (selectedHierarchy != null) + { + ErrorHandler.ThrowOnFailure(selectedHierarchy.GetProperty(projectItemId, (int)__VSHPROPID.VSHPROPID_ExtObject, out selectedObject)); + } + + Project selectedProject = selectedObject as Project; + + string projectPath = selectedProject.FullName; + + // Adds the project name to the Settings File to use it later. + GeneralSettings.Default.ProjectName = projectPath; + + // Starts the wizard + var botFileCreatorWizard = new BotFileCreationWizard(); + + botFileCreatorWizard.ShowDialog(); + + selectedProject.DTE.ExecuteCommand("Project.UnloadProject"); + selectedProject.DTE.ExecuteCommand("Project.ReloadProject"); + } + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreatorPackage.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreatorPackage.cs new file mode 100644 index 0000000000..c4d09696e1 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreatorPackage.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace BotFileCreator +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.InteropServices; + using System.Threading; + using Microsoft.VisualStudio.Shell; + using Task = System.Threading.Tasks.Task; + + /// + /// This is the class that implements the package exposed by this assembly. + /// + /// + /// + /// The minimum requirement for a class to be considered a valid package for Visual Studio + /// is to implement the IVsPackage interface and register itself with the shell. + /// This package uses the helper classes defined inside the Managed Package Framework (MPF) + /// to do it: it derives from the Package class that provides the implementation of the + /// IVsPackage interface and uses the registration attributes defined in the framework to + /// register itself and its components with the shell. These attributes tell the pkgdef creation + /// utility what data to put into .pkgdef file. + /// + /// + /// To get loaded into VS, the package must be referred by <Asset Type="Microsoft.VisualStudio.VsPackage" ...> in .vsixmanifest file. + /// + /// + [PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)] + [InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)] // Info on this package for Help/About + [Guid(BotFileCreatorPackage.PackageGuidString)] + [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "pkgdef, VS and vsixmanifest are valid VS terms")] + [ProvideMenuResource("Menus.ctmenu", 1)] + public sealed class BotFileCreatorPackage : AsyncPackage + { + /// + /// BotFileCreatorPackage GUID string. + /// + public const string PackageGuidString = "81cae91a-c890-4be2-8970-ff09441817cf"; + + /// + /// Initializes a new instance of the class. + /// + public BotFileCreatorPackage() + { + // Inside this method you can place any initialization code that does not require + // any Visual Studio service because at this point the package object is created but + // not sited yet inside Visual Studio environment. The place to do all the other + // initialization is the Initialize method. + } + + #region Package Members + + /// + /// Initialization of the package; this method is called right after the package is sited, so this is the place + /// where you can put all the initialization code that rely on services provided by VisualStudio. + /// + /// A cancellation token to monitor for initialization cancellation, which can occur when VS is shutting down. + /// A provider for progress updates. + /// A task representing the async work of package initialization, or an already completed task if there is none. Do not return null from this method. + protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) + { + // When initialized asynchronously, the current thread may be a background thread at this point. + // Do any initialization that requires the UI thread after switching to the UI thread. + await this.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + await BotFileCreatorCommand.InitializeAsync(this); + } + + #endregion + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreatorPackage.vsct b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreatorPackage.vsct new file mode 100644 index 0000000000..37f2d212fb --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/BotFileCreatorPackage.vsct @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/FodyWeavers.xml b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/FodyWeavers.xml new file mode 100644 index 0000000000..4e68ed1a8b --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/FodyWeavers.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/FodyWeavers.xsd b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/FodyWeavers.xsd new file mode 100644 index 0000000000..a608e3f556 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/FodyWeavers.xsd @@ -0,0 +1,49 @@ + + + + + + + + + + + Used to control if the On_PropertyName_Changed feature is enabled. + + + + + Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form. + + + + + Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project. + + + + + Used to control if equality checks should use the Equals method resolved from the base class. + + + + + Used to control if equality checks should use the static Equals method resolved from the base class. + + + + + + + + 'true' to run assembly verification on the target assembly after all weavers have been finished. + + + + + A comma separated list of error codes that can be safely ignored in assembly verification. + + + + + \ No newline at end of file diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/GeneralSettings.settings b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/GeneralSettings.settings new file mode 100644 index 0000000000..d051b7373b --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/GeneralSettings.settings @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/GeneralSettings1.Designer.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/GeneralSettings1.Designer.cs new file mode 100644 index 0000000000..b5245af00a --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/GeneralSettings1.Designer.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace BotFileCreator { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] + internal sealed partial class GeneralSettings : global::System.Configuration.ApplicationSettingsBase { + + private static GeneralSettings defaultInstance = ((GeneralSettings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new GeneralSettings()))); + + public static GeneralSettings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ProjectName { + get { + return ((string)(this["ProjectName"])); + } + set { + this["ProjectName"] = value; + } + } + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Key.snk b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Key.snk new file mode 100644 index 0000000000..706047cf4f Binary files /dev/null and b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Key.snk differ diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Models/Data/EndpointItem.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Models/Data/EndpointItem.cs new file mode 100644 index 0000000000..35b819ce8c --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Models/Data/EndpointItem.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace BotFileCreator +{ + public class EndpointItem : BaseViewModel + { + public EndpointItem() + { + this.Name = string.Empty; + this.AppId = string.Empty; + this.AppPassword = string.Empty; + } + + public string Name { get; set; } + + public string Endpoint { get; set; } + + public string AppId { get; set; } + + public string AppPassword { get; set; } + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Newtonsoft.Json.dll b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Newtonsoft.Json.dll new file mode 100644 index 0000000000..77a5d89e60 Binary files /dev/null and b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Newtonsoft.Json.dll differ diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Properties/AssemblyInfo.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..7711695175 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Properties/AssemblyInfo.cs @@ -0,0 +1,32 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BotFileCreator")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BotFileCreator")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/PropertyChanged.dll b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/PropertyChanged.dll new file mode 100644 index 0000000000..842020ce8d Binary files /dev/null and b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/PropertyChanged.dll differ diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Repository/Implementations/BotFileRepository.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Repository/Implementations/BotFileRepository.cs new file mode 100644 index 0000000000..e4d800c9f6 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Repository/Implementations/BotFileRepository.cs @@ -0,0 +1,167 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace BotFileCreator.Repository +{ + using System.IO; + using Microsoft.Bot.Configuration; + + public class BotFileRepository : IBotConfigurationRepository + { + private BotConfiguration botConfiguration; + private string path; + private string secret; + private string fileName; + + public BotFileRepository(string fileName, string path, string secret = default(string)) + { + this.fileName = fileName; + this.path = path; + + if (!string.IsNullOrWhiteSpace(secret)) + { + this.secret = secret; + } + + // Initialize the BotConfiguration + Initialize(); + } + + /// + /// Generates a Key + /// + /// string + public static string GenerateKey() + { + return BotConfiguration.GenerateKey(); + } + + /// + /// Load + /// + /// file + /// secret + public void Load(string file, string secret = default(string)) + { + var botConfiguration = BotConfiguration.Load(file, secret); + + if (botConfiguration != null) + { + this.botConfiguration = botConfiguration; + } + } + + /// + /// Save + /// + /// secret + public void Save(string secret = default(string)) + { + if (this.botConfiguration != null) + { + #pragma warning disable VSTHRD002 // Avoid problematic synchronous waits + this.botConfiguration.SaveAsAsync(this.GetFullPath(), secret).GetAwaiter().GetResult(); + #pragma warning restore VSTHRD002 // Avoid problematic synchronous waits + } + } + + /// + /// ConnectService + /// + /// service + public void ConnectService(ConnectedService service) + { + if (this.botConfiguration != null) + { + this.botConfiguration.ConnectService(service); + } + } + + /// + /// DisconnectService + /// + /// serviceId + public void DisconnectService(string serviceId) + { + if (this.botConfiguration != null) + { + this.botConfiguration.DisconnectService(serviceId); + } + } + + /// + /// Encrypt + /// + /// secret + public void Encrypt(string secret) + { + if (this.botConfiguration != null) + { + this.botConfiguration.Encrypt(secret); + } + } + + /// + /// Decrypt + /// + /// secret + public void Decrypt(string secret) + { + if (this.botConfiguration != null) + { + this.botConfiguration.Decrypt(secret); + } + } + + /// + /// Initialize + /// + private void Initialize() + { + string fullPath = GetFullPath(); + + // If the configuration file exists, load it. If not, create + // a new instance of BotConfiguration for managing it + if (File.Exists(fullPath)) + { + Load(fullPath, this.secret); + } + else + { + this.botConfiguration = new BotConfiguration(); + + // Sets the botConfiguration's name + SetBotProperties(); + } + } + + /// + /// Sets the Bot's name + /// + private void SetBotProperties() + { + if (this.botConfiguration != null) + { + this.botConfiguration.Name = this.fileName.Replace(".bot", string.Empty); + this.botConfiguration.Padlock = string.Empty; + this.botConfiguration.Description = string.Empty; + } + } + + /// + /// Get full path + /// + /// string + private string GetFullPath() + { + string fullPath = Path.Combine(this.path, this.fileName); + + if (!fullPath.EndsWith(".bot")) + { + fullPath = string.Join(string.Empty, fullPath, ".bot"); + } + + return fullPath; + } + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Repository/Interface/IBotConfigurationRepository.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Repository/Interface/IBotConfigurationRepository.cs new file mode 100644 index 0000000000..4b75d8e585 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Repository/Interface/IBotConfigurationRepository.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace BotFileCreator.Repository +{ + using Microsoft.Bot.Configuration; + + public interface IBotConfigurationRepository + { + /// + /// Load + /// + /// file + /// secret + void Load(string file, string secret = default(string)); + + /// + /// Save + /// + /// secret + void Save(string secret = default(string)); + + /// + /// ConnectService + /// + /// service + void ConnectService(ConnectedService service); + + /// + /// DisconnectService + /// + /// serviceId + void DisconnectService(string serviceId); + + /// + /// Encrypt + /// + /// secret + void Encrypt(string secret); + + /// + /// Decrypt + /// + /// secret + void Decrypt(string secret); + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Resources/BotFileCreatorCommand.png b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Resources/BotFileCreatorCommand.png new file mode 100644 index 0000000000..b22d975cbf Binary files /dev/null and b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Resources/BotFileCreatorCommand.png differ diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Resources/BotFileCreatorPackage.ico b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Resources/BotFileCreatorPackage.ico new file mode 100644 index 0000000000..d323b07fb8 Binary files /dev/null and b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Resources/BotFileCreatorPackage.ico differ diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Services/FileSystemService.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Services/FileSystemService.cs new file mode 100644 index 0000000000..f58f731ee9 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Services/FileSystemService.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace BotFileCreator +{ + using System.Linq; + + public class FileSystemService + { + private string _projectName; + + public FileSystemService() + { + this._projectName = GeneralSettings.Default.ProjectName; + } + + public void AddFileToProject(string botFileName) + { + // Load a specific project. Also, avoids several problems for re-loading the same project more than once + var project = Microsoft.Build.Evaluation.ProjectCollection.GlobalProjectCollection.LoadedProjects.FirstOrDefault(pr => pr.FullPath == _projectName); + project = project == null ? new Microsoft.Build.Evaluation.Project(this._projectName) : project; + + if (project != null) + { + // Reevaluates the project to add any change + project.ReevaluateIfNecessary(); + + // Checks if the project has a file with the same name. If it doesn't, it will be added to the project + if (project.Items.FirstOrDefault(item => item.EvaluatedInclude == botFileName) == null) + { + project.AddItem("Compile", botFileName); + project.Save(); + } + } + } + + public string GetProjectDirectoryPath() + { + return _projectName.Substring(0, _projectName.LastIndexOf('\\')); + } + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/VSPackage.resx b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/VSPackage.resx new file mode 100644 index 0000000000..2b6a54216d --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/VSPackage.resx @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + BotFileCreatorPackage Extension + + + BotFileCreatorPackage Visual Studio Extension Detailed Info + + + Resources\BotFileCreatorPackage.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/ViewModels/BaseViewModel.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/ViewModels/BaseViewModel.cs new file mode 100644 index 0000000000..fafb5dd726 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/ViewModels/BaseViewModel.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace BotFileCreator +{ + using System.Collections.Generic; + using System.ComponentModel; + using System.Runtime.CompilerServices; + + public class BaseViewModel : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged = (sender, e) => { }; + + protected bool SetProperty(ref T field, T newValue, [CallerMemberName]string propertyName = null) + { + if (!EqualityComparer.Default.Equals(field, newValue)) + { + field = newValue; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + return true; + } + + return false; + } + + protected void NotifyPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/ViewModels/BotConfigurationViewModel.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/ViewModels/BotConfigurationViewModel.cs new file mode 100644 index 0000000000..52a2717ecb --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/ViewModels/BotConfigurationViewModel.cs @@ -0,0 +1,258 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace BotFileCreator +{ + using System; + using System.IO; + using System.Linq; + using System.Windows; + using System.Windows.Input; + using BotFileCreator.Repository; + using Microsoft.Bot.Configuration; + + public class BotConfigurationViewModel : BaseViewModel + { + private IBotConfigurationRepository _repository; + + private readonly FileSystemService _fileSystemService; + + private readonly ICommand _cancelCommand; + + private readonly ICommand _createCommand; + + private readonly ICommand _botNameCommand; + + private readonly ICommand _botEndpointCommmand; + + private readonly ICommand _botServicesCommand; + + private readonly ICommand _botEncryptCommand; + + private readonly ICommand _isCheckedEncryptCheckBox; + + private readonly ICommand _copyCommand; + + private bool _encryptNoteIsVisible; + + private EndpointItem _endpointItem; + + private string _secretKey; + + private string _botFileName = string.Empty; + + private string _panelToShow = "BotName"; + + public BotConfigurationViewModel() + { + _fileSystemService = new FileSystemService(); + _endpointItem = new EndpointItem(); + _encryptNoteIsVisible = false; + _copyCommand = new RelayCommand(param => this.CopySecretKey(), null); + _isCheckedEncryptCheckBox = new RelayCommand(param => this.CheckEncryptCheckBox(), null); + _createCommand = new RelayCommand(param => this.CreateBotFile(), null); + _cancelCommand = new RelayCommand(param => this.CloseAction(), null); + _botNameCommand = new RelayCommand(param => this.SetPanelToShow("BotName"), null); + _botEndpointCommmand = new RelayCommand(param => this.SetPanelToShow("BotEndpoint"), null); + _botServicesCommand = new RelayCommand(param => this.SetPanelToShow("BotServices"), null); + _botEncryptCommand = new RelayCommand(param => this.SetPanelToShow("BotEncrypt"), null); + } + + public bool EncryptNoteIsVisible + { + get => _encryptNoteIsVisible; + set + { + _encryptNoteIsVisible = value; + NotifyPropertyChanged("EncryptNoteVisibility"); + } + } + + public string PanelToShow + { + get => _panelToShow; + set + { + _panelToShow = value; + NotifyPropertyChanged("BotNameVisibility"); + NotifyPropertyChanged("BotEndpointVisibility"); + NotifyPropertyChanged("BotServicesVisibility"); + NotifyPropertyChanged("BotEncrypVisibility"); + } + } + + public Visibility EncryptNoteVisibility + { + get => EncryptNoteIsVisible ? Visibility.Visible : Visibility.Collapsed; + } + + public Visibility BotNameVisibility + { + get => _panelToShow == "BotName" ? Visibility.Visible : Visibility.Collapsed; + } + + public Visibility BotEndpointVisibility + { + get => _panelToShow == "BotEndpoint" ? Visibility.Visible : Visibility.Collapsed; + } + + public Visibility BotServicesVisibility + { + get => _panelToShow == "BotServices" ? Visibility.Visible : Visibility.Collapsed; + } + + public Visibility BotEncrypVisibility + { + get => _panelToShow == "BotEncrypt" ? Visibility.Visible : Visibility.Collapsed; + } + + public string SecretKey { get => _secretKey; set => SetProperty(ref _secretKey, value); } + + public string BotFileName { get => _botFileName; set => SetProperty(ref _botFileName, value); } + + public EndpointItem EndpointItem { get => _endpointItem; set => SetProperty(ref _endpointItem, value); } + + public bool EncryptCheckBoxIsChecked { get; set; } + + public ICommand CopyCommand { get => _copyCommand; } + + public ICommand CreateCommand { get => _createCommand; } + + public ICommand CancelCommand { get => _cancelCommand; } + + public ICommand BotNameCommand { get => _botNameCommand; } + + public ICommand BotEndpointCommand { get => _botEndpointCommmand; } + + public ICommand BotServicesCommand { get => _botServicesCommand; } + + public ICommand BotEncryptCommand { get => _botEncryptCommand; } + + public ICommand IsCheckedEncryptCheckBox { get => _isCheckedEncryptCheckBox; } + + public Action CloseAction { get; set; } + + public void CreateBotFile() + { + // Checks if the bot configuration is valid + Tuple configIsValid = BotFileConfigurationIsValid(BotFileName); + + // If the bot's configuration is not valid, it will show an error + if (!configIsValid.Item1) + { + MessageBox.Show(configIsValid.Item2, "Error", MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + + // Repository for creating bot files + _repository = new BotFileRepository(BotFileName, _fileSystemService.GetProjectDirectoryPath()); + + // Adds the only endpoint (if it's not null) to the bot configuration + if (!string.IsNullOrWhiteSpace(EndpointItem.Endpoint)) + { + EndpointService endpoint = new EndpointService() { Name = this.EndpointItem.Name, Endpoint = this.EndpointItem.Endpoint, AppId = this.EndpointItem.AppId, AppPassword = this.EndpointItem.AppPassword, ChannelService = string.Empty }; + _repository.ConnectService(endpoint); + } + + // If the "SecretKey" has value, the bot configuration is save with encryption + if (!string.IsNullOrWhiteSpace(this.SecretKey)) + { + _repository.Save(this.SecretKey); + } + else + { + // Save the bot configuration without encryption + _repository.Save(); + } + + // Adds the just generated bot file to the project + _fileSystemService.AddFileToProject(string.Concat(BotFileName, ".bot")); + + // If the file was successfully created, the Wizard will be closed. + MessageBox.Show("Bot file successfully created", "Bot file successfully created", MessageBoxButton.OK, MessageBoxImage.Exclamation); + CloseAction(); + } + + /// + /// Checks if the Bot File Configuration to create is valid + /// + /// bot file's name + /// Tuple + private Tuple BotFileConfigurationIsValid(string botFileName) + { + // If the .bot file name is Null or WhiteSpace, returns an error. + if (string.IsNullOrWhiteSpace(botFileName)) + { + return new Tuple(false, "Bot file name can't be null."); + } + + // If the .bot file name contains any whitespace, the method will return an error. + if (botFileName.Contains(" ")) + { + return new Tuple(false, "Bot file name can't have whitespaces."); + } + + if (File.Exists(Path.Combine(_fileSystemService.GetProjectDirectoryPath(), string.Concat(botFileName, ".bot")))) + { + return new Tuple(false, $"The bot file {botFileName} already exists."); + } + + // A tuple with True and Empty string will be returned if there are no errors. + return new Tuple(true, string.Empty); + } + + /// + /// Adds a specified file to another specified project + /// + /// The full path to .csproj file + /// The file name to add to csproj + private void AddFileToProject(string projectName, string fileName) + { + // Load a specific project. Also, avoids several problems for re-loading the same project more than once + var project = Microsoft.Build.Evaluation.ProjectCollection.GlobalProjectCollection.LoadedProjects.FirstOrDefault(pr => pr.FullPath == projectName); + + if (project != null) + { + // Reevaluates the project to add any change + project.ReevaluateIfNecessary(); + + // Checks if the project has a file with the same name. If it doesn't, it will be added to the project + if (project.Items.FirstOrDefault(item => item.EvaluatedInclude == fileName) == null) + { + project.AddItem("Compile", fileName); + project.Save(); + } + } + } + + /// + /// Returns the Working Project Directory + /// + /// Project's full path + /// Project's directory path + private string GetProjectDirectoryPath(string projectPath) + { + return projectPath.Substring(0, projectPath.LastIndexOf('\\')); + } + + private void SetPanelToShow(string panelToShow) + { + this.PanelToShow = panelToShow; + } + + private void CheckEncryptCheckBox() + { + EncryptCheckBoxIsChecked = !EncryptCheckBoxIsChecked; + EncryptNoteIsVisible = !EncryptNoteIsVisible; + this.SecretKey = EncryptCheckBoxIsChecked ? BotFileRepository.GenerateKey() : string.Empty; + } + + private void CopySecretKey() + { + if (!string.IsNullOrWhiteSpace(SecretKey)) + { + Clipboard.SetText(SecretKey); + } + } + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/ViewModels/RelayCommand.cs b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/ViewModels/RelayCommand.cs new file mode 100644 index 0000000000..92234efed1 --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/ViewModels/RelayCommand.cs @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace BotFileCreator +{ + using System; + using System.Windows.Input; + + public class RelayCommand : ICommand + { + private readonly Action _execute; + private readonly Predicate _canExecute; + + public RelayCommand(Action execute) + : this(execute, null) + { + } + + public RelayCommand(Action execute, Predicate canExecute) + { + _execute = execute ?? throw new ArgumentNullException("execute"); + _canExecute = canExecute; + } + + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + public bool CanExecute(object parameter) + { + return _canExecute == null ? true : _canExecute(parameter); + } + + public void Execute(object parameter) + { + _execute(parameter); + } + } +} diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Views/BotConfigurationStyles.xaml b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Views/BotConfigurationStyles.xaml new file mode 100644 index 0000000000..2a076188ae --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Views/BotConfigurationStyles.xaml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Views/BotConfigurationView.xaml b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Views/BotConfigurationView.xaml new file mode 100644 index 0000000000..83668a13cf --- /dev/null +++ b/generators/vsix-vs-win/BotConfigurationWizard/BotFileCreator/Views/BotConfigurationView.xaml @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +