From de4ba5777b32cf1696a203d601eb52a5a37fba0a Mon Sep 17 00:00:00 2001 From: Christian LaCourt Date: Thu, 19 Jul 2018 09:28:41 -0400 Subject: [PATCH 1/5] Return the full list of items with GetAll when the total count is less than 1000 --- SnipeSharp/Endpoints/EndPointManager.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/SnipeSharp/Endpoints/EndPointManager.cs b/SnipeSharp/Endpoints/EndPointManager.cs index 7847c11..47de118 100644 --- a/SnipeSharp/Endpoints/EndPointManager.cs +++ b/SnipeSharp/Endpoints/EndPointManager.cs @@ -40,9 +40,7 @@ public ResponseCollection GetAll() // If there are more than 1000 assets split up the requests to avoid timeouts if (count.Total < 1000) { - string response = _reqManager.Get(_endPoint); - ResponseCollection results = JsonConvert.DeserializeObject>(response); - return results; + return FindAll(new SearchFilter { Limit = (int) count.Total }); } else { From 76590d806276f7e3954865562c04766befc2588c Mon Sep 17 00:00:00 2001 From: Christian LaCourt Date: Thu, 19 Jul 2018 09:55:12 -0400 Subject: [PATCH 2/5] Return the full filtered list of items with FindAll when a limit is not provided and the total count is greater than the page size --- SnipeSharp/Endpoints/EndPointManager.cs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/SnipeSharp/Endpoints/EndPointManager.cs b/SnipeSharp/Endpoints/EndPointManager.cs index 47de118..e80bf7b 100644 --- a/SnipeSharp/Endpoints/EndPointManager.cs +++ b/SnipeSharp/Endpoints/EndPointManager.cs @@ -79,8 +79,26 @@ public ResponseCollection GetAll() /// public ResponseCollection FindAll(ISearchFilter filter) { - string response = _reqManager.Get(_endPoint, filter); - ResponseCollection results = JsonConvert.DeserializeObject>(response); + var response = _reqManager.Get(_endPoint, filter); + var results = JsonConvert.DeserializeObject>(response); + + // If there is no limit and there are more total than retrieved + if(filter.Limit == null && results.Rows.Count < results.Total) + { + filter.Limit = 1000; + filter.Offset = (filter.Offset == null ? 0 : filter.Offset) + results.Rows.Count; + + while (results.Rows.Count < results.Total) + { + response = _reqManager.Get(_endPoint, filter); + var batch = JsonConvert.DeserializeObject>(response); + + results.Rows.AddRange(batch.Rows); + + filter.Offset += 1000; + } + } + return results; } From 5b4f7545e985288c2413e4bb1ea2c800d0a01a6d Mon Sep 17 00:00:00 2001 From: Christian LaCourt Date: Thu, 19 Jul 2018 10:20:28 -0400 Subject: [PATCH 3/5] Fixed bug introduced by previous commit where too much would be grabbed when an offset was specified in the filter --- SnipeSharp/Endpoints/EndPointManager.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SnipeSharp/Endpoints/EndPointManager.cs b/SnipeSharp/Endpoints/EndPointManager.cs index e80bf7b..e0a8118 100644 --- a/SnipeSharp/Endpoints/EndPointManager.cs +++ b/SnipeSharp/Endpoints/EndPointManager.cs @@ -82,13 +82,14 @@ public ResponseCollection FindAll(ISearchFilter filter) var response = _reqManager.Get(_endPoint, filter); var results = JsonConvert.DeserializeObject>(response); + var baseOffset = filter.Offset == null ? 0 : filter.Offset; // If there is no limit and there are more total than retrieved - if(filter.Limit == null && results.Rows.Count < results.Total) + if(filter.Limit == null && baseOffset + results.Rows.Count < results.Total) { filter.Limit = 1000; - filter.Offset = (filter.Offset == null ? 0 : filter.Offset) + results.Rows.Count; + filter.Offset = baseOffset + results.Rows.Count; - while (results.Rows.Count < results.Total) + while (baseOffset + results.Rows.Count < results.Total) { response = _reqManager.Get(_endPoint, filter); var batch = JsonConvert.DeserializeObject>(response); From 768eacd93f1ffca9d666ac64962530a8bb642f35 Mon Sep 17 00:00:00 2001 From: Christian LaCourt Date: Mon, 23 Jul 2018 13:02:33 -0400 Subject: [PATCH 4/5] Add check to avoid out-of-bounds index --- SnipeSharp/Endpoints/EndPointManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SnipeSharp/Endpoints/EndPointManager.cs b/SnipeSharp/Endpoints/EndPointManager.cs index e0a8118..c682832 100644 --- a/SnipeSharp/Endpoints/EndPointManager.cs +++ b/SnipeSharp/Endpoints/EndPointManager.cs @@ -112,7 +112,7 @@ public T FindOne(ISearchFilter filter) { string response = _reqManager.Get(_endPoint, filter); ResponseCollection result = JsonConvert.DeserializeObject>(response); - return (result.Rows != null) ? result.Rows[0] : default(T); + return (result.Rows != null && result.Rows.Count > 0) ? result.Rows[0] : default(T); } /// From eadd5ce468682b0a34db16ab568303156db6d5e9 Mon Sep 17 00:00:00 2001 From: Christian LaCourt Date: Mon, 23 Jul 2018 14:55:51 -0400 Subject: [PATCH 5/5] Make Get(int) return null instead of garbage when result does not exist. --- .../EndpointObjectNotFoundMessage.cs | 17 +++++++++++++++ SnipeSharp/Endpoints/EndPointManager.cs | 21 ++++++++++++++----- SnipeSharp/Endpoints/Models/Accessory.cs | 1 + SnipeSharp/Endpoints/Models/Asset.cs | 1 + SnipeSharp/Endpoints/Models/Category.cs | 1 + SnipeSharp/Endpoints/Models/Company.cs | 4 +++- SnipeSharp/Endpoints/Models/Component.cs | 1 + SnipeSharp/Endpoints/Models/Consumable.cs | 1 + SnipeSharp/Endpoints/Models/Department.cs | 1 + SnipeSharp/Endpoints/Models/Depreciation.cs | 1 + SnipeSharp/Endpoints/Models/FieldSet.cs | 4 +++- SnipeSharp/Endpoints/Models/License.cs | 2 ++ SnipeSharp/Endpoints/Models/Location.cs | 1 + SnipeSharp/Endpoints/Models/Manufacturer.cs | 2 +- SnipeSharp/Endpoints/Models/Model.cs | 1 + SnipeSharp/Endpoints/Models/StatusLabel.cs | 1 + SnipeSharp/Endpoints/Models/Supplier.cs | 1 + SnipeSharp/Endpoints/Models/User.cs | 1 + SnipeSharp/SnipeSharp.csproj | 1 + 19 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 SnipeSharp/Attributes/EndpointObjectNotFoundMessage.cs diff --git a/SnipeSharp/Attributes/EndpointObjectNotFoundMessage.cs b/SnipeSharp/Attributes/EndpointObjectNotFoundMessage.cs new file mode 100644 index 0000000..b0bd01c --- /dev/null +++ b/SnipeSharp/Attributes/EndpointObjectNotFoundMessage.cs @@ -0,0 +1,17 @@ +using System; + +namespace SnipeSharp.Attributes +{ + /// + /// Since the SnipeIT Api uses inconsistent error string to note whether or not an object exists or not, we can use this attribute to declare it. + /// + [AttributeUsage(AttributeTargets.Class)] + public class EndpointObjectNotFoundMessage : Attribute + { + public string Message { get; private set; } + public EndpointObjectNotFoundMessage(string notFoundMessage) + { + Message = notFoundMessage; + } + } +} diff --git a/SnipeSharp/Endpoints/EndPointManager.cs b/SnipeSharp/Endpoints/EndPointManager.cs index c682832..85f766e 100644 --- a/SnipeSharp/Endpoints/EndPointManager.cs +++ b/SnipeSharp/Endpoints/EndPointManager.cs @@ -1,7 +1,9 @@ using Newtonsoft.Json; +using SnipeSharp.Attributes; using SnipeSharp.Common; using SnipeSharp.Endpoints.Models; using SnipeSharp.Endpoints.SearchFilters; +using System; using System.Collections.Generic; using System.Linq; @@ -15,6 +17,7 @@ public class EndPointManager where T : CommonEndpointModel { protected IRequestManager _reqManager; protected string _endPoint; + protected string _notFoundMessage; /// /// @@ -25,6 +28,11 @@ public EndPointManager(IRequestManager reqManager, string endPoint) { _reqManager = reqManager; _endPoint = endPoint; + var attribute = typeof(T).GetCustomAttributes(typeof(EndpointObjectNotFoundMessage), true).FirstOrDefault() as EndpointObjectNotFoundMessage; + if(attribute != null) + { + _notFoundMessage = attribute.Message; + } } /// @@ -122,11 +130,14 @@ public T FindOne(ISearchFilter filter) /// public T Get(int id) { - // TODO: Find better way to deal with objects that are not found - T result; - string response = _reqManager.Get(string.Format("{0}/{1}", _endPoint, id.ToString())); - result = JsonConvert.DeserializeObject(response); - return result; + var response = _reqManager.Get(string.Format("{0}/{1}", _endPoint, id.ToString())); + // Parse the response as a message to see if there's a result. + var message = JsonConvert.DeserializeObject(response); + // If there isn't a result, return default(T). + if(message.Status == "error" && message.Messages.ContainsKey("general") && message.Messages["general"] == _notFoundMessage) + return default(T); + // We do have one, so re-deserialize the response as the type we want. + return JsonConvert.DeserializeObject(response); } /// diff --git a/SnipeSharp/Endpoints/Models/Accessory.cs b/SnipeSharp/Endpoints/Models/Accessory.cs index c9ba3c0..d7a1298 100644 --- a/SnipeSharp/Endpoints/Models/Accessory.cs +++ b/SnipeSharp/Endpoints/Models/Accessory.cs @@ -4,6 +4,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Accessory not found")] public class Accessory : CommonEndpointModel { [JsonProperty("company")] diff --git a/SnipeSharp/Endpoints/Models/Asset.cs b/SnipeSharp/Endpoints/Models/Asset.cs index fad0472..d8a899c 100644 --- a/SnipeSharp/Endpoints/Models/Asset.cs +++ b/SnipeSharp/Endpoints/Models/Asset.cs @@ -10,6 +10,7 @@ namespace SnipeSharp.Endpoints.Models { // TODO: Make constructor that forces required fields + [EndpointObjectNotFoundMessage("Asset not found")] public class Asset : CommonEndpointModel { diff --git a/SnipeSharp/Endpoints/Models/Category.cs b/SnipeSharp/Endpoints/Models/Category.cs index 37a2149..55830c4 100644 --- a/SnipeSharp/Endpoints/Models/Category.cs +++ b/SnipeSharp/Endpoints/Models/Category.cs @@ -5,6 +5,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Category not found")] public class Category : CommonEndpointModel { [JsonProperty("image")] diff --git a/SnipeSharp/Endpoints/Models/Company.cs b/SnipeSharp/Endpoints/Models/Company.cs index cdba025..31f0160 100644 --- a/SnipeSharp/Endpoints/Models/Company.cs +++ b/SnipeSharp/Endpoints/Models/Company.cs @@ -1,8 +1,10 @@ -using SnipeSharp.Common; +using SnipeSharp.Attributes; +using SnipeSharp.Common; using Newtonsoft.Json; namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Company not found")] public class Company : CommonEndpointModel { [JsonProperty("image")] diff --git a/SnipeSharp/Endpoints/Models/Component.cs b/SnipeSharp/Endpoints/Models/Component.cs index 984ba4c..f21cffe 100644 --- a/SnipeSharp/Endpoints/Models/Component.cs +++ b/SnipeSharp/Endpoints/Models/Component.cs @@ -4,6 +4,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Component not found")] public class Component : CommonEndpointModel { [JsonProperty("serial_number")] diff --git a/SnipeSharp/Endpoints/Models/Consumable.cs b/SnipeSharp/Endpoints/Models/Consumable.cs index e2c5fd3..1cfda5d 100644 --- a/SnipeSharp/Endpoints/Models/Consumable.cs +++ b/SnipeSharp/Endpoints/Models/Consumable.cs @@ -4,6 +4,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Consumable not found")] public class Consumable : CommonEndpointModel { [JsonProperty("category")] diff --git a/SnipeSharp/Endpoints/Models/Department.cs b/SnipeSharp/Endpoints/Models/Department.cs index 522c8c0..1263c8d 100644 --- a/SnipeSharp/Endpoints/Models/Department.cs +++ b/SnipeSharp/Endpoints/Models/Department.cs @@ -4,6 +4,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Department not found")] public class Department : CommonEndpointModel { [JsonProperty("company_id")] diff --git a/SnipeSharp/Endpoints/Models/Depreciation.cs b/SnipeSharp/Endpoints/Models/Depreciation.cs index 561c8e6..3cb4e99 100644 --- a/SnipeSharp/Endpoints/Models/Depreciation.cs +++ b/SnipeSharp/Endpoints/Models/Depreciation.cs @@ -4,6 +4,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Depreciation not found")] public class Depreciation : CommonEndpointModel { diff --git a/SnipeSharp/Endpoints/Models/FieldSet.cs b/SnipeSharp/Endpoints/Models/FieldSet.cs index 77970dd..2461ccc 100644 --- a/SnipeSharp/Endpoints/Models/FieldSet.cs +++ b/SnipeSharp/Endpoints/Models/FieldSet.cs @@ -1,8 +1,10 @@ -using SnipeSharp.Common; +using SnipeSharp.Attributes; +using SnipeSharp.Common; using Newtonsoft.Json; namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Fieldset does not exist")] public class FieldSet : CommonEndpointModel { [JsonProperty("fields")] diff --git a/SnipeSharp/Endpoints/Models/License.cs b/SnipeSharp/Endpoints/Models/License.cs index 0f5cd81..1f4e56b 100644 --- a/SnipeSharp/Endpoints/Models/License.cs +++ b/SnipeSharp/Endpoints/Models/License.cs @@ -1,8 +1,10 @@ using Newtonsoft.Json; +using SnipeSharp.Attributes; using SnipeSharp.Common; namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("License not found")] public class License : CommonEndpointModel { diff --git a/SnipeSharp/Endpoints/Models/Location.cs b/SnipeSharp/Endpoints/Models/Location.cs index c09ab36..cea6c47 100644 --- a/SnipeSharp/Endpoints/Models/Location.cs +++ b/SnipeSharp/Endpoints/Models/Location.cs @@ -5,6 +5,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Location not found")] public class Location : CommonEndpointModel { [JsonProperty("image")] diff --git a/SnipeSharp/Endpoints/Models/Manufacturer.cs b/SnipeSharp/Endpoints/Models/Manufacturer.cs index 6e99a28..680206b 100644 --- a/SnipeSharp/Endpoints/Models/Manufacturer.cs +++ b/SnipeSharp/Endpoints/Models/Manufacturer.cs @@ -5,7 +5,7 @@ namespace SnipeSharp.Endpoints.Models { - + [EndpointObjectNotFoundMessage("Manufacturer not found")] public class Manufacturer : CommonEndpointModel { [JsonProperty("url")] diff --git a/SnipeSharp/Endpoints/Models/Model.cs b/SnipeSharp/Endpoints/Models/Model.cs index cd7bfbc..5ffc317 100644 --- a/SnipeSharp/Endpoints/Models/Model.cs +++ b/SnipeSharp/Endpoints/Models/Model.cs @@ -4,6 +4,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("AssetModel not found")] public class Model : CommonEndpointModel { diff --git a/SnipeSharp/Endpoints/Models/StatusLabel.cs b/SnipeSharp/Endpoints/Models/StatusLabel.cs index 0df12ff..d13f828 100644 --- a/SnipeSharp/Endpoints/Models/StatusLabel.cs +++ b/SnipeSharp/Endpoints/Models/StatusLabel.cs @@ -6,6 +6,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Statuslabel not found")] public class StatusLabel : CommonEndpointModel { private string _type; diff --git a/SnipeSharp/Endpoints/Models/Supplier.cs b/SnipeSharp/Endpoints/Models/Supplier.cs index bb5eeb7..75dfaff 100644 --- a/SnipeSharp/Endpoints/Models/Supplier.cs +++ b/SnipeSharp/Endpoints/Models/Supplier.cs @@ -4,6 +4,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("Supplier not found")] public class Supplier : CommonEndpointModel { [JsonProperty("name")] diff --git a/SnipeSharp/Endpoints/Models/User.cs b/SnipeSharp/Endpoints/Models/User.cs index 6e0ed28..d599937 100644 --- a/SnipeSharp/Endpoints/Models/User.cs +++ b/SnipeSharp/Endpoints/Models/User.cs @@ -5,6 +5,7 @@ namespace SnipeSharp.Endpoints.Models { + [EndpointObjectNotFoundMessage("User not found")] public class User : CommonEndpointModel { diff --git a/SnipeSharp/SnipeSharp.csproj b/SnipeSharp/SnipeSharp.csproj index b8b7840..6abdaf5 100644 --- a/SnipeSharp/SnipeSharp.csproj +++ b/SnipeSharp/SnipeSharp.csproj @@ -52,6 +52,7 @@ +