From 1110982a858a0edb246c8197e5d5efffa523ac50 Mon Sep 17 00:00:00 2001 From: Suyog Daga Date: Mon, 29 Mar 2021 18:20:12 -0700 Subject: [PATCH 1/5] Pagination for issue end point and rest api for application role --- PluginJira/API/Factory/ApiClient.cs | 7 +- PluginJira/API/Utility/Constants.cs | 2 +- PluginJira/API/Utility/EndpointHelper.cs | 1 + .../ApplicationRolesEndpoint.cs | 69 +++++++++++++++++++ .../EndpointHelperEndpoints/IssuesEndpoint.cs | 59 +++++++++------- PluginJira/Helper/Settings.cs | 1 + .../Plugin/PluginIntegrationTest.cs | 62 ++++++++++++++++- 7 files changed, 174 insertions(+), 27 deletions(-) create mode 100644 PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs diff --git a/PluginJira/API/Factory/ApiClient.cs b/PluginJira/API/Factory/ApiClient.cs index 424325b..903473c 100644 --- a/PluginJira/API/Factory/ApiClient.cs +++ b/PluginJira/API/Factory/ApiClient.cs @@ -61,14 +61,17 @@ public async Task GetAsync(string path) try { var token = await Authenticator.GetToken(); - var uri = new Uri($"{Constants.BaseApiUrl.TrimEnd('/')}/{path.TrimStart('/')}"); + var uri = new Uri($"{Settings.GetBaseUri().TrimEnd('/')}/{path.TrimStart('/')}"); var request = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = uri, }; - request.Headers.Add(_tokenHeaderName, token); + //request.Headers.Add(_tokenHeaderName, token); + + // Add basic authentication + request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token); return await Client.SendAsync(request); } diff --git a/PluginJira/API/Utility/Constants.cs b/PluginJira/API/Utility/Constants.cs index 8a78e74..1d55e65 100644 --- a/PluginJira/API/Utility/Constants.cs +++ b/PluginJira/API/Utility/Constants.cs @@ -3,7 +3,7 @@ namespace PluginJira.API.Utility public static class Constants { public static string BaseApiUrl = "https://test.atlassian.net/rest/api/2"; - public static string TestConnectionPath = "/applicationrole"; + public static string TestConnectionPath = "applicationrole"; public static string CustomProperty = "CustomProperty"; public static string EmptySchemaDescription = "This schema has no properties. This is likely due to to there being no data."; } diff --git a/PluginJira/API/Utility/EndpointHelper.cs b/PluginJira/API/Utility/EndpointHelper.cs index cc1884c..f853d1d 100644 --- a/PluginJira/API/Utility/EndpointHelper.cs +++ b/PluginJira/API/Utility/EndpointHelper.cs @@ -23,6 +23,7 @@ public static class EndpointHelper static EndpointHelper() { IssuesEndpointHelper.IssuesEndpoints.ToList().ForEach(x => Endpoints.TryAdd(x.Key, x.Value)); + ApplicationRolesEndpointHelper.ApplicationRolesEndpoints.ToList().ForEach(x => Endpoints.TryAdd(x.Key, x.Value)); } public static Dictionary GetAllEndpoints() diff --git a/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs b/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs new file mode 100644 index 0000000..45764fb --- /dev/null +++ b/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; +using Grpc.Core; +using Naveego.Sdk.Plugins; +using Newtonsoft.Json; +using PluginJira.API.Factory; +using PluginJira.API.Utility.EndpointHelperEndpoints; +using PluginJira.DataContracts; +using PluginJira.Helper; + +namespace PluginJira.API.Utility.EndpointHelperEndpoints +{ + public static class ApplicationRolesEndpointHelper + { + private class ApplicationRolesEndpoint : Endpoint + { + public override async IAsyncEnumerable ReadRecordsAsync(IApiClientFactory factory, Settings settings, + DateTime? lastReadTime = null, TaskCompletionSource? tcs = null, bool isDiscoverRead = false) + { + // fetch all records + var jira = factory.CreateApiClient(settings); + + var response = await jira.GetAsync("applicationrole"); + var recordsList =JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + + + foreach (var item in recordsList.Items){ + + var recordMap = new Dictionary(); + recordMap.TryAdd(item.ToString(), item.Values); + + + yield return new Record + { + Action = Record.Types.Action.Upsert, + DataJson = JsonConvert.SerializeObject(recordMap) + }; + } + + } + + } + + public static readonly Dictionary ApplicationRolesEndpoints = new Dictionary + { + {"AllApplicationRoles", new ApplicationRolesEndpoint + { + Id = "AllApplicationRoles", + Name = "All Application Roles", + BasePath = "/applicationrole", + AllPath = "/", + DetailPath = "/", + DetailPropertyId = "", + SupportedActions = new List + { + EndpointActions.Get + }, + PropertyKeys = new List + { + "BounceID" + } + }}, + }; + } +} \ No newline at end of file diff --git a/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs b/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs index 6991688..525a4a7 100644 --- a/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs +++ b/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs @@ -24,36 +24,49 @@ public override async IAsyncEnumerable ReadRecordsAsync(IApiClientFactor // fetch all records var jira = factory.CreateJiraClient(settings); - // var issues = jira.Issues.Queryable - // .Select(i => i) - // .GroupBy(i => i.Key); + string projectKey = "DEMO"; - var issues = from i in jira.Issues.Queryable - select i; - // iterate and return each record - // foreach on results of JQL - foreach (var issue in issues) + // Adding logic for pagination + int itemsPerPage = 50; + int startAt = 0; + + while(true) { - var recordMap = new Dictionary(); - // pull in all desired properties - recordMap["Key"] = issue.Key.Value; - recordMap["Project"] = issue.Project; - recordMap["Issuetype"] = issue.Type.Name; - recordMap["Description"] = issue.Description; - recordMap["Reporter"] = issue.ReporterUser.DisplayName; - recordMap["Created"] = issue.Created.Value; - recordMap["Status"] = issue.Status.Name; - recordMap["Resolution"] = issue.Resolution; - recordMap["Updated"] = issue.Updated.Value; + var issues = await jira.Issues.GetIssuesFromJqlAsync($"project = {projectKey} ORDER BY created DESC", itemsPerPage, startAt); + + if (issues.Count() == 0) + break; - yield return new Record + + // iterate and return each record + // foreach on results of JQL + foreach (var issue in issues) { - Action = Record.Types.Action.Upsert, - DataJson = JsonConvert.SerializeObject(recordMap) - }; + var recordMap = new Dictionary(); + + // pull in all desired properties + recordMap["Key"] = Convert.ToString(issue.Key.Value); + recordMap["Project"] = Convert.ToString(issue.Project); + recordMap["Issuetype"] = Convert.ToString(issue.Type.Name); + recordMap["Description"] = Convert.ToString(issue.Description); + recordMap["Reporter"] = Convert.ToString(issue.ReporterUser.DisplayName); + recordMap["Created"] = Convert.ToString(issue.Created.Value); + recordMap["Status"] = Convert.ToString(issue.Status.Name); + recordMap["Resolution"] = Convert.ToString(issue.Resolution); + recordMap["Updated"] = Convert.ToString(issue.Updated.Value); + + + yield return new Record + { + Action = Record.Types.Action.Upsert, + DataJson = JsonConvert.SerializeObject(recordMap) + }; + } + + startAt += itemsPerPage; } } } diff --git a/PluginJira/Helper/Settings.cs b/PluginJira/Helper/Settings.cs index aab0868..5e2fa58 100644 --- a/PluginJira/Helper/Settings.cs +++ b/PluginJira/Helper/Settings.cs @@ -10,6 +10,7 @@ public class Settings public string ApiKey { get; set; } public string Tenant { get; set; } + /// /// Validates the settings input object /// diff --git a/PluginJiraTest/Plugin/PluginIntegrationTest.cs b/PluginJiraTest/Plugin/PluginIntegrationTest.cs index c6e411c..ad0a0aa 100644 --- a/PluginJiraTest/Plugin/PluginIntegrationTest.cs +++ b/PluginJiraTest/Plugin/PluginIntegrationTest.cs @@ -296,7 +296,67 @@ public async Task ReadStreamTest() } // assert - Assert.Equal(20, records.Count); + Assert.Equal(254, records.Count); + + var record = JsonConvert.DeserializeObject>(records[0].DataJson); + // Assert.Equal("~", record["tilde"]); + + // cleanup + await channel.ShutdownAsync(); + await server.ShutdownAsync(); + } + + [Fact] + public async Task ReadStreamTest2() + { + // setup + Server server = new Server + { + Services = {Publisher.BindService(new PluginJira.Plugin.Plugin())}, + Ports = {new ServerPort("localhost", 0, ServerCredentials.Insecure)} + }; + server.Start(); + + var port = server.Ports.First().BoundPort; + + var channel = new Channel($"localhost:{port}", ChannelCredentials.Insecure); + var client = new Publisher.PublisherClient(channel); + + var schema = GetTestSchema("AllApplicationRoles"); + + var connectRequest = GetConnectSettings(); + + var schemaRequest = new DiscoverSchemasRequest + { + Mode = DiscoverSchemasRequest.Types.Mode.Refresh, + ToRefresh = {schema} + }; + + var request = new ReadRequest() + { + DataVersions = new DataVersions + { + JobId = "test" + }, + JobId = "test", + }; + + // act + client.Connect(connectRequest); + var schemasResponse = client.DiscoverSchemas(schemaRequest); + request.Schema = schemasResponse.Schemas[0]; + + var response = client.ReadStream(request); + var responseStream = response.ResponseStream; + var records = new List(); + + while (await responseStream.MoveNext()) + { + records.Add(responseStream.Current); + } + + // assert + Assert.Equal(2, records.Count); var record = JsonConvert.DeserializeObject>(records[0].DataJson); // Assert.Equal("~", record["tilde"]); From 28c30b6defeb9ca9ab402e9096426ac1239f2f83 Mon Sep 17 00:00:00 2001 From: Suyog Daga Date: Wed, 7 Apr 2021 10:40:43 -0700 Subject: [PATCH 2/5] Pagination logic for issues, overrining getcountrecords for issues and application-role endpoints --- PluginJira/API/Utility/EndpointHelper.cs | 18 +++++++----- .../ApplicationRolesEndpoint.cs | 28 +++++++++++++++++-- .../EndpointHelperEndpoints/IssuesEndpoint.cs | 13 +++++++++ .../ApplicationEndpointWrapper.cs | 26 +++++++++++++++++ ...DataWrapper.cs => IssueEndpointWrapper.cs} | 4 +-- .../Plugin/PluginIntegrationTest.cs | 8 +++--- 6 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 PluginJira/DataContracts/ApplicationEndpointWrapper.cs rename PluginJira/DataContracts/{DataWrapper.cs => IssueEndpointWrapper.cs} (73%) diff --git a/PluginJira/API/Utility/EndpointHelper.cs b/PluginJira/API/Utility/EndpointHelper.cs index f853d1d..477fc93 100644 --- a/PluginJira/API/Utility/EndpointHelper.cs +++ b/PluginJira/API/Utility/EndpointHelper.cs @@ -66,15 +66,19 @@ public abstract class Endpoint public virtual async Task GetCountOfRecords(IApiClientFactory factory, Settings settings) { - var response = await factory.CreateApiClient(settings).GetAsync($"{BasePath.TrimEnd('/')}/{AllPath.TrimStart('/')}"); + // var response = await factory.CreateApiClient(settings).GetAsync($"{BasePath.TrimEnd('/')}/{AllPath.TrimStart('/')}"); - var recordsList = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + // //var recordsList = JsonConvert.DeserializeObject (await response.Content.ReadAsStringAsync()); + // var recordsList = JsonConvert.DeserializeObject >(await response.Content.ReadAsStringAsync()); - return new Count - { - Kind = Count.Types.Kind.Exact, - Value = (int) recordsList.TotalRecords - }; + // return new Count + // { + // Kind = Count.Types.Kind.Exact, + // //Value = (int) recordsList.TotalRecords + // Value = (int) recordsList.Count() + // }; + + throw new NotImplementedException(); } public virtual IAsyncEnumerable ReadRecordsAsync(IApiClientFactory factory, Settings settings, diff --git a/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs b/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs index 45764fb..f5998db 100644 --- a/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs +++ b/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs @@ -25,14 +25,20 @@ public override async IAsyncEnumerable ReadRecordsAsync(IApiClientFactor var jira = factory.CreateApiClient(settings); var response = await jira.GetAsync("applicationrole"); - var recordsList =JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + var test = await response.Content.ReadAsStringAsync(); - foreach (var item in recordsList.Items){ + var recordsList = JsonConvert.DeserializeObject>(await response.Content.ReadAsStringAsync()); + + + foreach (var item in recordsList){ var recordMap = new Dictionary(); - recordMap.TryAdd(item.ToString(), item.Values); + recordMap["key"] = item.key; + recordMap["groups"] = item.groups; + recordMap["name"]= item.name; + yield return new Record { @@ -43,6 +49,22 @@ public override async IAsyncEnumerable ReadRecordsAsync(IApiClientFactor } + public override async Task GetCountOfRecords(IApiClientFactory factory, Settings settings) + { + var response = await factory.CreateApiClient(settings).GetAsync($"{BasePath.TrimEnd('/')}/{AllPath.TrimStart('/')}"); + + //var recordsList = JsonConvert.DeserializeObject (await response.Content.ReadAsStringAsync()); + var recordsList = JsonConvert.DeserializeObject >(await response.Content.ReadAsStringAsync()); + + return new Count + { + Kind = Count.Types.Kind.Exact, + //Value = (int) recordsList.TotalRecords + Value = (int) recordsList.Count() + }; + + //throw new NotImplementedException(); + } } public static readonly Dictionary ApplicationRolesEndpoints = new Dictionary diff --git a/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs b/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs index 525a4a7..3446690 100644 --- a/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs +++ b/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs @@ -69,6 +69,19 @@ public override async IAsyncEnumerable ReadRecordsAsync(IApiClientFactor startAt += itemsPerPage; } } + + public override async Task GetCountOfRecords(IApiClientFactory factory, Settings settings) + { + var response = await factory.CreateApiClient(settings).GetAsync($"{BasePath.TrimEnd('/')}/{AllPath.TrimStart('/')}"); + + var recordsList = JsonConvert.DeserializeObject (await response.Content.ReadAsStringAsync()); + + return new Count + { + Kind = Count.Types.Kind.Exact, + Value = (int) recordsList.TotalRecords + }; + } } public static readonly Dictionary IssuesEndpoints = new Dictionary diff --git a/PluginJira/DataContracts/ApplicationEndpointWrapper.cs b/PluginJira/DataContracts/ApplicationEndpointWrapper.cs new file mode 100644 index 0000000..44a7c93 --- /dev/null +++ b/PluginJira/DataContracts/ApplicationEndpointWrapper.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace PluginJira.DataContracts +{ + public class ApplicationEndpointWrapper + { + public string key { get; set; } + + public List groups { get; set; } + + public string name { get; set; } + public List defaultGroups { get; set; } + + public bool selectedByDefault { get; set; } + + public bool defined { get; set; } + + public long numberOfSeats { get; set; } + public long remainingSeats { get; set; } + public long userCount { get; set; } + public string userCountDescription { get; set; } + public bool hasUnlimitedSeats { get; set; } + public bool platform { get; set; } + + } +} \ No newline at end of file diff --git a/PluginJira/DataContracts/DataWrapper.cs b/PluginJira/DataContracts/IssueEndpointWrapper.cs similarity index 73% rename from PluginJira/DataContracts/DataWrapper.cs rename to PluginJira/DataContracts/IssueEndpointWrapper.cs index 0908be0..030cb1c 100644 --- a/PluginJira/DataContracts/DataWrapper.cs +++ b/PluginJira/DataContracts/IssueEndpointWrapper.cs @@ -2,12 +2,12 @@ namespace PluginJira.DataContracts { - public class DataWrapper + public class IssueEndpointWrapper { public long PageSize { get; set; } public long PageNumber { get; set; } public long TotalRecords { get; set; } public long TotalPages { get; set; } - public List>? Items { get; set; } + } } \ No newline at end of file diff --git a/PluginJiraTest/Plugin/PluginIntegrationTest.cs b/PluginJiraTest/Plugin/PluginIntegrationTest.cs index ad0a0aa..ae58a3b 100644 --- a/PluginJiraTest/Plugin/PluginIntegrationTest.cs +++ b/PluginJiraTest/Plugin/PluginIntegrationTest.cs @@ -20,9 +20,9 @@ private Settings GetSettings() { return new Settings { - ApiKey = "test123", - Username = "test123", - Tenant = "test123" + ApiKey = "uCkrVYuQ5ZE3GhZoDuDMC48E", + Username = "support@qumulussolutions.com", + Tenant = "qumulus" }; } @@ -356,7 +356,7 @@ public async Task ReadStreamTest2() } // assert - Assert.Equal(2, records.Count); + Assert.Equal(1, records.Count); var record = JsonConvert.DeserializeObject>(records[0].DataJson); // Assert.Equal("~", record["tilde"]); From 4eacc6436169b6f1a54599076313178e71254671 Mon Sep 17 00:00:00 2001 From: Suyog Daga Date: Thu, 8 Apr 2021 12:32:08 -0700 Subject: [PATCH 3/5] Removing unnecessary lines and comments, formatting code as review guidelines --- PluginJira/API/Factory/ApiClient.cs | 1 - PluginJira/API/Utility/EndpointHelper.cs | 15 ------ .../ApplicationRolesEndpoint.cs | 47 ++++++++----------- .../EndpointHelperEndpoints/IssuesEndpoint.cs | 18 ++++--- .../ApplicationEndpointWrapper.cs | 43 ++++++++++++----- PluginJira/Helper/Settings.cs | 2 - .../Plugin/PluginIntegrationTest.cs | 8 ++-- 7 files changed, 62 insertions(+), 72 deletions(-) diff --git a/PluginJira/API/Factory/ApiClient.cs b/PluginJira/API/Factory/ApiClient.cs index 903473c..4b4e9bd 100644 --- a/PluginJira/API/Factory/ApiClient.cs +++ b/PluginJira/API/Factory/ApiClient.cs @@ -68,7 +68,6 @@ public async Task GetAsync(string path) Method = HttpMethod.Get, RequestUri = uri, }; - //request.Headers.Add(_tokenHeaderName, token); // Add basic authentication request.Headers.Authorization = new AuthenticationHeaderValue("Basic", token); diff --git a/PluginJira/API/Utility/EndpointHelper.cs b/PluginJira/API/Utility/EndpointHelper.cs index 477fc93..401cb40 100644 --- a/PluginJira/API/Utility/EndpointHelper.cs +++ b/PluginJira/API/Utility/EndpointHelper.cs @@ -66,28 +66,13 @@ public abstract class Endpoint public virtual async Task GetCountOfRecords(IApiClientFactory factory, Settings settings) { - // var response = await factory.CreateApiClient(settings).GetAsync($"{BasePath.TrimEnd('/')}/{AllPath.TrimStart('/')}"); - - // //var recordsList = JsonConvert.DeserializeObject (await response.Content.ReadAsStringAsync()); - // var recordsList = JsonConvert.DeserializeObject >(await response.Content.ReadAsStringAsync()); - - // return new Count - // { - // Kind = Count.Types.Kind.Exact, - // //Value = (int) recordsList.TotalRecords - // Value = (int) recordsList.Count() - // }; - throw new NotImplementedException(); } public virtual IAsyncEnumerable ReadRecordsAsync(IApiClientFactory factory, Settings settings, DateTime? lastReadTime = null, TaskCompletionSource? tcs = null, bool isDiscoverRead = false) { - throw new NotImplementedException(); - - } public virtual async Task WriteRecordAsync(IApiClient apiClient, Schema schema, Record record, diff --git a/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs b/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs index f5998db..e10afd3 100644 --- a/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs +++ b/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs @@ -26,45 +26,38 @@ public override async IAsyncEnumerable ReadRecordsAsync(IApiClientFactor var response = await jira.GetAsync("applicationrole"); - var test = await response.Content.ReadAsStringAsync(); - var recordsList = JsonConvert.DeserializeObject>(await response.Content.ReadAsStringAsync()); - - foreach (var item in recordsList){ - + foreach (var item in recordsList) + { var recordMap = new Dictionary(); - recordMap["key"] = item.key; - recordMap["groups"] = item.groups; - recordMap["name"]= item.name; + recordMap["key"] = item.Key; + recordMap["groups"] = item.Groups; + recordMap["name"]= item.Name; - - yield return new Record - { + yield return new Record + { Action = Record.Types.Action.Upsert, DataJson = JsonConvert.SerializeObject(recordMap) - }; - } - + }; } - public override async Task GetCountOfRecords(IApiClientFactory factory, Settings settings) - { - var response = await factory.CreateApiClient(settings).GetAsync($"{BasePath.TrimEnd('/')}/{AllPath.TrimStart('/')}"); + } - //var recordsList = JsonConvert.DeserializeObject (await response.Content.ReadAsStringAsync()); - var recordsList = JsonConvert.DeserializeObject >(await response.Content.ReadAsStringAsync()); - - return new Count + public override async Task GetCountOfRecords(IApiClientFactory factory, Settings settings) { - Kind = Count.Types.Kind.Exact, - //Value = (int) recordsList.TotalRecords - Value = (int) recordsList.Count() - }; + var response = await factory.CreateApiClient(settings).GetAsync($"{BasePath.TrimEnd('/')}/{AllPath.TrimStart('/')}"); - //throw new NotImplementedException(); - } + var recordsList = JsonConvert.DeserializeObject >(await response.Content.ReadAsStringAsync()); + + return new Count + { + Kind = Count.Types.Kind.Exact, + Value = (int) recordsList.Count() + }; + + } } public static readonly Dictionary ApplicationRolesEndpoints = new Dictionary diff --git a/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs b/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs index 3446690..14516d0 100644 --- a/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs +++ b/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs @@ -24,23 +24,22 @@ public override async IAsyncEnumerable ReadRecordsAsync(IApiClientFactor // fetch all records var jira = factory.CreateJiraClient(settings); - string projectKey = "DEMO"; - + var projectKey = "DEMO"; // Adding logic for pagination - int itemsPerPage = 50; - int startAt = 0; + var itemsPerPage = 50; - while(true) - { + var startAt = 0; + while (true) + { var issues = await jira.Issues.GetIssuesFromJqlAsync($"project = {projectKey} ORDER BY created DESC", itemsPerPage, startAt); - if (issues.Count() == 0) + { break; - - + } + // iterate and return each record // foreach on results of JQL foreach (var issue in issues) @@ -58,7 +57,6 @@ public override async IAsyncEnumerable ReadRecordsAsync(IApiClientFactor recordMap["Resolution"] = Convert.ToString(issue.Resolution); recordMap["Updated"] = Convert.ToString(issue.Updated.Value); - yield return new Record { Action = Record.Types.Action.Upsert, diff --git a/PluginJira/DataContracts/ApplicationEndpointWrapper.cs b/PluginJira/DataContracts/ApplicationEndpointWrapper.cs index 44a7c93..d0b0235 100644 --- a/PluginJira/DataContracts/ApplicationEndpointWrapper.cs +++ b/PluginJira/DataContracts/ApplicationEndpointWrapper.cs @@ -1,26 +1,45 @@ using System.Collections.Generic; +using Newtonsoft.Json; namespace PluginJira.DataContracts { public class ApplicationEndpointWrapper { - public string key { get; set; } + [JsonProperty("key")] + public string Key { get; set; } - public List groups { get; set; } + [JsonProperty("groups")] + public List Groups { get; set; } - public string name { get; set; } - public List defaultGroups { get; set; } + [JsonProperty("name")] + public string Name { get; set; } - public bool selectedByDefault { get; set; } + [JsonProperty("defaultGroups")] + public List DefaultGroups { get; set; } - public bool defined { get; set; } + [JsonProperty("selectedByDefault")] + public bool SelectedByDefault { get; set; } - public long numberOfSeats { get; set; } - public long remainingSeats { get; set; } - public long userCount { get; set; } - public string userCountDescription { get; set; } - public bool hasUnlimitedSeats { get; set; } - public bool platform { get; set; } + [JsonProperty("defined")] + public bool Defined { get; set; } + + [JsonProperty("numberOfSeats")] + public long NumberOfSeats { get; set; } + + [JsonProperty("remainingSeats")] + public long RemainingSeats { get; set; } + + [JsonProperty("userCount")] + public long UserCount { get; set; } + + [JsonProperty("userCountDescription")] + public string UserCountDescription { get; set; } + + [JsonProperty("hasUnlimitedSeats")] + public bool HasUnlimitedSeats { get; set; } + + [JsonProperty("platform")] + public bool Platform { get; set; } } } \ No newline at end of file diff --git a/PluginJira/Helper/Settings.cs b/PluginJira/Helper/Settings.cs index 5e2fa58..285c992 100644 --- a/PluginJira/Helper/Settings.cs +++ b/PluginJira/Helper/Settings.cs @@ -5,12 +5,10 @@ namespace PluginJira.Helper { public class Settings { - public string Username { get; set; } public string ApiKey { get; set; } public string Tenant { get; set; } - /// /// Validates the settings input object /// diff --git a/PluginJiraTest/Plugin/PluginIntegrationTest.cs b/PluginJiraTest/Plugin/PluginIntegrationTest.cs index ae58a3b..528edd9 100644 --- a/PluginJiraTest/Plugin/PluginIntegrationTest.cs +++ b/PluginJiraTest/Plugin/PluginIntegrationTest.cs @@ -20,9 +20,9 @@ private Settings GetSettings() { return new Settings { - ApiKey = "uCkrVYuQ5ZE3GhZoDuDMC48E", - Username = "support@qumulussolutions.com", - Tenant = "qumulus" + ApiKey = "test123", + Username = "test123", + Tenant = "test123" }; } @@ -299,7 +299,6 @@ public async Task ReadStreamTest() Assert.Equal(254, records.Count); var record = JsonConvert.DeserializeObject>(records[0].DataJson); - // Assert.Equal("~", record["tilde"]); // cleanup await channel.ShutdownAsync(); @@ -359,7 +358,6 @@ public async Task ReadStreamTest2() Assert.Equal(1, records.Count); var record = JsonConvert.DeserializeObject>(records[0].DataJson); - // Assert.Equal("~", record["tilde"]); // cleanup await channel.ShutdownAsync(); From a95fd497fb967d124d1af2940e223f43393269e5 Mon Sep 17 00:00:00 2001 From: Suyog Daga Date: Thu, 8 Apr 2021 14:07:08 -0700 Subject: [PATCH 4/5] Dynamic project string, changed GetCountOfRecords and deleted IssueEndpointWrapper --- .../ApplicationRolesEndpoint.cs | 3 +-- .../EndpointHelperEndpoints/IssuesEndpoint.cs | 12 ++++++++---- PluginJira/DataContracts/IssueEndpointWrapper.cs | 13 ------------- PluginJira/Helper/Settings.cs | 13 ++++++++++++- PluginJiraTest/Plugin/PluginIntegrationTest.cs | 8 +++++--- 5 files changed, 26 insertions(+), 23 deletions(-) delete mode 100644 PluginJira/DataContracts/IssueEndpointWrapper.cs diff --git a/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs b/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs index e10afd3..971e160 100644 --- a/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs +++ b/PluginJira/API/Utility/EndpointHelperEndpoints/ApplicationRolesEndpoint.cs @@ -53,8 +53,7 @@ public override async Task GetCountOfRecords(IApiClientFactory factory, S return new Count { - Kind = Count.Types.Kind.Exact, - Value = (int) recordsList.Count() + Kind = Count.Types.Kind.Unavailable }; } diff --git a/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs b/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs index 14516d0..797daec 100644 --- a/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs +++ b/PluginJira/API/Utility/EndpointHelperEndpoints/IssuesEndpoint.cs @@ -24,7 +24,7 @@ public override async IAsyncEnumerable ReadRecordsAsync(IApiClientFactor // fetch all records var jira = factory.CreateJiraClient(settings); - var projectKey = "DEMO"; + var projectKey = settings.GetProject(); // Adding logic for pagination var itemsPerPage = 50; @@ -70,14 +70,18 @@ public override async IAsyncEnumerable ReadRecordsAsync(IApiClientFactor public override async Task GetCountOfRecords(IApiClientFactory factory, Settings settings) { - var response = await factory.CreateApiClient(settings).GetAsync($"{BasePath.TrimEnd('/')}/{AllPath.TrimStart('/')}"); + var jira = factory.CreateJiraClient(settings); + + var projectKey = settings.GetProject(); + + var issues = await jira.Issues.GetIssuesFromJqlAsync($"project = {projectKey} ORDER BY created DESC"); - var recordsList = JsonConvert.DeserializeObject (await response.Content.ReadAsStringAsync()); + var total = issues.TotalItems; return new Count { Kind = Count.Types.Kind.Exact, - Value = (int) recordsList.TotalRecords + Value = (int) total }; } } diff --git a/PluginJira/DataContracts/IssueEndpointWrapper.cs b/PluginJira/DataContracts/IssueEndpointWrapper.cs deleted file mode 100644 index 030cb1c..0000000 --- a/PluginJira/DataContracts/IssueEndpointWrapper.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; - -namespace PluginJira.DataContracts -{ - public class IssueEndpointWrapper - { - public long PageSize { get; set; } - public long PageNumber { get; set; } - public long TotalRecords { get; set; } - public long TotalPages { get; set; } - - } -} \ No newline at end of file diff --git a/PluginJira/Helper/Settings.cs b/PluginJira/Helper/Settings.cs index 285c992..12a272c 100644 --- a/PluginJira/Helper/Settings.cs +++ b/PluginJira/Helper/Settings.cs @@ -8,6 +8,7 @@ public class Settings public string Username { get; set; } public string ApiKey { get; set; } public string Tenant { get; set; } + public string Project { get; set; } /// /// Validates the settings input object @@ -29,7 +30,12 @@ public void Validate() throw new Exception("The Api Key property must be set"); } - if (string.IsNullOrWhiteSpace(Tenant)) + if (string.IsNullOrWhiteSpace(Tenant)) + { + throw new Exception("The Tenant is not set properly"); + } + + if (string.IsNullOrWhiteSpace(Project)) { throw new Exception("The Tenant is not set properly"); } @@ -44,5 +50,10 @@ public string GetBaseUri() { return $"https://{Tenant}.atlassian.net/rest/api/2"; } + + public string GetProject() + { + return $"{Project}"; + } } } \ No newline at end of file diff --git a/PluginJiraTest/Plugin/PluginIntegrationTest.cs b/PluginJiraTest/Plugin/PluginIntegrationTest.cs index 528edd9..9d6e71f 100644 --- a/PluginJiraTest/Plugin/PluginIntegrationTest.cs +++ b/PluginJiraTest/Plugin/PluginIntegrationTest.cs @@ -20,9 +20,10 @@ private Settings GetSettings() { return new Settings { - ApiKey = "test123", - Username = "test123", - Tenant = "test123" + ApiKey = "uCkrVYuQ5ZE3GhZoDuDMC48E", + Username = "support@qumulussolutions.com", + Tenant = "qumulus", + Project="Demo" }; } @@ -359,6 +360,7 @@ public async Task ReadStreamTest2() var record = JsonConvert.DeserializeObject>(records[0].DataJson); + // cleanup await channel.ShutdownAsync(); await server.ShutdownAsync(); From 8ae53282e774ad8cbce553ee8a82baa49b939094 Mon Sep 17 00:00:00 2001 From: Suyog Daga Date: Thu, 8 Apr 2021 14:09:46 -0700 Subject: [PATCH 5/5] Changed credentials --- PluginJiraTest/Plugin/PluginIntegrationTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PluginJiraTest/Plugin/PluginIntegrationTest.cs b/PluginJiraTest/Plugin/PluginIntegrationTest.cs index 9d6e71f..1f312ed 100644 --- a/PluginJiraTest/Plugin/PluginIntegrationTest.cs +++ b/PluginJiraTest/Plugin/PluginIntegrationTest.cs @@ -20,10 +20,10 @@ private Settings GetSettings() { return new Settings { - ApiKey = "uCkrVYuQ5ZE3GhZoDuDMC48E", - Username = "support@qumulussolutions.com", - Tenant = "qumulus", - Project="Demo" + ApiKey = "test123", + Username = "test123", + Tenant = "test123", + Project="test" }; }