Skip to content

Commit

Permalink
Add run as admin context menu item for application results returned b…
Browse files Browse the repository at this point in the history
…y the Indexer Plugin (#4807)

* Added run as admin context menu item to apps returned by indexer plugin

* Added a test and localized strings

* localize strings

* Add more tests for folder and other file types

* fixed run as admin -> run as administrator

* resolved merge conflict

* refactored tests

* moved common code to helper and added logs

* moved start process to the helper class

* added more info in a comment

* fixed count in tests as open in console was added

* removed additional code that was added while fixing merge conflicts
  • Loading branch information
alekhyareddy28 committed Jul 8, 2020
1 parent 638cd1d commit 411140c
Show file tree
Hide file tree
Showing 11 changed files with 162 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
using Wox.Infrastructure.Logger;
using Wox.Plugin;
using Microsoft.Plugin.Indexer.SearchHelper;
using System.Windows.Input;
using System.Reflection;
using System.Windows.Input;
using System.Reflection;
using System.Threading.Tasks;
using Wox.Infrastructure;

namespace Microsoft.Plugin.Indexer
Expand All @@ -22,6 +23,9 @@ public enum ResultType
File
}

// Extensions for adding run as admin context menu item for applications
private readonly string[] appExtensions = { ".exe", ".bat", ".appref-ms", ".lnk" };

public ContextMenuLoader(PluginInitContext context)
{
_context = context;
Expand All @@ -39,6 +43,12 @@ public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
contextMenus.Add(CreateOpenContainingFolderResult(record));
}

// Test to check if File can be Run as admin, if yes, we add a 'run as admin' context menu item
if(CanFileBeRunAsAdmin(record.Path))
{
contextMenus.Add(CreateRunAsAdminContextMenu(record));
}

contextMenus.Add(new ContextMenuResult
{
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
Expand Down Expand Up @@ -98,8 +108,51 @@ public List<ContextMenuResult> LoadContextMenus(Result selectedResult)
}

return contextMenus;
}

}

// Function to add the context menu item to run as admin
private ContextMenuResult CreateRunAsAdminContextMenu(SearchResult record)
{
return new ContextMenuResult
{
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
Title = _context.API.GetTranslation("Microsoft_plugin_indexer_run_as_administrator"),
Glyph = "\xE7EF",
FontFamily = "Segoe MDL2 Assets",
AcceleratorKey = Key.Enter,
AcceleratorModifiers = (ModifierKeys.Control | ModifierKeys.Shift),
Action = _ =>
{
try
{
Task.Run(() => Helper.RunAsAdmin(record.Path));
return true;
}
catch(Exception e)
{
Log.Exception($"|Microsoft.Plugin.Indexer.ContextMenu| Failed to run {record.Path} as admin, {e.Message}", e);
return false;
}
}
};
}

