From 2c02dfe45a6d1252bfef557db8f39f97e57d3d19 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 22 Sep 2017 00:47:46 -0400 Subject: rewrite to make update-check logic vendor-agnostic (#336) --- .../Framework/ModRepositories/IModRepository.cs | 24 +++++++ .../Framework/ModRepositories/NexusRepository.cs | 80 ++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs create mode 100644 src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs (limited to 'src/StardewModdingAPI.Web/Framework/ModRepositories') diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs new file mode 100644 index 00000000..43bad4e9 --- /dev/null +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs @@ -0,0 +1,24 @@ +using System; +using System.Threading.Tasks; +using StardewModdingAPI.Web.Models; + +namespace StardewModdingAPI.Web.Framework.ModRepositories +{ + /// A repository which provides mod metadata. + internal interface IModRepository : IDisposable + { + /********* + ** Accessors + *********/ + /// The unique key for this vendor. + string VendorKey { get; } + + + /********* + ** Public methods + *********/ + /// Get metadata about a mod in the repository. + /// The mod ID in this repository. + Task GetModInfoAsync(string id); + } +} diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs new file mode 100644 index 00000000..37f309da --- /dev/null +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs @@ -0,0 +1,80 @@ +using System; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Pathoschild.Http.Client; +using StardewModdingAPI.Web.Models; + +namespace StardewModdingAPI.Web.Framework.ModRepositories +{ + /// An HTTP client for fetching mod metadata from Nexus Mods. + internal class NexusRepository : IModRepository + { + /********* + ** Properties + *********/ + /// The underlying HTTP client. + private readonly IClient Client; + + + /********* + ** Accessors + *********/ + /// The unique key for this vendor. + public string VendorKey { get; } = "Nexus"; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + public NexusRepository() + { + this.Client = new FluentClient("http://www.nexusmods.com/stardewvalley") + .SetUserAgent("Nexus Client v0.63.15"); + } + + /// Get metadata about a mod in the repository. + /// The mod ID in this repository. + public async Task GetModInfoAsync(string id) + { + try + { + NexusResponseModel response = await this.Client + .GetAsync($"mods/{id}") + .As(); + return new ModGenericModel($"{this.VendorKey}:{id}", response.Name, response.Version, response.Url); + } + catch (Exception ex) + { + return new ModGenericModel($"{this.VendorKey}:{id}", ex.ToString()); + } + } + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + this.Client.Dispose(); + } + + + /********* + ** Private models + *********/ + /// A mod metadata response from Nexus Mods. + private class NexusResponseModel + { + /********* + ** Accessors + *********/ + /// The mod name. + public string Name { get; set; } + + /// The mod's semantic version number. + public string Version { get; set; } + + /// The mod's web URL. + [JsonProperty("mod_page_uri")] + public string Url { get; set; } + } + } +} -- cgit From 9c072333d161d2510ee884d71dc9a714bbf86033 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 22 Sep 2017 00:58:25 -0400 Subject: rename mods endpoint & model (#336) --- .../Controllers/CheckController.cs | 87 ---------------------- .../Controllers/ModsController.cs | 87 ++++++++++++++++++++++ .../Framework/ModRepositories/IModRepository.cs | 2 +- .../Framework/ModRepositories/NexusRepository.cs | 6 +- .../Models/ModGenericModel.cs | 55 -------------- src/StardewModdingAPI.Web/Models/ModInfoModel.cs | 55 ++++++++++++++ 6 files changed, 146 insertions(+), 146 deletions(-) delete mode 100644 src/StardewModdingAPI.Web/Controllers/CheckController.cs create mode 100644 src/StardewModdingAPI.Web/Controllers/ModsController.cs delete mode 100644 src/StardewModdingAPI.Web/Models/ModGenericModel.cs create mode 100644 src/StardewModdingAPI.Web/Models/ModInfoModel.cs (limited to 'src/StardewModdingAPI.Web/Framework/ModRepositories') diff --git a/src/StardewModdingAPI.Web/Controllers/CheckController.cs b/src/StardewModdingAPI.Web/Controllers/CheckController.cs deleted file mode 100644 index 2a346cf3..00000000 --- a/src/StardewModdingAPI.Web/Controllers/CheckController.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using StardewModdingAPI.Web.Framework.ModRepositories; -using StardewModdingAPI.Web.Models; - -namespace StardewModdingAPI.Web.Controllers -{ - /// Provides an API to perform mod update checks. - [Produces("application/json")] - [Route("api/check")] - public class CheckController : Controller - { - /********* - ** Properties - *********/ - /// The mod repositories which provide mod metadata. - private readonly IDictionary Repositories = - new IModRepository[] - { - new NexusRepository() - } - .ToDictionary(p => p.VendorKey, StringComparer.CurrentCultureIgnoreCase); - - - /********* - ** Public methods - *********/ - /// Fetch version metadata for the given mods. - /// The mod update search criteria. - [HttpPost] - public async Task Post([FromBody] ModSearchModel search) - { - IList result = new List(); - - foreach (string modKey in search.ModKeys) - { - // parse mod key - if (!this.TryParseModKey(modKey, out string vendorKey, out string modID)) - { - result.Add(new ModGenericModel(modKey, "The mod key isn't in a valid format. It should contain the mod repository key and mod ID like 'Nexus:541'.")); - continue; - } - - // get matching repository - if (!this.Repositories.TryGetValue(vendorKey, out IModRepository repository)) - { - result.Add(new ModGenericModel(modKey, "There's no mod repository matching this namespaced mod ID.")); - continue; - } - - // fetch mod info - result.Add(await repository.GetModInfoAsync(modID)); - } - - return result.ToArray(); - } - - - /********* - ** Private methods - *********/ - /// Parse a namespaced mod ID. - /// The raw mod ID to parse. - /// The parsed vendor key. - /// The parsed mod ID. - /// Returns whether the value could be parsed. - private bool TryParseModKey(string raw, out string vendorKey, out string modID) - { - // split parts - string[] parts = raw?.Split(':'); - if (parts == null || parts.Length != 2) - { - vendorKey = null; - modID = null; - return false; - } - - // parse - vendorKey = parts[0]; - modID = parts[1]; - return true; - } - } -} diff --git a/src/StardewModdingAPI.Web/Controllers/ModsController.cs b/src/StardewModdingAPI.Web/Controllers/ModsController.cs new file mode 100644 index 00000000..bbf1744f --- /dev/null +++ b/src/StardewModdingAPI.Web/Controllers/ModsController.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using StardewModdingAPI.Web.Framework.ModRepositories; +using StardewModdingAPI.Web.Models; + +namespace StardewModdingAPI.Web.Controllers +{ + /// Provides an API to perform mod update checks. + [Produces("application/json")] + public class ModsController : Controller + { + /********* + ** Properties + *********/ + /// The mod repositories which provide mod metadata. + private readonly IDictionary Repositories = + new IModRepository[] + { + new NexusRepository() + } + .ToDictionary(p => p.VendorKey, StringComparer.CurrentCultureIgnoreCase); + + + /********* + ** Public methods + *********/ + /// Fetch version metadata for the given mods. + /// The mod update search criteria. + [HttpPost] + [Route("mods")] + public async Task Post([FromBody] ModSearchModel search) + { + IList result = new List(); + + foreach (string modKey in search.ModKeys) + { + // parse mod key + if (!this.TryParseModKey(modKey, out string vendorKey, out string modID)) + { + result.Add(new ModInfoModel(modKey, "The mod key isn't in a valid format. It should contain the mod repository key and mod ID like 'Nexus:541'.")); + continue; + } + + // get matching repository + if (!this.Repositories.TryGetValue(vendorKey, out IModRepository repository)) + { + result.Add(new ModInfoModel(modKey, "There's no mod repository matching this namespaced mod ID.")); + continue; + } + + // fetch mod info + result.Add(await repository.GetModInfoAsync(modID)); + } + + return result.ToArray(); + } + + + /********* + ** Private methods + *********/ + /// Parse a namespaced mod ID. + /// The raw mod ID to parse. + /// The parsed vendor key. + /// The parsed mod ID. + /// Returns whether the value could be parsed. + private bool TryParseModKey(string raw, out string vendorKey, out string modID) + { + // split parts + string[] parts = raw?.Split(':'); + if (parts == null || parts.Length != 2) + { + vendorKey = null; + modID = null; + return false; + } + + // parse + vendorKey = parts[0]; + modID = parts[1]; + return true; + } + } +} diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs index 43bad4e9..7fd735cd 100644 --- a/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs @@ -19,6 +19,6 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories *********/ /// Get metadata about a mod in the repository. /// The mod ID in this repository. - Task GetModInfoAsync(string id); + Task GetModInfoAsync(string id); } } diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs index 37f309da..74eef2ef 100644 --- a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs @@ -35,18 +35,18 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories /// Get metadata about a mod in the repository. /// The mod ID in this repository. - public async Task GetModInfoAsync(string id) + public async Task GetModInfoAsync(string id) { try { NexusResponseModel response = await this.Client .GetAsync($"mods/{id}") .As(); - return new ModGenericModel($"{this.VendorKey}:{id}", response.Name, response.Version, response.Url); + return new ModInfoModel($"{this.VendorKey}:{id}", response.Name, response.Version, response.Url); } catch (Exception ex) { - return new ModGenericModel($"{this.VendorKey}:{id}", ex.ToString()); + return new ModInfoModel($"{this.VendorKey}:{id}", ex.ToString()); } } diff --git a/src/StardewModdingAPI.Web/Models/ModGenericModel.cs b/src/StardewModdingAPI.Web/Models/ModGenericModel.cs deleted file mode 100644 index 88a6e4bd..00000000 --- a/src/StardewModdingAPI.Web/Models/ModGenericModel.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Newtonsoft.Json; - -namespace StardewModdingAPI.Web.Models -{ - /// Generic metadata about a mod. - public class ModGenericModel - { - /********* - ** Accessors - *********/ - /// The namespaced mod key. - public string ModKey { get; } - - /// The mod name. - public string Name { get; } - - /// The mod's semantic version number. - public string Version { get; } - - /// The mod's web URL. - public string Url { get; } - - /// The error message indicating why the mod is invalid (if applicable). - public string Error { get; } - - - /********* - ** Public methods - *********/ - /// Construct a valid instance. - /// The namespaced mod key. - /// The mod name. - /// The mod's semantic version number. - /// The mod's web URL. - /// The error message indicating why the mod is invalid (if applicable). - [JsonConstructor] - public ModGenericModel(string modKey, string name, string version, string url, string error = null) - { - this.ModKey = modKey; - this.Name = name; - this.Version = version; - this.Url = url; - this.Error = error; // mainly initialised here for the JSON deserialiser - } - - /// Construct an valid instance. - /// The namespaced mod key. - /// The error message indicating why the mod is invalid. - public ModGenericModel(string modKey, string error) - { - this.ModKey = modKey; - this.Error = error; - } - } -} diff --git a/src/StardewModdingAPI.Web/Models/ModInfoModel.cs b/src/StardewModdingAPI.Web/Models/ModInfoModel.cs new file mode 100644 index 00000000..723d6c73 --- /dev/null +++ b/src/StardewModdingAPI.Web/Models/ModInfoModel.cs @@ -0,0 +1,55 @@ +using Newtonsoft.Json; + +namespace StardewModdingAPI.Web.Models +{ + /// Generic metadata about a mod. + public class ModInfoModel + { + /********* + ** Accessors + *********/ + /// The namespaced mod key. + public string ModKey { get; } + + /// The mod name. + public string Name { get; } + + /// The mod's semantic version number. + public string Version { get; } + + /// The mod's web URL. + public string Url { get; } + + /// The error message indicating why the mod is invalid (if applicable). + public string Error { get; } + + + /********* + ** Public methods + *********/ + /// Construct a valid instance. + /// The namespaced mod key. + /// The mod name. + /// The mod's semantic version number. + /// The mod's web URL. + /// The error message indicating why the mod is invalid (if applicable). + [JsonConstructor] + public ModInfoModel(string modKey, string name, string version, string url, string error = null) + { + this.ModKey = modKey; + this.Name = name; + this.Version = version; + this.Url = url; + this.Error = error; // mainly initialised here for the JSON deserialiser + } + + /// Construct an valid instance. + /// The namespaced mod key. + /// The error message indicating why the mod is invalid. + public ModInfoModel(string modKey, string error) + { + this.ModKey = modKey; + this.Error = error; + } + } +} -- cgit From 7d703c9c5ca76a99fc3d430fa2b3fd22301a5ffb Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 22 Sep 2017 02:00:15 -0400 Subject: handle invalid Nexus mod IDs (#336) --- .../Framework/ModRepositories/NexusRepository.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/StardewModdingAPI.Web/Framework/ModRepositories') diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs index 74eef2ef..7e3ce4b6 100644 --- a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs @@ -42,7 +42,10 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories NexusResponseModel response = await this.Client .GetAsync($"mods/{id}") .As(); - return new ModInfoModel($"{this.VendorKey}:{id}", response.Name, response.Version, response.Url); + + return response != null + ? new ModInfoModel($"{this.VendorKey}:{id}", response.Name, response.Version, response.Url) + : new ModInfoModel($"{this.VendorKey}:{id}", "Found no mod with this ID."); } catch (Exception ex) { -- cgit From 86d4827df211cc28549acb88ee7cb08d6cc4d4aa Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 22 Sep 2017 03:01:40 -0400 Subject: simplify input & output format (#336) --- .../Controllers/ModsController.cs | 22 +++++--- .../Framework/CommaDelimitedModelBinder.cs | 58 ---------------------- .../Framework/CommaDelimitedModelBinderProvider.cs | 27 ---------- .../Framework/ModRepositories/NexusRepository.cs | 6 +-- src/StardewModdingAPI.Web/Models/ModInfoModel.cs | 11 +--- src/StardewModdingAPI.Web/Models/ModSearchModel.cs | 9 ++++ src/StardewModdingAPI.Web/Startup.cs | 16 +----- 7 files changed, 30 insertions(+), 119 deletions(-) delete mode 100644 src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs delete mode 100644 src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinderProvider.cs create mode 100644 src/StardewModdingAPI.Web/Models/ModSearchModel.cs (limited to 'src/StardewModdingAPI.Web/Framework/ModRepositories') diff --git a/src/StardewModdingAPI.Web/Controllers/ModsController.cs b/src/StardewModdingAPI.Web/Controllers/ModsController.cs index d3b49445..876f5248 100644 --- a/src/StardewModdingAPI.Web/Controllers/ModsController.cs +++ b/src/StardewModdingAPI.Web/Controllers/ModsController.cs @@ -29,33 +29,39 @@ namespace StardewModdingAPI.Web.Controllers ** Public methods *********/ /// Fetch version metadata for the given mods. - /// The namespaced mod keys to search. - [HttpGet] - public async Task Post(IEnumerable modKeys) + /// The search options. + [HttpPost] + public async Task> Post([FromBody] ModSearchModel search) { - IList result = new List(); + // sort & filter keys + string[] modKeys = (search.ModKeys ?? new string[0]) + .Distinct(StringComparer.CurrentCultureIgnoreCase) + .OrderBy(p => p, StringComparer.CurrentCultureIgnoreCase) + .ToArray(); + // fetch mod info + IDictionary result = new Dictionary(StringComparer.CurrentCultureIgnoreCase); foreach (string modKey in modKeys) { // parse mod key if (!this.TryParseModKey(modKey, out string vendorKey, out string modID)) { - result.Add(new ModInfoModel(modKey, "The mod key isn't in a valid format. It should contain the mod repository key and mod ID like 'Nexus:541'.")); + result[modKey] = new ModInfoModel("The mod key isn't in a valid format. It should contain the mod repository key and mod ID like 'Nexus:541'."); continue; } // get matching repository if (!this.Repositories.TryGetValue(vendorKey, out IModRepository repository)) { - result.Add(new ModInfoModel(modKey, "There's no mod repository matching this namespaced mod ID.")); + result[modKey] = new ModInfoModel("There's no mod repository matching this namespaced mod ID."); continue; } // fetch mod info - result.Add(await repository.GetModInfoAsync(modID)); + result[modKey] = await repository.GetModInfoAsync(modID); } - return result.ToArray(); + return result; } diff --git a/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs b/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs deleted file mode 100644 index 119b18e6..00000000 --- a/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinder.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.ComponentModel; -using System.Reflection; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.ModelBinding; - -namespace StardewModdingAPI.Web.Framework -{ - /// Maps comma-delimited values to an parameter. - /// Derived from . - public class CommaDelimitedModelBinder : IModelBinder - { - /********* - ** Public methods - *********/ - /// Attempts to bind a model. - /// The model binding context. - public Task BindModelAsync(ModelBindingContext bindingContext) - { - // validate - if (bindingContext == null) - throw new ArgumentNullException(nameof(bindingContext)); - - // extract values - string modelName = bindingContext.ModelName; - ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(modelName); - string[] values = valueProviderResult - .ToString() - .Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - Type elementType = bindingContext.ModelType.GetTypeInfo().GenericTypeArguments[0]; - if (values.Length == 0) - { - bindingContext.Result = ModelBindingResult.Success(Array.CreateInstance(elementType, 0)); - return Task.CompletedTask; - } - - // map values - TypeConverter converter = TypeDescriptor.GetConverter(elementType); - Array typedArray = Array.CreateInstance(elementType, values.Length); - try - { - for (int i = 0; i < values.Length; ++i) - { - string value = values[i]; - object convertedValue = converter.ConvertFromString(value); - typedArray.SetValue(convertedValue, i); - } - } - catch (Exception exception) - { - bindingContext.ModelState.TryAddModelError(modelName, exception, bindingContext.ModelMetadata); - } - - bindingContext.Result = ModelBindingResult.Success(typedArray); - return Task.CompletedTask; - } - } -} diff --git a/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinderProvider.cs b/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinderProvider.cs deleted file mode 100644 index 1b3f0073..00000000 --- a/src/StardewModdingAPI.Web/Framework/CommaDelimitedModelBinderProvider.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using Microsoft.AspNetCore.Mvc.ModelBinding; - -namespace StardewModdingAPI.Web.Framework -{ - /// Provides comma-delimited model binds for mapping parameters. - /// Derived from . - public class CommaDelimitedModelBinderProvider : IModelBinderProvider - { - /********* - ** Public methods - *********/ - /// Creates a model binder based on the given context. - /// The model binding context. - public IModelBinder GetBinder(ModelBinderProviderContext context) - { - // validate - if (context == null) - throw new ArgumentNullException(nameof(context)); - - // get model binder - return context.Metadata.IsEnumerableType && !context.Metadata.ElementMetadata.IsComplexType - ? new CommaDelimitedModelBinder() - : null; - } - } -} diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs index 7e3ce4b6..02c2939a 100644 --- a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs @@ -44,12 +44,12 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories .As(); return response != null - ? new ModInfoModel($"{this.VendorKey}:{id}", response.Name, response.Version, response.Url) - : new ModInfoModel($"{this.VendorKey}:{id}", "Found no mod with this ID."); + ? new ModInfoModel(response.Name, response.Version, response.Url) + : new ModInfoModel("Found no mod with this ID."); } catch (Exception ex) { - return new ModInfoModel($"{this.VendorKey}:{id}", ex.ToString()); + return new ModInfoModel(ex.ToString()); } } diff --git a/src/StardewModdingAPI.Web/Models/ModInfoModel.cs b/src/StardewModdingAPI.Web/Models/ModInfoModel.cs index 723d6c73..180420cd 100644 --- a/src/StardewModdingAPI.Web/Models/ModInfoModel.cs +++ b/src/StardewModdingAPI.Web/Models/ModInfoModel.cs @@ -8,9 +8,6 @@ namespace StardewModdingAPI.Web.Models /********* ** Accessors *********/ - /// The namespaced mod key. - public string ModKey { get; } - /// The mod name. public string Name { get; } @@ -28,15 +25,13 @@ namespace StardewModdingAPI.Web.Models ** Public methods *********/ /// Construct a valid instance. - /// The namespaced mod key. /// The mod name. /// The mod's semantic version number. /// The mod's web URL. /// The error message indicating why the mod is invalid (if applicable). [JsonConstructor] - public ModInfoModel(string modKey, string name, string version, string url, string error = null) + public ModInfoModel(string name, string version, string url, string error = null) { - this.ModKey = modKey; this.Name = name; this.Version = version; this.Url = url; @@ -44,11 +39,9 @@ namespace StardewModdingAPI.Web.Models } /// Construct an valid instance. - /// The namespaced mod key. /// The error message indicating why the mod is invalid. - public ModInfoModel(string modKey, string error) + public ModInfoModel(string error) { - this.ModKey = modKey; this.Error = error; } } diff --git a/src/StardewModdingAPI.Web/Models/ModSearchModel.cs b/src/StardewModdingAPI.Web/Models/ModSearchModel.cs new file mode 100644 index 00000000..b5bd12fb --- /dev/null +++ b/src/StardewModdingAPI.Web/Models/ModSearchModel.cs @@ -0,0 +1,9 @@ +namespace StardewModdingAPI.Web.Models +{ + /// Metadata for mods to look up. + public class ModSearchModel + { + /// The namespaced mod keys to search. + public string[] ModKeys { get; set; } + } +} diff --git a/src/StardewModdingAPI.Web/Startup.cs b/src/StardewModdingAPI.Web/Startup.cs index 2d9a95f1..abae06ec 100644 --- a/src/StardewModdingAPI.Web/Startup.cs +++ b/src/StardewModdingAPI.Web/Startup.cs @@ -1,12 +1,9 @@ -using System.Linq; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using StardewModdingAPI.Web.Framework; namespace StardewModdingAPI.Web { @@ -40,17 +37,8 @@ namespace StardewModdingAPI.Web public void ConfigureServices(IServiceCollection services) { services - .AddMvc(options => - { - // add support for comma-delimited parameters - ArrayModelBinderProvider arrayModelBinderProvider = options.ModelBinderProviders.OfType().First(); - options.ModelBinderProviders.Insert(options.ModelBinderProviders.IndexOf(arrayModelBinderProvider), new CommaDelimitedModelBinderProvider()); - }) - .AddJsonOptions(options => - { - // suppress null values in JSON responses - options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; - }); + .AddMvc() + .AddJsonOptions(options => options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore); // suppress null values in JSON responses } /// The method called by the runtime to configure the HTTP request pipeline. -- cgit From ecdbefffd9c0acbbecd8178d7d2ac285715b5e7f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 22 Sep 2017 21:49:05 -0400 Subject: move hardcoded values into config (#336) --- .../Controllers/ModsController.cs | 27 +++++++++++++++------- .../Framework/ConfigModels/ModUpdateCheckConfig.cs | 21 +++++++++++++++++ .../Framework/ModRepositories/NexusRepository.cs | 18 +++++++++++---- src/StardewModdingAPI.Web/Startup.cs | 2 ++ src/StardewModdingAPI.Web/appsettings.json | 11 +++++++-- 5 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs (limited to 'src/StardewModdingAPI.Web/Framework/ModRepositories') diff --git a/src/StardewModdingAPI.Web/Controllers/ModsController.cs b/src/StardewModdingAPI.Web/Controllers/ModsController.cs index bd5ecef9..50c23b99 100644 --- a/src/StardewModdingAPI.Web/Controllers/ModsController.cs +++ b/src/StardewModdingAPI.Web/Controllers/ModsController.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; +using Microsoft.Extensions.Options; +using StardewModdingAPI.Web.Framework.ConfigModels; using StardewModdingAPI.Web.Framework.ModRepositories; using StardewModdingAPI.Web.Models; @@ -18,25 +20,34 @@ namespace StardewModdingAPI.Web.Controllers ** Properties *********/ /// The mod repositories which provide mod metadata. - private readonly IDictionary Repositories = - new IModRepository[] - { - new NexusRepository() - } - .ToDictionary(p => p.VendorKey, StringComparer.CurrentCultureIgnoreCase); + private readonly IDictionary Repositories; /// The cache in which to store mod metadata. private readonly IMemoryCache Cache; + /// The number of minutes update checks should be cached before refetching them. + private readonly int CacheMinutes; + /********* ** Public methods *********/ /// Construct an instance. /// The cache in which to store mod metadata. - public ModsController(IMemoryCache cache) + /// The config settings for mod update checks. + public ModsController(IMemoryCache cache, IOptions configProvider) { + ModUpdateCheckConfig config = configProvider.Value; + this.Cache = cache; + this.CacheMinutes = config.CacheMinutes; + + this.Repositories = + new IModRepository[] + { + new NexusRepository(config.NexusKey, config.NexusUserAgent, config.NexusBaseUrl, config.NexusModUrlFormat) + } + .ToDictionary(p => p.VendorKey, StringComparer.CurrentCultureIgnoreCase); } /// Fetch version metadata for the given mods. @@ -82,7 +93,7 @@ namespace StardewModdingAPI.Web.Controllers // fetch mod info result[modKey] = await this.Cache.GetOrCreateAsync($"{repository.VendorKey}:{modID}".ToLower(), async entry => { - entry.AbsoluteExpiration = DateTimeOffset.UtcNow.AddHours(1); + entry.AbsoluteExpiration = DateTimeOffset.UtcNow.AddMinutes(this.CacheMinutes); return await repository.GetModInfoAsync(modID); }); } diff --git a/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs b/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs new file mode 100644 index 00000000..c8763800 --- /dev/null +++ b/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs @@ -0,0 +1,21 @@ +namespace StardewModdingAPI.Web.Framework.ConfigModels +{ + /// The config settings for mod update checks. + public class ModUpdateCheckConfig + { + /// The number of minutes update checks should be cached before refetching them. + public int CacheMinutes { get; set; } + + /// The repository key for Nexus Mods. + public string NexusKey { get; set; } + + /// The user agent for the Nexus Mods API client. + public string NexusUserAgent { get; set; } + + /// The base URL for the Nexus Mods API. + public string NexusBaseUrl { get; set; } + + /// The URL for a Nexus Mods API query excluding the , where {0} is the mod ID. + public string NexusModUrlFormat { get; set; } + } +} diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs index 02c2939a..312058ae 100644 --- a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs @@ -20,17 +20,25 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories ** Accessors *********/ /// The unique key for this vendor. - public string VendorKey { get; } = "Nexus"; + public string VendorKey { get; } + + /// The URL for a Nexus Mods API query excluding the base URL, where {0} is the mod ID. + public string ModUrlFormat { get; } /********* ** Public methods *********/ /// Construct an instance. - public NexusRepository() + /// The unique key for this vendor. + /// The user agent for the Nexus Mods API client. + /// The base URL for the Nexus Mods API. + /// The URL for a Nexus Mods API query excluding the , where {0} is the mod ID. + public NexusRepository(string vendorKey, string userAgent, string baseUrl, string modUrlFormat) { - this.Client = new FluentClient("http://www.nexusmods.com/stardewvalley") - .SetUserAgent("Nexus Client v0.63.15"); + this.VendorKey = vendorKey; + this.ModUrlFormat = modUrlFormat; + this.Client = new FluentClient(baseUrl).SetUserAgent(userAgent); } /// Get metadata about a mod in the repository. @@ -40,7 +48,7 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories try { NexusResponseModel response = await this.Client - .GetAsync($"mods/{id}") + .GetAsync(string.Format(this.ModUrlFormat, id)) .As(); return response != null diff --git a/src/StardewModdingAPI.Web/Startup.cs b/src/StardewModdingAPI.Web/Startup.cs index 8aba6a5a..fbe2bd92 100644 --- a/src/StardewModdingAPI.Web/Startup.cs +++ b/src/StardewModdingAPI.Web/Startup.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using StardewModdingAPI.Web.Framework; +using StardewModdingAPI.Web.Framework.ConfigModels; namespace StardewModdingAPI.Web { @@ -39,6 +40,7 @@ namespace StardewModdingAPI.Web public void ConfigureServices(IServiceCollection services) { services + .Configure(this.Configuration.GetSection("ModUpdateCheck")) .AddMemoryCache() .AddMvc() .AddJsonOptions(options => diff --git a/src/StardewModdingAPI.Web/appsettings.json b/src/StardewModdingAPI.Web/appsettings.json index 5fff67ba..1e624055 100644 --- a/src/StardewModdingAPI.Web/appsettings.json +++ b/src/StardewModdingAPI.Web/appsettings.json @@ -1,8 +1,15 @@ -{ +{ "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Warning" } - } + }, + "ModUpdateCheck": { + "CacheMinutes": 60, + "NexusKey": "Nexus", + "NexusUserAgent": "Nexus Client v0.63.15", + "NexusBaseUrl": "http://www.nexusmods.com/stardewvalley", + "NexusModUrlFormat": "mods/{0}" + } } -- cgit From 0d6f6a9acef175fd9ea0df6790111d8d58d7f368 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 22 Sep 2017 22:42:04 -0400 Subject: add GitHub update check support (#336) --- .../Controllers/ModsController.cs | 1 + .../Framework/ConfigModels/ModUpdateCheckConfig.cs | 27 +++++++ .../Framework/ModRepositories/GitHubRepository.cs | 91 ++++++++++++++++++++++ src/StardewModdingAPI.Web/appsettings.json | 7 ++ 4 files changed, 126 insertions(+) create mode 100644 src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs (limited to 'src/StardewModdingAPI.Web/Framework/ModRepositories') diff --git a/src/StardewModdingAPI.Web/Controllers/ModsController.cs b/src/StardewModdingAPI.Web/Controllers/ModsController.cs index a3f5001a..4b1abde4 100644 --- a/src/StardewModdingAPI.Web/Controllers/ModsController.cs +++ b/src/StardewModdingAPI.Web/Controllers/ModsController.cs @@ -44,6 +44,7 @@ namespace StardewModdingAPI.Web.Controllers this.Repositories = new IModRepository[] { + new GitHubRepository(config.GitHubKey, config.GitHubBaseUrl, config.GitHubReleaseUrlFormat, config.GitHubUserAgent, config.GitHubAcceptHeader), new NexusRepository(config.NexusKey, config.NexusUserAgent, config.NexusBaseUrl, config.NexusModUrlFormat) } .ToDictionary(p => p.VendorKey, StringComparer.CurrentCultureIgnoreCase); diff --git a/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs b/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs index c8763800..4dbad506 100644 --- a/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs +++ b/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs @@ -3,9 +3,36 @@ namespace StardewModdingAPI.Web.Framework.ConfigModels /// The config settings for mod update checks. public class ModUpdateCheckConfig { + /********* + ** Accessors + *********/ + /**** + ** General + ****/ /// The number of minutes update checks should be cached before refetching them. public int CacheMinutes { get; set; } + /**** + ** GitHub + ****/ + /// The repository key for Nexus Mods. + public string GitHubKey { get; set; } + + /// The user agent for the GitHub API client. + public string GitHubUserAgent { get; set; } + + /// The base URL for the GitHub API. + public string GitHubBaseUrl { get; set; } + + /// The URL for a GitHub API latest-release query excluding the , where {0} is the organisation and project name. + public string GitHubReleaseUrlFormat { get; set; } + + /// The Accept header value expected by the GitHub API. + public string GitHubAcceptHeader { get; set; } + + /**** + ** Nexus Mods + ****/ /// The repository key for Nexus Mods. public string NexusKey { get; set; } diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs new file mode 100644 index 00000000..c5772ad9 --- /dev/null +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs @@ -0,0 +1,91 @@ +using System; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Pathoschild.Http.Client; +using StardewModdingAPI.Web.Models; + +namespace StardewModdingAPI.Web.Framework.ModRepositories +{ + /// An HTTP client for fetching mod metadata from GitHub project releases. + internal class GitHubRepository : IModRepository + { + /********* + ** Properties + *********/ + /// The underlying HTTP client. + private readonly IClient Client; + + + /********* + ** Accessors + *********/ + /// The unique key for this vendor. + public string VendorKey { get; } + + /// The URL for a Nexus Mods API query excluding the base URL, where {0} is the mod ID. + public string ReleaseUrlFormat { get; } + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The unique key for this vendor. + /// The base URL for the Nexus Mods API. + /// The URL for a Nexus Mods API query excluding the , where {0} is the mod ID. + /// The user agent for the GitHub API client. + /// The Accept header value expected by the GitHub API. + public GitHubRepository(string vendorKey, string baseUrl, string releaseUrlFormat, string userAgent, string acceptHeader) + { + this.VendorKey = vendorKey; + this.ReleaseUrlFormat = releaseUrlFormat; + + this.Client = new FluentClient(baseUrl) + .SetUserAgent(string.Format(userAgent, this.GetType().Assembly.GetName().Version)) + .AddDefault(req => req.WithHeader("Accept", acceptHeader)); + } + + /// Get metadata about a mod in the repository. + /// The mod ID in this repository. + public async Task GetModInfoAsync(string id) + { + try + { + GitRelease release = await this.Client + .GetAsync(string.Format(this.ReleaseUrlFormat, id)) + .As(); + + return new ModInfoModel(id, release.Tag, $"https://github.com/{id}/releases"); + } + catch (Exception ex) + { + return new ModInfoModel(ex.ToString()); + } + } + + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + this.Client.Dispose(); + } + + + /********* + ** Private models + *********/ + /// Metadata about a GitHub release tag. + private class GitRelease + { + /********* + ** Accessors + *********/ + /// The display name. + [JsonProperty("name")] + public string Name { get; set; } + + /// The semantic version string. + [JsonProperty("tag_name")] + public string Tag { get; set; } + } + } +} diff --git a/src/StardewModdingAPI.Web/appsettings.json b/src/StardewModdingAPI.Web/appsettings.json index 1e624055..f996157c 100644 --- a/src/StardewModdingAPI.Web/appsettings.json +++ b/src/StardewModdingAPI.Web/appsettings.json @@ -7,6 +7,13 @@ }, "ModUpdateCheck": { "CacheMinutes": 60, + + "GitHubKey": "GitHub", + "GitHubUserAgent": "SMAPI/{0} (+https://github.com/Pathoschild/SMAPI)", + "GitHubBaseUrl": "https://api.github.com", + "GitHubReleaseUrlFormat": "repos/{0}/releases/latest", + "GitHubAcceptHeader": "application/vnd.github.v3+json", + "NexusKey": "Nexus", "NexusUserAgent": "Nexus Client v0.63.15", "NexusBaseUrl": "http://www.nexusmods.com/stardewvalley", -- cgit From eaabd91f31db35e050b7215f5f36568bf6982a83 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 22 Sep 2017 23:43:58 -0400 Subject: authenticate GitHub queries if auth details are configured (#336) --- src/StardewModdingAPI.Web/Controllers/ModsController.cs | 17 +++++++++++++++-- .../Framework/ConfigModels/ModUpdateCheckConfig.cs | 6 ++++++ .../Framework/ModRepositories/GitHubRepository.cs | 6 +++++- src/StardewModdingAPI.Web/Startup.cs | 1 + src/StardewModdingAPI.Web/appsettings.json | 2 ++ 5 files changed, 29 insertions(+), 3 deletions(-) (limited to 'src/StardewModdingAPI.Web/Framework/ModRepositories') diff --git a/src/StardewModdingAPI.Web/Controllers/ModsController.cs b/src/StardewModdingAPI.Web/Controllers/ModsController.cs index 4b1abde4..4715d379 100644 --- a/src/StardewModdingAPI.Web/Controllers/ModsController.cs +++ b/src/StardewModdingAPI.Web/Controllers/ModsController.cs @@ -44,8 +44,21 @@ namespace StardewModdingAPI.Web.Controllers this.Repositories = new IModRepository[] { - new GitHubRepository(config.GitHubKey, config.GitHubBaseUrl, config.GitHubReleaseUrlFormat, config.GitHubUserAgent, config.GitHubAcceptHeader), - new NexusRepository(config.NexusKey, config.NexusUserAgent, config.NexusBaseUrl, config.NexusModUrlFormat) + new GitHubRepository( + vendorKey: config.GitHubKey, + baseUrl: config.GitHubBaseUrl, + releaseUrlFormat: config.GitHubReleaseUrlFormat, + userAgent: config.GitHubUserAgent, + acceptHeader: config.GitHubAcceptHeader, + username: config.GitHubUsername, + password: config.GitHubPassword + ), + new NexusRepository( + vendorKey: config.NexusKey, + userAgent: config.NexusUserAgent, + baseUrl: config.NexusBaseUrl, + modUrlFormat: config.NexusModUrlFormat + ) } .ToDictionary(p => p.VendorKey, StringComparer.CurrentCultureIgnoreCase); } diff --git a/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs b/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs index 4dbad506..5d55ba18 100644 --- a/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs +++ b/src/StardewModdingAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs @@ -30,6 +30,12 @@ namespace StardewModdingAPI.Web.Framework.ConfigModels /// The Accept header value expected by the GitHub API. public string GitHubAcceptHeader { get; set; } + /// The username with which to authenticate to the GitHub API (if any). + public string GitHubUsername { get; set; } + + /// The password with which to authenticate to the GitHub API (if any). + public string GitHubPassword { get; set; } + /**** ** Nexus Mods ****/ diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs index c5772ad9..67e706ed 100644 --- a/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs @@ -35,7 +35,9 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories /// The URL for a Nexus Mods API query excluding the , where {0} is the mod ID. /// The user agent for the GitHub API client. /// The Accept header value expected by the GitHub API. - public GitHubRepository(string vendorKey, string baseUrl, string releaseUrlFormat, string userAgent, string acceptHeader) + /// The username with which to authenticate to the GitHub API. + /// The password with which to authenticate to the GitHub API. + public GitHubRepository(string vendorKey, string baseUrl, string releaseUrlFormat, string userAgent, string acceptHeader, string username, string password) { this.VendorKey = vendorKey; this.ReleaseUrlFormat = releaseUrlFormat; @@ -43,6 +45,8 @@ namespace StardewModdingAPI.Web.Framework.ModRepositories this.Client = new FluentClient(baseUrl) .SetUserAgent(string.Format(userAgent, this.GetType().Assembly.GetName().Version)) .AddDefault(req => req.WithHeader("Accept", acceptHeader)); + if (!string.IsNullOrWhiteSpace(username)) + this.Client = this.Client.SetBasicAuthentication(username, password); } /// Get metadata about a mod in the repository. diff --git a/src/StardewModdingAPI.Web/Startup.cs b/src/StardewModdingAPI.Web/Startup.cs index b668c63e..4806aefe 100644 --- a/src/StardewModdingAPI.Web/Startup.cs +++ b/src/StardewModdingAPI.Web/Startup.cs @@ -29,6 +29,7 @@ namespace StardewModdingAPI.Web { this.Configuration = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) + .AddEnvironmentVariables() .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables() diff --git a/src/StardewModdingAPI.Web/appsettings.json b/src/StardewModdingAPI.Web/appsettings.json index f996157c..29fb195e 100644 --- a/src/StardewModdingAPI.Web/appsettings.json +++ b/src/StardewModdingAPI.Web/appsettings.json @@ -13,6 +13,8 @@ "GitHubBaseUrl": "https://api.github.com", "GitHubReleaseUrlFormat": "repos/{0}/releases/latest", "GitHubAcceptHeader": "application/vnd.github.v3+json", + "GitHubUsername": null, /* set via environment properties */ + "GitHubPassword": null, /* set via environment properties */ "NexusKey": "Nexus", "NexusUserAgent": "Nexus Client v0.63.15", -- cgit From bdee7f88e9ddbab51869431efbff90100b65bbd1 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 23 Sep 2017 14:37:58 -0400 Subject: move API models into shared project for reuse (#336) --- src/StardewModdingAPI.Models/ModInfoModel.cs | 48 ++++++++++++++++++++++ .../StardewModdingAPI.Models.projitems | 14 +++++++ .../StardewModdingAPI.Models.shproj | 13 ++++++ .../Controllers/ModsController.cs | 2 +- .../Framework/ModRepositories/GitHubRepository.cs | 2 +- .../Framework/ModRepositories/IModRepository.cs | 2 +- .../Framework/ModRepositories/NexusRepository.cs | 2 +- src/StardewModdingAPI.Web/Models/ModInfoModel.cs | 48 ---------------------- .../StardewModdingAPI.Web.csproj | 1 + src/StardewModdingAPI.sln | 13 +++++- 10 files changed, 92 insertions(+), 53 deletions(-) create mode 100644 src/StardewModdingAPI.Models/ModInfoModel.cs create mode 100644 src/StardewModdingAPI.Models/StardewModdingAPI.Models.projitems create mode 100644 src/StardewModdingAPI.Models/StardewModdingAPI.Models.shproj delete mode 100644 src/StardewModdingAPI.Web/Models/ModInfoModel.cs (limited to 'src/StardewModdingAPI.Web/Framework/ModRepositories') diff --git a/src/StardewModdingAPI.Models/ModInfoModel.cs b/src/StardewModdingAPI.Models/ModInfoModel.cs new file mode 100644 index 00000000..44071230 --- /dev/null +++ b/src/StardewModdingAPI.Models/ModInfoModel.cs @@ -0,0 +1,48 @@ +using Newtonsoft.Json; + +namespace StardewModdingAPI.Models +{ + /// Generic metadata about a mod. + internal class ModInfoModel + { + /********* + ** Accessors + *********/ + /// The mod name. + public string Name { get; } + + /// The mod's semantic version number. + public string Version { get; } + + /// The mod's web URL. + public string Url { get; } + + /// The error message indicating why the mod is invalid (if applicable). + public string Error { get; } + + + /********* + ** Public methods + *********/ + /// Construct a valid instance. + /// The mod name. + /// The mod's semantic version number. + /// The mod's web URL. + /// The error message indicating why the mod is invalid (if applicable). + [JsonConstructor] + public ModInfoModel(string name, string version, string url, string error = null) + { + this.Name = name; + this.Version = version; + this.Url = url; + this.Error = error; // mainly initialised here for the JSON deserialiser + } + + /// Construct an valid instance. + /// The error message indicating why the mod is invalid. + public ModInfoModel(string error) + { + this.Error = error; + } + } +} diff --git a/src/StardewModdingAPI.Models/StardewModdingAPI.Models.projitems b/src/StardewModdingAPI.Models/StardewModdingAPI.Models.projitems new file mode 100644 index 00000000..2465760e --- /dev/null +++ b/src/StardewModdingAPI.Models/StardewModdingAPI.Models.projitems @@ -0,0 +1,14 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 2aa02fb6-ff03-41cf-a215-2ee60ab4f5dc + + + StardewModdingAPI.Models + + + + + \ No newline at end of file diff --git a/src/StardewModdingAPI.Models/StardewModdingAPI.Models.shproj b/src/StardewModdingAPI.Models/StardewModdingAPI.Models.shproj new file mode 100644 index 00000000..c80517af --- /dev/null +++ b/src/StardewModdingAPI.Models/StardewModdingAPI.Models.shproj @@ -0,0 +1,13 @@ + + + + 2aa02fb6-ff03-41cf-a215-2ee60ab4f5dc + 14.0 + + + + + + + + diff --git a/src/StardewModdingAPI.Web/Controllers/ModsController.cs b/src/StardewModdingAPI.Web/Controllers/ModsController.cs index 06a80638..8fc2cb51 100644 --- a/src/StardewModdingAPI.Web/Controllers/ModsController.cs +++ b/src/StardewModdingAPI.Web/Controllers/ModsController.cs @@ -7,7 +7,7 @@ using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using StardewModdingAPI.Web.Framework.ConfigModels; using StardewModdingAPI.Web.Framework.ModRepositories; -using StardewModdingAPI.Web.Models; +using StardewModdingAPI.Models; namespace StardewModdingAPI.Web.Controllers { diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs index 67e706ed..421220de 100644 --- a/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/GitHubRepository.cs @@ -2,7 +2,7 @@ using System; using System.Threading.Tasks; using Newtonsoft.Json; using Pathoschild.Http.Client; -using StardewModdingAPI.Web.Models; +using StardewModdingAPI.Models; namespace StardewModdingAPI.Web.Framework.ModRepositories { diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs index 7fd735cd..98e4c957 100644 --- a/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/IModRepository.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using StardewModdingAPI.Web.Models; +using StardewModdingAPI.Models; namespace StardewModdingAPI.Web.Framework.ModRepositories { diff --git a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs index 312058ae..6cf5b04a 100644 --- a/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs +++ b/src/StardewModdingAPI.Web/Framework/ModRepositories/NexusRepository.cs @@ -2,7 +2,7 @@ using System; using System.Threading.Tasks; using Newtonsoft.Json; using Pathoschild.Http.Client; -using StardewModdingAPI.Web.Models; +using StardewModdingAPI.Models; namespace StardewModdingAPI.Web.Framework.ModRepositories { diff --git a/src/StardewModdingAPI.Web/Models/ModInfoModel.cs b/src/StardewModdingAPI.Web/Models/ModInfoModel.cs deleted file mode 100644 index 4e9762e5..00000000 --- a/src/StardewModdingAPI.Web/Models/ModInfoModel.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Newtonsoft.Json; - -namespace StardewModdingAPI.Web.Models -{ - /// Generic metadata about a mod. - internal class ModInfoModel - { - /********* - ** Accessors - *********/ - /// The mod name. - public string Name { get; } - - /// The mod's semantic version number. - public string Version { get; } - - /// The mod's web URL. - public string Url { get; } - - /// The error message indicating why the mod is invalid (if applicable). - public string Error { get; } - - - /********* - ** Public methods - *********/ - /// Construct a valid instance. - /// The mod name. - /// The mod's semantic version number. - /// The mod's web URL. - /// The error message indicating why the mod is invalid (if applicable). - [JsonConstructor] - public ModInfoModel(string name, string version, string url, string error = null) - { - this.Name = name; - this.Version = version; - this.Url = url; - this.Error = error; // mainly initialised here for the JSON deserialiser - } - - /// Construct an valid instance. - /// The error message indicating why the mod is invalid. - public ModInfoModel(string error) - { - this.Error = error; - } - } -} diff --git a/src/StardewModdingAPI.Web/StardewModdingAPI.Web.csproj b/src/StardewModdingAPI.Web/StardewModdingAPI.Web.csproj index 2af7c3df..c30abc55 100644 --- a/src/StardewModdingAPI.Web/StardewModdingAPI.Web.csproj +++ b/src/StardewModdingAPI.Web/StardewModdingAPI.Web.csproj @@ -15,5 +15,6 @@ + diff --git a/src/StardewModdingAPI.sln b/src/StardewModdingAPI.sln index 031e2d5f..bc2bb8b2 100644 --- a/src/StardewModdingAPI.sln +++ b/src/StardewModdingAPI.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26730.15 +VisualStudioVersion = 15.0.26730.16 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrainerMod", "TrainerMod\TrainerMod.csproj", "{28480467-1A48-46A7-99F8-236D95225359}" EndProject @@ -31,7 +31,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StardewModdingAPI.Tests", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StardewModdingAPI.Web", "StardewModdingAPI.Web\StardewModdingAPI.Web.csproj", "{A308F679-51A3-4006-92D5-BAEC7EBD01A1}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Internal", "Internal", "{82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11}" +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "StardewModdingAPI.Models", "StardewModdingAPI.Models\StardewModdingAPI.Models.shproj", "{2AA02FB6-FF03-41CF-A215-2EE60AB4F5DC}" +EndProject Global + GlobalSection(SharedMSBuildProjectFiles) = preSolution + StardewModdingAPI.Models\StardewModdingAPI.Models.projitems*{2aa02fb6-ff03-41cf-a215-2ee60ab4f5dc}*SharedItemsImports = 13 + EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|Mixed Platforms = Debug|Mixed Platforms @@ -97,6 +104,10 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {36CCB19E-92EB-48C7-9615-98EEFD45109B} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} + {2AA02FB6-FF03-41CF-A215-2EE60AB4F5DC} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {70143042-A862-47A8-A677-7C819DDC90DC} EndGlobalSection -- cgit