diff --git a/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaClient.cs b/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaClient.cs index a44b20641f1..6b596976b86 100644 --- a/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaClient.cs +++ b/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaClient.cs @@ -686,7 +686,7 @@ public ArdiaResult GetServerStorageInfo() // API documentation: https://api.ardia-core-int.cmdtest.thermofisher.com/navigation/api/swagger/index.html public ArdiaResult GetFolderByGetParentFolderByPath(string path) { - var uri = UriFromParts(ServerUri, $"{PATH_GET_PARENT_BY_PATH}?itemPath={Uri.EscapeDataString(path)}"); + var uri = UriWithParams(UriFromParts(ServerUri, PATH_GET_PARENT_BY_PATH), new Dictionary { ["itemPath"] = path }); HttpStatusCode? statusCode = null; try @@ -720,12 +720,40 @@ private static Uri GetFolderContentsUrl(ArdiaAccount account, ArdiaUrl ardiaUrl) return new Uri(account.GetFolderContentsUrl(ardiaUrl)); } - private static Uri UriFromParts(Uri host, string path) + public static Uri UriFromParts(Uri host, params string[] paths) { - return new Uri(host.ToString().TrimEnd('/') + path); + var baseUri = host.AbsoluteUri.TrimEnd('/'); + + var combinedPath = string.Join("/", paths.Select(p => p.Trim('/'))); + + var full = $"{baseUri}/{combinedPath}"; + + if (!Uri.TryCreate(full, UriKind.Absolute, out var result)) + throw new UriFormatException($"Resulting URI was not valid: {full}"); + + return new Uri(result.AbsoluteUri); } + public static Uri UriWithParams(Uri url, IDictionary queryParams) + { + var baseUri = url.AbsoluteUri.TrimEnd('/'); + + string full; + if (queryParams != null && queryParams.Count > 0) + { + var query = string.Join("&", queryParams.Select(kvp => + $"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}" + )); + full = $"{baseUri}?{query}"; + } + else full = baseUri; + + if (!Uri.TryCreate(full, UriKind.Absolute, out var result)) + throw new UriFormatException($"Resulting URI was not valid: {full}"); + + return new Uri(result.AbsoluteUri); + } private static bool ShouldHandleException(Exception exception) { diff --git a/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaResources.Designer.cs b/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaResources.Designer.cs index 9d9560c4304..8f7264537d4 100644 --- a/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaResources.Designer.cs +++ b/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaResources.Designer.cs @@ -331,6 +331,15 @@ public static string FileUpload_Success { } } + /// + /// Looks up a localized string similar to Successfully uploaded the document to Ardia. Would you like to view it in the Ardia Data Explorer?. + /// + public static string FileUpload_Success_OpenDataExplorer { + get { + return ResourceManager.GetString("FileUpload_Success_OpenDataExplorer", resourceCulture); + } + } + /// /// Looks up a localized string similar to Error getting document '{0}'. A problem occurred communicating with the server.. /// diff --git a/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaResources.resx b/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaResources.resx index 9758d2dae0f..0d3e926bbb3 100644 --- a/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaResources.resx +++ b/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/ArdiaResources.resx @@ -145,6 +145,9 @@ Successfully uploaded the document to Ardia. + + Successfully uploaded the document to Ardia. Would you like to view it in the Ardia Data Explorer? + Unable to publish the document. A problem occurred communicating with the server. diff --git a/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/GetParentFolderResponse.cs b/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/GetParentFolderResponse.cs index 2264e078dd8..b033d534a3e 100644 --- a/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/GetParentFolderResponse.cs +++ b/pwiz_tools/Shared/CommonMsData/RemoteApi/Ardia/GetParentFolderResponse.cs @@ -21,7 +21,7 @@ namespace pwiz.CommonMsData.RemoteApi.Ardia { public class GetParentFolderResponse { - private const string PATH_DATA_EXPLORER = @"/app/data-explorer/"; + private const string PATH_DATA_EXPLORER = @"/app/data-explorer"; public string RLink2 { get; set; } @@ -30,7 +30,7 @@ public class GetParentFolderResponse public static GetParentFolderResponse FromJson(string json, Uri serverUrl) { var response = JsonConvert.DeserializeObject(json); - response.Url = new Uri(serverUrl.ToString().TrimEnd('/') + PATH_DATA_EXPLORER + response.RLink2); + response.Url = ArdiaClient.UriFromParts(serverUrl, PATH_DATA_EXPLORER, response.RLink2); return response; } } diff --git a/pwiz_tools/Skyline/FileUI/PublishDocumentDlgArdia.cs b/pwiz_tools/Skyline/FileUI/PublishDocumentDlgArdia.cs index 154fb3fd1c3..5faebd444bd 100644 --- a/pwiz_tools/Skyline/FileUI/PublishDocumentDlgArdia.cs +++ b/pwiz_tools/Skyline/FileUI/PublishDocumentDlgArdia.cs @@ -17,6 +17,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.Linq; using System.Net; @@ -285,14 +286,8 @@ public void Upload(Control parent, SrmDocumentArchive archive) if (isCanceled) return; - - if (result.IsSuccess) - { - PublishedDocument = result.Value; - - MessageDlg.Show(parent, ArdiaResources.FileUpload_Success); - } - else + + if (result.IsFailure) { string message; if (result.ErrorStatusCode == HttpStatusCode.Unauthorized) @@ -300,7 +295,24 @@ public void Upload(Control parent, SrmDocumentArchive archive) else message = ArdiaResources.FileUpload_Error; MessageDlg.ShowWithExceptionAndNetworkDetail(parent, message, result.ErrorMessage, result.ErrorException); + return; } + + PublishedDocument = result.Value; + + var successMessage = ArdiaResources.FileUpload_Success_OpenDataExplorer; + if (MultiButtonMsgDlg.Show(parent, successMessage, MultiButtonMsgDlg.BUTTON_YES, MultiButtonMsgDlg.BUTTON_NO, false) == DialogResult.No) + return; + + var getUrlResult = Client.GetFolderByGetParentFolderByPath(DestinationPath); + if (getUrlResult.IsFailure) + { + var message = result.ErrorStatusCode == HttpStatusCode.Unauthorized ? ArdiaResources.Error_InvalidToken : ArdiaResources.Error_StatusCode_Unexpected; + MessageDlg.ShowWithExceptionAndNetworkDetail(parent, message, getUrlResult.ErrorMessage, getUrlResult.ErrorException); + return; + } + + Process.Start(getUrlResult.Value.Url.ToString()); } public TreeNode CreateFolder() diff --git a/pwiz_tools/Skyline/Test/Test.csproj b/pwiz_tools/Skyline/Test/Test.csproj index 10ef6807526..48329e2943e 100644 --- a/pwiz_tools/Skyline/Test/Test.csproj +++ b/pwiz_tools/Skyline/Test/Test.csproj @@ -297,6 +297,7 @@ + diff --git a/pwiz_tools/Skyline/Test/UriBuilderTest.cs b/pwiz_tools/Skyline/Test/UriBuilderTest.cs new file mode 100644 index 00000000000..67fbe48626d --- /dev/null +++ b/pwiz_tools/Skyline/Test/UriBuilderTest.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using pwiz.CommonMsData.RemoteApi.Ardia; +using pwiz.SkylineTestUtil; + +namespace pwiz.SkylineTest +{ + [TestClass] + public class UriBuilderTest : AbstractUnitTest + { + private const string VALID_HOST = "https://ardia-core-int.cmdtest.thermofisher.com"; + private const string PATH_1 = "/app/data-explorer"; + private const string PATH_2 = "folders/8935b4af-015c-4ece-82a5-a812cd5a1626"; + + [TestMethod] + public void TestUriFromParts() + { + var host = new Uri(VALID_HOST); + Assert.AreEqual(VALID_HOST + PATH_1, ArdiaClient.UriFromParts(host, PATH_1).AbsoluteUri); + Assert.AreEqual(VALID_HOST + PATH_1 + "/" + PATH_2, ArdiaClient.UriFromParts(host, PATH_1, PATH_2).AbsoluteUri); + } + + [TestMethod] + public void TestUriWithParams() + { + var host = new Uri(VALID_HOST); + var queryParams = new Dictionary { ["param 1"] = "value 1" }; + Assert.AreEqual(VALID_HOST + PATH_1 + $"?{Uri.EscapeDataString("param 1")}={Uri.EscapeDataString("value 1")}", + ArdiaClient.UriWithParams(ArdiaClient.UriFromParts(host, PATH_1), queryParams).AbsoluteUri); + queryParams.Add("param 2", "value 2"); + Assert.AreEqual( + VALID_HOST + PATH_1 + + $"?{Uri.EscapeDataString("param 1")}={Uri.EscapeDataString("value 1")}&{Uri.EscapeDataString("param 2")}={Uri.EscapeDataString("value 2")}", + ArdiaClient.UriWithParams(ArdiaClient.UriFromParts(host, PATH_1), queryParams).AbsoluteUri); + } + } +} diff --git a/pwiz_tools/Skyline/TestConnected/ArdiaFileUploadTest.cs b/pwiz_tools/Skyline/TestConnected/ArdiaFileUploadTest.cs index 9a7782cd1c1..e5400d2f9df 100644 --- a/pwiz_tools/Skyline/TestConnected/ArdiaFileUploadTest.cs +++ b/pwiz_tools/Skyline/TestConnected/ArdiaFileUploadTest.cs @@ -362,15 +362,15 @@ private static void TestSuccessfulUpload(ArdiaAccount account, ArdiaClient clien }); var shareTypeDlg = ShowDialog(publishDlg.OkDialog); - var docUploadedDlg = ShowDialog(shareTypeDlg.OkDialog); + var docUploadedDlg = ShowDialog(shareTypeDlg.OkDialog); // CONSIDER: in this case, MessageDlg displays when publishing is successful AND when there's an error. // Calling OkDialog(...) works in both cases - which causes downstream, less obvious errors. // Is there a better way to detect when a MessageDlg indicates an error without looking at // the message string? - Assert.AreEqual(ArdiaResources.FileUpload_Success, docUploadedDlg.Message, @"Error publishing the document to Ardia"); + Assert.AreEqual(ArdiaResources.FileUpload_Success_OpenDataExplorer, docUploadedDlg.Message, @"Error publishing the document to Ardia"); - OkDialog(docUploadedDlg, docUploadedDlg.ClickOk); + OkDialog(docUploadedDlg, docUploadedDlg.ClickYes); Assert.IsNotNull(publishDlg.DestinationPath); Assert.AreEqual(@$"/{folderPath[0]}/{folderPath[1]}", publishDlg.DestinationPath);