// Function to test if the file can be run as admin
private bool CanFileBeRunAsAdmin(string path)
{
string fileExtension = Path.GetExtension(path);
foreach(string extension in appExtensions)
{
if(extension.Equals(fileExtension, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}


private ContextMenuResult CreateOpenContainingFolderResult(SearchResult record)
{
return new ContextMenuResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<system:String x:Key="Microsoft_plugin_indexer_copy_path">Copy path (Ctrl+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_containing_folder">Open containing folder (Ctrl+Shift+E)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_run_as_administrator">Run As Administrator (Ctrl+Shift+Enter)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_in_console">Open path in console (Ctrl+Shift+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_name">Name</system:String>
<system:String x:Key="Microsoft_plugin_indexer_path">Path</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<system:String x:Key="Microsoft_plugin_indexer_copy_path">Copy path (Ctrl+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_containing_folder">Open containing folder (Ctrl+Shift+E)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_run_as_administrator">Run As Administrator (Ctrl+Shift+Enter)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_in_console">Open path in console (Ctrl+Shift+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_name">Name</system:String>
<system:String x:Key="Microsoft_plugin_indexer_path">Path</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<system:String x:Key="Microsoft_plugin_indexer_copy_path">Copy path (Ctrl+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_containing_folder">Open containing folder (Ctrl+Shift+E)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_run_as_administrator">Run As Administrator (Ctrl+Shift+Enter)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_in_console">Open path in console (Ctrl+Shift+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_name">Name</system:String>
<system:String x:Key="Microsoft_plugin_indexer_path">Path</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<system:String x:Key="Microsoft_plugin_indexer_copy_path">Copy path (Ctrl+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_containing_folder">Open containing folder (Ctrl+Shift+E)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_run_as_administrator">Run As Administrator (Ctrl+Shift+Enter)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_in_console">Open path in console (Ctrl+Shift+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_name">Name</system:String>
<system:String x:Key="Microsoft_plugin_indexer_path">Path</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<system:String x:Key="Microsoft_plugin_indexer_copy_path">Copy path (Ctrl+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_containing_folder">Open containing folder (Ctrl+Shift+E)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_run_as_administrator">Run As Administrator (Ctrl+Shift+Enter)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_in_console">Open path in console (Ctrl+Shift+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_name">Name</system:String>
<system:String x:Key="Microsoft_plugin_indexer_path">Path</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<system:String x:Key="Microsoft_plugin_indexer_copy_path">Copy path (Ctrl+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_containing_folder">Open containing folder (Ctrl+Shift+E)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_run_as_administrator">Run As Administrator (Ctrl+Shift+Enter)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_in_console">Open path in console (Ctrl+Shift+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_name">Name</system:String>
<system:String x:Key="Microsoft_plugin_indexer_path">Path</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<system:String x:Key="Microsoft_plugin_indexer_copy_path">Copy path (Ctrl+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_containing_folder">Open containing folder (Ctrl+Shift+E)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_run_as_administrator">Run As Administrator (Ctrl+Shift+Enter)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_open_in_console">Open path in console (Ctrl+Shift+C)</system:String>
<system:String x:Key="Microsoft_plugin_indexer_name">Name</system:String>
<system:String x:Key="Microsoft_plugin_indexer_path">Path</system:String>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Wox.Test</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

<ItemGroup>
<Content Include="Languages\de.xaml">
Expand Down Expand Up @@ -101,4 +95,11 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Wox.Test</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

</Project>
21 changes: 21 additions & 0 deletions src/modules/launcher/Wox.Infrastructure/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Wox.Infrastructure.Logger;

namespace Wox.Infrastructure
{
Expand Down Expand Up @@ -76,6 +77,26 @@ public static string Formatted<T>(this T t)
return formatted;
}

// Function to run as admin for context menu items
public static void RunAsAdmin(string path)
{
var info = new ProcessStartInfo
{
FileName = path,
WorkingDirectory = Path.GetDirectoryName(path),
Verb = "runas",
UseShellExecute = true
};

try
{
Process.Start(info);
}
catch(System.Exception ex)
{
Log.Exception($"Wox.Infrastructure.Helper| Unable to Run {path} as admin : {ex.Message}", ex);
}
}
public static Process OpenInConsole(string path)
{
var processStartInfo = new ProcessStartInfo
Expand Down
100 changes: 70 additions & 30 deletions src/modules/launcher/Wox.Test/Plugins/WindowsIndexerTest.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Data.OleDb;
using Microsoft.Search.Interop;
using Microsoft.Plugin.Indexer.SearchHelper;
using Microsoft.Plugin.Indexer.Interface;
using Moq;
using System.Linq;
using Microsoft.Plugin.Indexer;
using Moq;
using Wox.Plugin;
using System.Linq;

namespace Wox.Test.Plugins
{
Expand Down Expand Up @@ -217,45 +216,86 @@ public void WindowsSearchAPI_ShouldNotReturnResultsWithNullValue_WhenDbResultHas
Assert.IsTrue(windowsSearchAPIResults.Any(x => x.Title == "file2.txt"));
}

[Test]
public void ContextMenuLoader_ReturnContextMenuForFolderWithOpenInConsole_WhenLoadContextMenusIsCalled()
[TestCase("item.exe")]
[TestCase("item.bat")]
[TestCase("item.appref-ms")]
[TestCase("item.lnk")]
public void LoadContextMenus_MustLoadAllItems_WhenFileIsAnApp(string path)
{
// Arrange
var mock = new Mock<IPublicAPI>();
mock.Setup(api => api.GetTranslation(It.IsAny<string>())).Returns(It.IsAny<string>());
var pluginInitContext = new PluginInitContext() { API = mock.Object };
var contextMenuLoader = new ContextMenuLoader(pluginInitContext);
var searchResult = new SearchResult() { Path = "C:/DummyFolder", Title = "DummyFolder" };
var result = new Result() { ContextData = searchResult };
// Arrange
var mockapi = new Mock<IPublicAPI>();
var pluginInitContext = new PluginInitContext() { API = mockapi.Object };

ContextMenuLoader _contextMenuLoader = new ContextMenuLoader(pluginInitContext);

// Act
List<ContextMenuResult> contextMenuResults = contextMenuLoader.LoadContextMenus(result);
Result result = new Result
{
ContextData = new SearchResult { Path = path }
};

List<ContextMenuResult> contextMenuItems = _contextMenuLoader.LoadContextMenus(result);

// Assert
Assert.AreEqual(contextMenuResults.Count, 2);
mock.Verify(x => x.GetTranslation("Microsoft_plugin_indexer_copy_path"), Times.Once());
mock.Verify(x => x.GetTranslation("Microsoft_plugin_indexer_open_in_console"), Times.Once());
Assert.AreEqual(contextMenuItems.Count, 4);
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_copy_path"), Times.Once());
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_run_as_administrator"), Times.Once());
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_containing_folder"), Times.Once());
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_in_console"), Times.Once());
}

[Test]
public void ContextMenuLoader_ReturnContextMenuForFileWithOpenInConsole_WhenLoadContextMenusIsCalled()
[TestCase("item.pdf")]
[TestCase("item.xls")]
[TestCase("item.ppt")]
[TestCase("C:/DummyFile.cs")]
public void LoadContextMenus_MustNotLoadRunAsAdmin_WhenFileIsAnNotApp(string path)
{
// Arrange
var mockapi = new Mock<IPublicAPI>();
var pluginInitContext = new PluginInitContext() { API = mockapi.Object };

ContextMenuLoader _contextMenuLoader = new ContextMenuLoader(pluginInitContext);

// Act
Result result = new Result
{
ContextData = new SearchResult { Path = path }
};

List<ContextMenuResult> contextMenuItems = _contextMenuLoader.LoadContextMenus(result);

// Assert
Assert.AreEqual(contextMenuItems.Count, 3);
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_copy_path"), Times.Once());
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_run_as_administrator"), Times.Never());
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_containing_folder"), Times.Once());
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_in_console"), Times.Once());
}

[TestCase("C:/DummyFolder")]
[TestCase("TestFolder")]
public void LoadContextMenus_MustNotLoadRunAsAdminAndOpenContainingFolder_ForFolder(string path)
{
// Arrange
var mock = new Mock<IPublicAPI>();
mock.Setup(api => api.GetTranslation(It.IsAny<string>())).Returns(It.IsAny<string>());
var pluginInitContext = new PluginInitContext() { API = mock.Object };
var contextMenuLoader = new ContextMenuLoader(pluginInitContext);
var searchResult = new SearchResult() { Path = "C:/DummyFile.cs", Title = "DummyFile.cs" };
var result = new Result() { ContextData = searchResult };
// Arrange
var mockapi = new Mock<IPublicAPI>();
var pluginInitContext = new PluginInitContext() { API = mockapi.Object };

ContextMenuLoader _contextMenuLoader = new ContextMenuLoader(pluginInitContext);

// Act
List<ContextMenuResult> contextMenuResults = contextMenuLoader.LoadContextMenus(result);
Result result = new Result
{
ContextData = new SearchResult { Path = path }
};

List<ContextMenuResult> contextMenuItems = _contextMenuLoader.LoadContextMenus(result);

// Assert
Assert.AreEqual(contextMenuResults.Count, 3);
mock.Verify(x => x.GetTranslation("Microsoft_plugin_indexer_copy_path"), Times.Once());
mock.Verify(x => x.GetTranslation("Microsoft_plugin_indexer_open_containing_folder"), Times.Once());
mock.Verify(x => x.GetTranslation("Microsoft_plugin_indexer_open_in_console"), Times.Once());
Assert.AreEqual(contextMenuItems.Count, 2);
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_copy_path"), Times.Once());
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_run_as_administrator"), Times.Never());
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_containing_folder"), Times.Never());
mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_in_console"), Times.Once());
}
}
}

0 comments on commit 411140c

Please sign in to comment.