From b1400bcb684c43790dd38628b6c131e9e7c4d400 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 27 Nov 2019 21:49:36 -0500 Subject: fallback to Amazon S3 if saving a log to Pastebin fails --- docs/release-notes.md | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index a891c495..4234223c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,6 +1,11 @@ ← [README](README.md) # Release notes +## Upcoming release + +* For the web UI: + * If a log can't be uploaded to Pastebin (e.g. due to rate limits), it'll be uploaded to Amazon S3 instead. Logs uploaded to S3 will expire after one month. + ## 3.0 Released 26 November 2019 for Stardew Valley 1.4. -- cgit From d7948fbe1cfb111fab009cd0977778dfff358d58 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 30 Nov 2019 16:44:34 -0500 Subject: update translation docs (#664, #671) --- docs/README.md | 2 +- docs/release-notes.md | 2 ++ src/SMAPI/i18n/zh.json | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'docs') diff --git a/docs/README.md b/docs/README.md index ddde6b09..d675b742 100644 --- a/docs/README.md +++ b/docs/README.md @@ -63,7 +63,7 @@ contributing translations. locale | status ---------- | :---------------- default | ✓ [fully translated](../src/SMAPI/i18n/default.json) -Chinese | ❑ not translated +Chinese | ✓ [fully translated](../src/SMAPI/i18n/zh.json) French | ❑ not translated German | ✓ [fully translated](../src/SMAPI/i18n/de.json) Hungarian | ❑ not translated diff --git a/docs/release-notes.md b/docs/release-notes.md index 4234223c..fde74d9d 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,6 +5,7 @@ * For the web UI: * If a log can't be uploaded to Pastebin (e.g. due to rate limits), it'll be uploaded to Amazon S3 instead. Logs uploaded to S3 will expire after one month. + * Updated translations. Thanks to feathershine (added Chinese)! ## 3.0 Released 26 November 2019 for Stardew Valley 1.4. @@ -85,6 +86,7 @@ For modders: * Update checks are now faster in some cases. * Updated mod compatibility list. * Updated SMAPI/game version map. + * Updated translations. Thanks to eren-kemer (added German)! * Fixes: * Fixed some assets not updated when you switch language to English. * Fixed lag in some cases due to incorrect asset caching when playing in non-English. diff --git a/src/SMAPI/i18n/zh.json b/src/SMAPI/i18n/zh.json index 8dec396a..bbd6a574 100644 --- a/src/SMAPI/i18n/zh.json +++ b/src/SMAPI/i18n/zh.json @@ -1,3 +1,3 @@ { "warn.invalid-content-removed": "非法内容已移除以防游戏闪退(查看SMAPI控制台获得更多信息)" -} \ No newline at end of file +} -- cgit From 8766a79408ce79bd632c1fe1c9b17ab0a7a6a976 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 2 Dec 2019 20:13:58 -0500 Subject: update readme and release notes --- docs/README.md | 4 ++-- docs/release-notes.md | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/README.md b/docs/README.md index d675b742..386259a9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -71,6 +71,6 @@ Italian | ❑ not translated Japanese | ❑ not translated Korean | ❑ not translated Portuguese | ❑ not translated -Russian | ❑ not translated +Russian | ✓ [fully translated](../src/SMAPI/i18n/ru.json) Spanish | ❑ not translated -Turkish | ❑ not translated +Turkish | ✓ [fully translated](../src/SMAPI/i18n/tr.json) diff --git a/docs/release-notes.md b/docs/release-notes.md index fde74d9d..c3840148 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -5,7 +5,8 @@ * For the web UI: * If a log can't be uploaded to Pastebin (e.g. due to rate limits), it'll be uploaded to Amazon S3 instead. Logs uploaded to S3 will expire after one month. - * Updated translations. Thanks to feathershine (added Chinese)! + * Improved compatibility with some Linux terminals (thanks to archification and DanielHeath!). + * Updated translations. Thanks to berkayylmao (added Turkish), feathershine (added Chinese), and Osiris901 (added Russian)! ## 3.0 Released 26 November 2019 for Stardew Valley 1.4. -- cgit From 5f532c259d5d3050bd6a053659067617db136d57 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 1 Dec 2019 21:55:20 -0500 Subject: migrate from AWS to Azure This commit migrates from subdomains to paths (due to the cost of a wildcard HTTPS certificate on Azure), adds a web project to redirect the old subdomains from AWS to Azure, and removes AWS-specific hacks. --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .gitignore | 5 +- build/prepare-install-package.targets | 2 +- docs/release-notes.md | 22 ++--- docs/technical/web.md | 12 ++- .../Controllers/ModsApiController.cs | 33 ++++++++ .../Framework/LambdaRewriteRule.cs | 37 +++++++++ src/SMAPI.Web.LegacyRedirects/Program.cs | 23 ++++++ .../Properties/launchSettings.json | 29 +++++++ .../SMAPI.Web.LegacyRedirects.csproj | 21 +++++ src/SMAPI.Web.LegacyRedirects/Startup.cs | 94 ++++++++++++++++++++++ .../Controllers/JsonValidatorController.cs | 24 ++---- src/SMAPI.Web/Controllers/LogParserController.cs | 14 +--- src/SMAPI.Web/Controllers/ModsApiController.cs | 8 +- .../Framework/BeanstalkEnvPropsConfigProvider.cs | 54 ------------- .../Framework/ConfigModels/ModUpdateCheckConfig.cs | 3 - src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs | 12 --- .../ConditionalRewriteSubdomainRule.cs | 48 ----------- src/SMAPI.Web/Startup.cs | 17 +--- .../ViewModels/JsonValidator/JsonValidatorModel.cs | 7 +- src/SMAPI.Web/ViewModels/LogParserModel.cs | 7 +- src/SMAPI.Web/Views/Index/Index.cshtml | 10 +-- src/SMAPI.Web/Views/Index/Privacy.cshtml | 4 +- src/SMAPI.Web/Views/JsonValidator/Index.cshtml | 10 +-- src/SMAPI.Web/Views/LogParser/Index.cshtml | 16 ++-- src/SMAPI.Web/Views/Shared/_Layout.cshtml | 8 +- src/SMAPI.Web/appsettings.Development.json | 4 - src/SMAPI.Web/appsettings.json | 7 +- src/SMAPI.sln | 6 ++ src/SMAPI/Framework/ModLoading/ModResolver.cs | 2 +- src/SMAPI/Framework/Models/SConfig.cs | 2 +- src/SMAPI/Framework/SCore.cs | 4 +- src/SMAPI/SMAPI.config.json | 2 +- 33 files changed, 311 insertions(+), 238 deletions(-) create mode 100644 src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs create mode 100644 src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs create mode 100644 src/SMAPI.Web.LegacyRedirects/Program.cs create mode 100644 src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json create mode 100644 src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj create mode 100644 src/SMAPI.Web.LegacyRedirects/Startup.cs delete mode 100644 src/SMAPI.Web/Framework/BeanstalkEnvPropsConfigProvider.cs delete mode 100644 src/SMAPI.Web/Framework/RewriteRules/ConditionalRewriteSubdomainRule.cs (limited to 'docs') diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 74954cf4..c51d164b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -24,7 +24,7 @@ Exact steps which reproduce the bug, if possible. For example: 4. Error occurs. **Log file** -Upload your SMAPI log to https://log.smapi.io and post a link here. +Upload your SMAPI log to https://smapi.io/log and post a link here. **Screenshots** If applicable, add screenshots to help explain your problem. diff --git a/.gitignore b/.gitignore index 7080a8fc..65695211 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,7 @@ _ReSharper*/ appsettings.Development.json # AWS generated files -src/SMAPI.Web/aws-beanstalk-tools-defaults.json +src/SMAPI.Web.LegacyRedirects/aws-beanstalk-tools-defaults.json + +# Azure generated files +src/SMAPI.Web/Properties/PublishProfiles/smapi-web-release - Web Deploy.pubxml diff --git a/build/prepare-install-package.targets b/build/prepare-install-package.targets index e5286bf5..4297756d 100644 --- a/build/prepare-install-package.targets +++ b/build/prepare-install-package.targets @@ -63,7 +63,7 @@ - + diff --git a/docs/release-notes.md b/docs/release-notes.md index c3840148..dcce70c9 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -110,7 +110,7 @@ For modders: * Clicking a mod link now automatically adds it to the visible mods if the list is filtered. * JSON validator: - * Added JSON validator at [json.smapi.io](https://json.smapi.io), which lets you validate a JSON file against predefined mod formats. + * Added JSON validator at [smapi.io/json](https://smapi.io/json), which lets you validate a JSON file against predefined mod formats. * Added support for the `manifest.json` format. * Added support for the Content Patcher format (thanks to TehPers!). * Added support for referencing a schema in a JSON Schema-compatible text editor. @@ -373,7 +373,7 @@ Released 19 November 2018 for Stardew Valley 1.3.32. * Updated compatibility list. * For the web UI: - * Added a [mod compatibility page](https://mods.smapi.io) and [privacy page](https://smapi.io/privacy). + * Added a [mod compatibility page](https://smapi.io/mods) and [privacy page](https://smapi.io/privacy). * The log parser now has a separate filter for game messages. * The log parser now shows content pack authors (thanks to danvolchek!). * Tweaked log parser UI (thanks to danvolchek!). @@ -557,7 +557,7 @@ Released 11 April 2018 for Stardew Valley 1.2.30–1.2.33. * Fixed error when two content packs use different capitalization for the same required mod ID. * Fixed rare crash if the game duplicates an item. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Tweaked UI. ## 2.5.4 @@ -569,7 +569,7 @@ Released 26 March 2018 for Stardew Valley 1.2.30–1.2.33. * Fixed error when mods remove an asset editor/loader. * Fixed minimum game version incorrectly increased in SMAPI 2.5.3. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Fixed error when log text contains certain tokens. * For modders: @@ -591,7 +591,7 @@ Released 13 March 2018 for Stardew Valley ~~1.2.30~~–1.2.33. * Fixed Linux ["magic number is wrong" errors](https://github.com/mono/mono/issues/6752) by changing default terminal order. * Updated compatibility list and added update checks for more mods. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Fixed incorrect filtering in some cases. * Fixed error if mods have duplicate names. * Fixed parse bugs if a mod has no author name. @@ -605,7 +605,7 @@ Released 25 February 2018 for Stardew Valley 1.2.30–1.2.33. * For modders: * Fixed issue where replacing an asset through `asset.AsImage()` or `asset.AsDictionary()` didn't take effect. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Fixed blank page after uploading a log in some cases. ## 2.5.1 @@ -636,7 +636,7 @@ Released 24 February 2018 for Stardew Valley 1.2.30–1.2.33. * Fixed unhelpful error when a translation file has duplicate keys due to case-insensitivity. * Fixed some JSON field names being case-sensitive. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Added support for SMAPI 2.5 content packs. * Reduced download size when viewing a parsed log with repeated errors. * Improved parse error handling. @@ -657,7 +657,7 @@ Released 24 January 2018 for Stardew Valley 1.2.30–1.2.33. * Fixed intermittent errors (e.g. 'collection has been modified') with some mods when loading a save. * Fixed compatibility with Linux Terminator terminal. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Fixed error parsing logs with zero installed mods. * For modders: @@ -692,7 +692,7 @@ Released 26 December 2017 for Stardew Valley 1.2.30–1.2.33. * Fixed issue where a mod could change the cursor position reported to other mods. * Updated compatibility list. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Fixed broken favicon. ## 2.2 @@ -706,7 +706,7 @@ Released 02 December 2017 for Stardew Valley 1.2.30–1.2.33. * Improved error when a mod has an invalid `EntryDLL` filename format. * Updated compatibility list. -* For the [log parser](https://log.smapi.io): +* For the [log parser](https://smapi.io/log): * Logs no longer expire after a week. * Fixed error when uploading very large logs. * Slightly improved the UI. @@ -721,7 +721,7 @@ Released 02 December 2017 for Stardew Valley 1.2.30–1.2.33. Released 01 November 2017 for Stardew Valley 1.2.30–1.2.33. * For players: - * Added a [log parser](https://log.smapi.io) site. + * Added a [log parser](https://smapi.io/log) site. * Added better Steam instructions to the SMAPI installer. * Renamed the bundled _TrainerMod_ to _ConsoleCommands_ to make its purpose clearer. * Removed the game's test messages from the console log. diff --git a/docs/technical/web.md b/docs/technical/web.md index 78d93625..97e0704a 100644 --- a/docs/technical/web.md +++ b/docs/technical/web.md @@ -14,13 +14,13 @@ and update check API. ## Log parser The log parser provides a web UI for uploading, parsing, and sharing SMAPI logs. The logs are -persisted in a compressed form to Pastebin. The log parser lives at https://log.smapi.io. +persisted in a compressed form to Pastebin. The log parser lives at https://smapi.io/log. ## JSON validator ### Overview The JSON validator provides a web UI for uploading and sharing JSON files, and validating them as plain JSON or against a predefined format like `manifest.json` or Content Patcher's `content.json`. -The JSON validator lives at https://json.smapi.io. +The JSON validator lives at https://smapi.io/json. ### Schema file format Schema files are defined in `wwwroot/schemas` using the [JSON Schema](https://json-schema.org/) @@ -111,7 +111,7 @@ format | schema URL ## Web API ### Overview -SMAPI provides a web API at `api.smapi.io` for use by SMAPI and external tools. The URL includes a +SMAPI provides a web API at `smapi.io/api` for use by SMAPI and external tools. The URL includes a `{version}` token, which is the SMAPI version for backwards compatibility. This API is publicly accessible but not officially released; it may change at any time. @@ -184,7 +184,7 @@ may be useful to external tools. Example request: ```js -POST https://api.smapi.io/v3.0/mods +POST https://smapi.io/api/v3.0/mods { "mods": [ { @@ -350,8 +350,7 @@ To launch the environment: mongod --dbpath C:\dev\smapi-cache ``` 2. Launch `SMAPI.Web` from Visual Studio to run a local version of the site. - (Local URLs will use HTTP instead of HTTPS, and subdomains will become routes, like - `log.smapi.io` → `localhost:59482/log`.) + (Local URLs will use HTTP instead of HTTPS.) ### Production environment A production environment includes the web servers and cache database hosted online for public @@ -367,7 +366,6 @@ Initial setup: ------------------------------- | ----------------- `LogParser:PastebinDevKey` | The [Pastebin developer key](https://pastebin.com/api#1) used to authenticate with the Pastebin API. `LogParser:PastebinUserKey` | The [Pastebin user key](https://pastebin.com/api#8) used to authenticate with the Pastebin API. Can be left blank to post anonymously. - `LogParser:SectionUrl` | The root URL of the log page, like `https://log.smapi.io/`. `ModUpdateCheck:GitHubPassword` | The password with which to authenticate to GitHub when fetching release info. `ModUpdateCheck:GitHubUsername` | The username with which to authenticate to GitHub when fetching release info. `MongoDB:Host` | The hostname for the MongoDB instance. diff --git a/src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs b/src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs new file mode 100644 index 00000000..44ed0b6b --- /dev/null +++ b/src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Pathoschild.Http.Client; +using StardewModdingAPI.Toolkit.Framework.Clients.WebApi; + +namespace SMAPI.Web.LegacyRedirects.Controllers +{ + /// Provides an API to perform mod update checks. + [ApiController] + [Produces("application/json")] + [Route("api/v{version}/mods")] + public class ModsApiController : Controller + { + /********* + ** Public methods + *********/ + /// Fetch version metadata for the given mods. + /// The mod search criteria. + [HttpPost] + public async Task> PostAsync([FromBody] ModSearchModel model) + { + using IClient client = new FluentClient("https://smapi.io/api"); + + Startup.ConfigureJsonNet(client.Formatters.JsonFormatter.SerializerSettings); + + return await client + .PostAsync(this.Request.Path) + .WithBody(model) + .AsArray(); + } + } +} diff --git a/src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs b/src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs new file mode 100644 index 00000000..e5138e5c --- /dev/null +++ b/src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs @@ -0,0 +1,37 @@ +using System; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite; + +namespace SMAPI.Web.LegacyRedirects.Framework +{ + /// Rewrite requests to prepend the subdomain portion (if any) to the path. + /// Derived from . + internal class LambdaRewriteRule : IRule + { + /********* + ** Accessors + *********/ + /// Rewrite an HTTP request if needed. + private readonly Action Rewrite; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Rewrite an HTTP request if needed. + public LambdaRewriteRule(Action rewrite) + { + this.Rewrite = rewrite ?? throw new ArgumentNullException(nameof(rewrite)); + } + + /// Applies the rule. Implementations of ApplyRule should set the value for (defaults to RuleResult.ContinueRules). + /// The rewrite context. + public void ApplyRule(RewriteContext context) + { + HttpRequest request = context.HttpContext.Request; + HttpResponse response = context.HttpContext.Response; + this.Rewrite(context, request, response); + } + } +} diff --git a/src/SMAPI.Web.LegacyRedirects/Program.cs b/src/SMAPI.Web.LegacyRedirects/Program.cs new file mode 100644 index 00000000..6adee877 --- /dev/null +++ b/src/SMAPI.Web.LegacyRedirects/Program.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace SMAPI.Web.LegacyRedirects +{ + /// The main app entry point. + public class Program + { + /********* + ** Public methods + *********/ + /// The main app entry point. + /// The command-line arguments. + public static void Main(string[] args) + { + Host + .CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(builder => builder.UseStartup()) + .Build() + .Run(); + } + } +} diff --git a/src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json b/src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json new file mode 100644 index 00000000..e9a1b210 --- /dev/null +++ b/src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:52756", + "sslPort": 0 + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "SMAPI.Web.LegacyRedirects": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "/", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" + } + } +} \ No newline at end of file diff --git a/src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj b/src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj new file mode 100644 index 00000000..a3d5c2b6 --- /dev/null +++ b/src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj @@ -0,0 +1,21 @@ + + + + netcoreapp3.0 + + + + + + + + + + + + + + + + + diff --git a/src/SMAPI.Web.LegacyRedirects/Startup.cs b/src/SMAPI.Web.LegacyRedirects/Startup.cs new file mode 100644 index 00000000..4af51575 --- /dev/null +++ b/src/SMAPI.Web.LegacyRedirects/Startup.cs @@ -0,0 +1,94 @@ +using System.Net; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Rewrite; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using SMAPI.Web.LegacyRedirects.Framework; +using StardewModdingAPI.Toolkit.Serialization; + +namespace SMAPI.Web.LegacyRedirects +{ + /// The web app startup configuration. + public class Startup + { + /********* + ** Public methods + *********/ + /// The method called by the runtime to add services to the container. + /// The service injection container. + public void ConfigureServices(IServiceCollection services) + { + services + .AddControllers() + .AddNewtonsoftJson(options => Startup.ConfigureJsonNet(options.SerializerSettings)); + } + + /// The method called by the runtime to configure the HTTP request pipeline. + /// The application builder. + /// The hosting environment. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + app.UseDeveloperExceptionPage(); + + app + .UseRewriter(this.GetRedirectRules()) + .UseRouting() + .UseAuthorization() + .UseEndpoints(endpoints => endpoints.MapControllers()); + } + + /// Configure a Json.NET serializer. + /// The serializer settings to edit. + internal static void ConfigureJsonNet(JsonSerializerSettings settings) + { + foreach (JsonConverter converter in new JsonHelper().JsonSettings.Converters) + settings.Converters.Add(converter); + + settings.Formatting = Formatting.Indented; + settings.NullValueHandling = NullValueHandling.Ignore; + } + + + /********* + ** Private methods + *********/ + /// Get the redirect rules to apply. + private RewriteOptions GetRedirectRules() + { + var redirects = new RewriteOptions(); + + redirects.Add( + new LambdaRewriteRule((context, request, response) => + { + string host = request.Host.Host; + + // map API requests to proxy + // This is needed because the low-level HTTP client SMAPI uses for Linux/Mac compatibility doesn't support redirects. + if (host == "api.smapi.io") + { + request.Path = $"/api{request.Path}"; + return; + } + + // redirect other requests to Azure + string newRoot = host switch + { + "api.smapi.io" => "smapi.io/api", + "json.smapi.io" => "smapi.io/json", + "log.smapi.io" => "smapi.io/log", + "mods.smapi.io" => "smapi.io/mods", + _ => "smapi.io" + }; + response.StatusCode = (int)HttpStatusCode.PermanentRedirect; + response.Headers["Location"] = $"{(request.IsHttps ? "https" : "http")}://{newRoot}{request.PathBase}{request.Path}{request.QueryString}"; + context.Result = RuleResult.EndResponse; + }) + ); + + return redirects; + } + } +} diff --git a/src/SMAPI.Web/Controllers/JsonValidatorController.cs b/src/SMAPI.Web/Controllers/JsonValidatorController.cs index b2eb9a87..c32fb084 100644 --- a/src/SMAPI.Web/Controllers/JsonValidatorController.cs +++ b/src/SMAPI.Web/Controllers/JsonValidatorController.cs @@ -5,14 +5,12 @@ using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Schema; using StardewModdingAPI.Web.Framework; using StardewModdingAPI.Web.Framework.Clients.Pastebin; using StardewModdingAPI.Web.Framework.Compression; -using StardewModdingAPI.Web.Framework.ConfigModels; using StardewModdingAPI.Web.ViewModels.JsonValidator; namespace StardewModdingAPI.Web.Controllers @@ -23,18 +21,12 @@ namespace StardewModdingAPI.Web.Controllers /********* ** Fields *********/ - /// The site config settings. - private readonly SiteConfig Config; - /// The underlying Pastebin client. private readonly IPastebinClient Pastebin; /// The underlying text compression helper. private readonly IGzipHelper GzipHelper; - /// The section URL for the schema validator. - private string SectionUrl => this.Config.JsonValidatorUrl; - /// The supported JSON schemas (names indexed by ID). private readonly IDictionary SchemaFormats = new Dictionary { @@ -57,12 +49,10 @@ namespace StardewModdingAPI.Web.Controllers ** Constructor ***/ /// Construct an instance. - /// The context config settings. /// The Pastebin API client. /// The underlying text compression helper. - public JsonValidatorController(IOptions siteConfig, IPastebinClient pastebin, IGzipHelper gzipHelper) + public JsonValidatorController(IPastebinClient pastebin, IGzipHelper gzipHelper) { - this.Config = siteConfig.Value; this.Pastebin = pastebin; this.GzipHelper = gzipHelper; } @@ -81,7 +71,7 @@ namespace StardewModdingAPI.Web.Controllers { schemaName = this.NormalizeSchemaName(schemaName); - var result = new JsonValidatorModel(this.SectionUrl, id, schemaName, this.SchemaFormats); + var result = new JsonValidatorModel(id, schemaName, this.SchemaFormats); if (string.IsNullOrWhiteSpace(id)) return this.View("Index", result); @@ -142,7 +132,7 @@ namespace StardewModdingAPI.Web.Controllers public async Task PostAsync(JsonValidatorRequestModel request) { if (request == null) - return this.View("Index", new JsonValidatorModel(this.SectionUrl, null, null, this.SchemaFormats).SetUploadError("The request seems to be invalid.")); + return this.View("Index", new JsonValidatorModel(null, null, this.SchemaFormats).SetUploadError("The request seems to be invalid.")); // normalize schema name string schemaName = this.NormalizeSchemaName(request.SchemaName); @@ -150,7 +140,7 @@ namespace StardewModdingAPI.Web.Controllers // get raw log text string input = request.Content; if (string.IsNullOrWhiteSpace(input)) - return this.View("Index", new JsonValidatorModel(this.SectionUrl, null, schemaName, this.SchemaFormats).SetUploadError("The JSON file seems to be empty.")); + return this.View("Index", new JsonValidatorModel(null, schemaName, this.SchemaFormats).SetUploadError("The JSON file seems to be empty.")); // upload log input = this.GzipHelper.CompressString(input); @@ -158,12 +148,10 @@ namespace StardewModdingAPI.Web.Controllers // handle errors if (!result.Success) - return this.View("Index", new JsonValidatorModel(this.SectionUrl, result.ID, schemaName, this.SchemaFormats).SetUploadError($"Pastebin error: {result.Error ?? "unknown error"}")); + return this.View("Index", new JsonValidatorModel(result.ID, schemaName, this.SchemaFormats).SetUploadError($"Pastebin error: {result.Error ?? "unknown error"}")); // redirect to view - UriBuilder uri = new UriBuilder(new Uri(this.SectionUrl)); - uri.Path = $"{uri.Path.TrimEnd('/')}/{schemaName}/{result.ID}"; - return this.Redirect(uri.Uri.ToString()); + return this.Redirect(this.Url.Action("Index", "LogParser", new { schemaName = schemaName, id = result.ID })); } diff --git a/src/SMAPI.Web/Controllers/LogParserController.cs b/src/SMAPI.Web/Controllers/LogParserController.cs index 32c45038..2ced5a05 100644 --- a/src/SMAPI.Web/Controllers/LogParserController.cs +++ b/src/SMAPI.Web/Controllers/LogParserController.cs @@ -27,9 +27,6 @@ namespace StardewModdingAPI.Web.Controllers /********* ** Fields *********/ - /// The site config settings. - private readonly SiteConfig SiteConfig; - /// The API client settings. private readonly ApiClientsConfig ClientsConfig; @@ -47,13 +44,11 @@ namespace StardewModdingAPI.Web.Controllers ** Constructor ***/ /// Construct an instance. - /// The context config settings. /// The API client settings. /// The Pastebin API client. /// The underlying text compression helper. - public LogParserController(IOptions siteConfig, IOptions clientsConfig, IPastebinClient pastebin, IGzipHelper gzipHelper) + public LogParserController(IOptions clientsConfig, IPastebinClient pastebin, IGzipHelper gzipHelper) { - this.SiteConfig = siteConfig.Value; this.ClientsConfig = clientsConfig.Value; this.Pastebin = pastebin; this.GzipHelper = gzipHelper; @@ -103,9 +98,7 @@ namespace StardewModdingAPI.Web.Controllers return this.View("Index", this.GetModel(null, uploadError: uploadResult.UploadError)); // redirect to view - UriBuilder uri = new UriBuilder(new Uri(this.SiteConfig.LogParserUrl)); - uri.Path = $"{uri.Path.TrimEnd('/')}/{uploadResult.ID}"; - return this.Redirect(uri.Uri.ToString()); + return this.Redirect(this.Url.Action("Index", "LogParser", new { id = uploadResult.ID })); } @@ -217,10 +210,9 @@ namespace StardewModdingAPI.Web.Controllers /// An error which occurred while uploading the log. private LogParserModel GetModel(string pasteID, DateTime? expiry = null, string uploadWarning = null, string uploadError = null) { - string sectionUrl = this.SiteConfig.LogParserUrl; Platform? platform = this.DetectClientPlatform(); - return new LogParserModel(sectionUrl, pasteID, platform) + return new LogParserModel(pasteID, platform) { UploadWarning = uploadWarning, UploadError = uploadError, diff --git a/src/SMAPI.Web/Controllers/ModsApiController.cs b/src/SMAPI.Web/Controllers/ModsApiController.cs index fe220eb5..f10e0067 100644 --- a/src/SMAPI.Web/Controllers/ModsApiController.cs +++ b/src/SMAPI.Web/Controllers/ModsApiController.cs @@ -49,9 +49,6 @@ namespace StardewModdingAPI.Web.Controllers /// The internal mod metadata list. private readonly ModDatabase ModDatabase; - /// The web URL for the compatibility list. - private readonly string CompatibilityPageUrl; - /********* ** Public methods @@ -70,7 +67,6 @@ namespace StardewModdingAPI.Web.Controllers { this.ModDatabase = new ModToolkit().GetModDatabase(Path.Combine(environment.WebRootPath, "SMAPI.metadata.json")); ModUpdateCheckConfig config = configProvider.Value; - this.CompatibilityPageUrl = config.CompatibilityPageUrl; this.WikiCache = wikiCache; this.ModCache = modCache; @@ -205,7 +201,7 @@ namespace StardewModdingAPI.Web.Controllers // get unofficial version if (wikiEntry?.Compatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, main?.Version) && this.IsNewer(wikiEntry.Compatibility.UnofficialVersion, optional?.Version)) - unofficial = new ModEntryVersionModel(wikiEntry.Compatibility.UnofficialVersion, $"{this.CompatibilityPageUrl}/#{wikiEntry.Anchor}"); + unofficial = new ModEntryVersionModel(wikiEntry.Compatibility.UnofficialVersion, $"{this.Url.Action("Index", "Mods")}#{wikiEntry.Anchor}"); // get unofficial version for beta if (wikiEntry?.HasBetaInfo == true) @@ -215,7 +211,7 @@ namespace StardewModdingAPI.Web.Controllers if (wikiEntry.BetaCompatibility.UnofficialVersion != null) { unofficialForBeta = (wikiEntry.BetaCompatibility.UnofficialVersion != null && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, main?.Version) && this.IsNewer(wikiEntry.BetaCompatibility.UnofficialVersion, optional?.Version)) - ? new ModEntryVersionModel(wikiEntry.BetaCompatibility.UnofficialVersion, $"{this.CompatibilityPageUrl}/#{wikiEntry.Anchor}") + ? new ModEntryVersionModel(wikiEntry.BetaCompatibility.UnofficialVersion, $"{this.Url.Action("Index", "Mods")}#{wikiEntry.Anchor}") : null; } else diff --git a/src/SMAPI.Web/Framework/BeanstalkEnvPropsConfigProvider.cs b/src/SMAPI.Web/Framework/BeanstalkEnvPropsConfigProvider.cs deleted file mode 100644 index fe27fe2f..00000000 --- a/src/SMAPI.Web/Framework/BeanstalkEnvPropsConfigProvider.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Microsoft.Extensions.Configuration; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace StardewModdingAPI.Web.Framework -{ - /// Reads configuration values from the AWS Beanstalk environment properties file (if present). - /// This is a workaround for AWS Beanstalk injection not working with .NET Core apps. - internal class BeanstalkEnvPropsConfigProvider : ConfigurationProvider, IConfigurationSource - { - /********* - ** Fields - *********/ - /// The absolute path to the container configuration file on an Amazon EC2 instance. - private const string ContainerConfigPath = @"C:\Program Files\Amazon\ElasticBeanstalk\config\containerconfiguration"; - - - /********* - ** Public methods - *********/ - /// Build the configuration provider for this source. - /// The configuration builder. - public IConfigurationProvider Build(IConfigurationBuilder builder) - { - return new BeanstalkEnvPropsConfigProvider(); - } - - /// Load the environment properties. - public override void Load() - { - this.Data = new Dictionary(StringComparer.OrdinalIgnoreCase); - - // get Beanstalk config file - FileInfo file = new FileInfo(BeanstalkEnvPropsConfigProvider.ContainerConfigPath); - if (!file.Exists) - return; - - // parse JSON - JObject jsonRoot = (JObject)JsonConvert.DeserializeObject(File.ReadAllText(file.FullName)); - if (jsonRoot["iis"]?["env"] is JArray jsonProps) - { - foreach (string prop in jsonProps.Values()) - { - string[] parts = prop.Split('=', 2); // key=value - if (parts.Length == 2) - this.Data[parts[0]] = parts[1]; - } - } - } - } -} diff --git a/src/SMAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs b/src/SMAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs index ab935bb3..46073eb8 100644 --- a/src/SMAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs +++ b/src/SMAPI.Web/Framework/ConfigModels/ModUpdateCheckConfig.cs @@ -11,8 +11,5 @@ namespace StardewModdingAPI.Web.Framework.ConfigModels /// The number of minutes failed update checks should be cached before refetching them. public int ErrorCacheMinutes { get; set; } - - /// The web URL for the wiki compatibility list. - public string CompatibilityPageUrl { get; set; } } } diff --git a/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs b/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs index bc6e868a..d379c423 100644 --- a/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs +++ b/src/SMAPI.Web/Framework/ConfigModels/SiteConfig.cs @@ -6,18 +6,6 @@ namespace StardewModdingAPI.Web.Framework.ConfigModels /********* ** Accessors *********/ - /// The root URL for the app. - public string RootUrl { get; set; } - - /// The root URL for the log parser. - public string LogParserUrl { get; set; } - - /// The root URL for the JSON validator. - public string JsonValidatorUrl { get; set; } - - /// The root URL for the mod list. - public string ModListUrl { get; set; } - /// Whether to show SMAPI beta versions on the main page, if any. public bool BetaEnabled { get; set; } diff --git a/src/SMAPI.Web/Framework/RewriteRules/ConditionalRewriteSubdomainRule.cs b/src/SMAPI.Web/Framework/RewriteRules/ConditionalRewriteSubdomainRule.cs deleted file mode 100644 index 920632ab..00000000 --- a/src/SMAPI.Web/Framework/RewriteRules/ConditionalRewriteSubdomainRule.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite; - -namespace StardewModdingAPI.Web.Framework.RewriteRules -{ - /// Rewrite requests to prepend the subdomain portion (if any) to the path. - /// Derived from . - internal class ConditionalRewriteSubdomainRule : IRule - { - /********* - ** Accessors - *********/ - /// A predicate which indicates when the rule should be applied. - private readonly Func ShouldRewrite; - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// A predicate which indicates when the rule should be applied. - public ConditionalRewriteSubdomainRule(Func shouldRewrite = null) - { - this.ShouldRewrite = shouldRewrite ?? (req => true); - } - - /// Applies the rule. Implementations of ApplyRule should set the value for (defaults to RuleResult.ContinueRules). - /// The rewrite context. - public void ApplyRule(RewriteContext context) - { - HttpRequest request = context.HttpContext.Request; - - // check condition - if (!this.ShouldRewrite(request)) - return; - - // get host parts - string host = request.Host.Host; - string[] parts = host.Split('.'); - if (parts.Length < 2) - return; - - // prepend to path - request.Path = $"/{parts[0]}{request.Path}"; - } - } -} diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs index fc6161b5..53823771 100644 --- a/src/SMAPI.Web/Startup.cs +++ b/src/SMAPI.Web/Startup.cs @@ -48,7 +48,7 @@ namespace StardewModdingAPI.Web .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - .Add(new BeanstalkEnvPropsConfigProvider()) + .AddEnvironmentVariables() .Build(); } @@ -173,8 +173,7 @@ namespace StardewModdingAPI.Web .UseCors(policy => policy .AllowAnyHeader() .AllowAnyMethod() - .WithOrigins("https://smapi.io", "https://*.smapi.io", "https://*.edge.smapi.io") - .SetIsOriginAllowedToAllowWildcardSubdomains() + .WithOrigins("https://smapi.io") ) .UseRewriter(this.GetRedirectRules()) .UseStaticFiles() // wwwroot folder @@ -202,23 +201,13 @@ namespace StardewModdingAPI.Web shouldRewrite: req => req.Host.Host != "localhost" && !req.Path.StartsWithSegments("/api") - && !req.Host.Host.StartsWith("api.") - )); - - // convert subdomain.smapi.io => smapi.io/subdomain for routing - redirects.Add(new ConditionalRewriteSubdomainRule( - shouldRewrite: req => - req.Host.Host != "localhost" - && (req.Host.Host.StartsWith("api.") || req.Host.Host.StartsWith("json.") || req.Host.Host.StartsWith("log.") || req.Host.Host.StartsWith("mods.")) - && !req.Path.StartsWithSegments("/content") - && !req.Path.StartsWithSegments("/favicon.ico") )); // shortcut redirects redirects.Add(new RedirectToUrlRule(@"^/3\.0\.?$", "https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0")); redirects.Add(new RedirectToUrlRule(@"^/(?:buildmsg|package)(?:/?(.*))$", "https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md#$1")); // buildmsg deprecated, remove when SDV 1.4 is released redirects.Add(new RedirectToUrlRule(@"^/community\.?$", "https://stardewvalleywiki.com/Modding:Community")); - redirects.Add(new RedirectToUrlRule(@"^/compat\.?$", "https://mods.smapi.io")); + redirects.Add(new RedirectToUrlRule(@"^/compat\.?$", "https://smapi.io/mods")); redirects.Add(new RedirectToUrlRule(@"^/docs\.?$", "https://stardewvalleywiki.com/Modding:Index")); redirects.Add(new RedirectToUrlRule(@"^/install\.?$", "https://stardewvalleywiki.com/Modding:Player_Guide/Getting_Started#Install_SMAPI")); redirects.Add(new RedirectToUrlRule(@"^/troubleshoot(.*)$", "https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting$1")); diff --git a/src/SMAPI.Web/ViewModels/JsonValidator/JsonValidatorModel.cs b/src/SMAPI.Web/ViewModels/JsonValidator/JsonValidatorModel.cs index 2d13bf23..5b18331f 100644 --- a/src/SMAPI.Web/ViewModels/JsonValidator/JsonValidatorModel.cs +++ b/src/SMAPI.Web/ViewModels/JsonValidator/JsonValidatorModel.cs @@ -9,9 +9,6 @@ namespace StardewModdingAPI.Web.ViewModels.JsonValidator /********* ** Accessors *********/ - /// The root URL for the log parser controller. - public string SectionUrl { get; set; } - /// The paste ID. public string PasteID { get; set; } @@ -44,13 +41,11 @@ namespace StardewModdingAPI.Web.ViewModels.JsonValidator public JsonValidatorModel() { } /// Construct an instance. - /// The root URL for the log parser controller. /// The paste ID. /// The schema name with which the JSON was validated. /// The supported JSON schemas (names indexed by ID). - public JsonValidatorModel(string sectionUrl, string pasteID, string schemaName, IDictionary schemaFormats) + public JsonValidatorModel(string pasteID, string schemaName, IDictionary schemaFormats) { - this.SectionUrl = sectionUrl; this.PasteID = pasteID; this.SchemaName = schemaName; this.SchemaFormats = schemaFormats; diff --git a/src/SMAPI.Web/ViewModels/LogParserModel.cs b/src/SMAPI.Web/ViewModels/LogParserModel.cs index b06b5b2d..bea79eae 100644 --- a/src/SMAPI.Web/ViewModels/LogParserModel.cs +++ b/src/SMAPI.Web/ViewModels/LogParserModel.cs @@ -20,9 +20,6 @@ namespace StardewModdingAPI.Web.ViewModels /********* ** Accessors *********/ - /// The root URL for the log parser controller. - public string SectionUrl { get; set; } - /// The paste ID. public string PasteID { get; set; } @@ -55,12 +52,10 @@ namespace StardewModdingAPI.Web.ViewModels public LogParserModel() { } /// Construct an instance. - /// The root URL for the log parser controller. /// The paste ID. /// The viewer's detected OS, if known. - public LogParserModel(string sectionUrl, string pasteID, Platform? platform) + public LogParserModel(string pasteID, Platform? platform) { - this.SectionUrl = sectionUrl; this.PasteID = pasteID; this.DetectedPlatform = platform; this.ParsedLog = null; diff --git a/src/SMAPI.Web/Views/Index/Index.cshtml b/src/SMAPI.Web/Views/Index/Index.cshtml index f42dde3b..a79a08f5 100644 --- a/src/SMAPI.Web/Views/Index/Index.cshtml +++ b/src/SMAPI.Web/Views/Index/Index.cshtml @@ -44,14 +44,14 @@ }

Get help

@@ -61,7 +61,7 @@
@Html.Raw(Markdig.Markdown.ToHtml(Model.StableVersion.Description))
-

See the release notes and mod compatibility list for more info.

+

See the release notes and mod compatibility list for more info.

} else { @@ -70,13 +70,13 @@ else
@Html.Raw(Markdig.Markdown.ToHtml(Model.StableVersion.Description))
-

See the release notes and mod compatibility list for more info.

+

See the release notes and mod compatibility list for more info.

SMAPI @Model.BetaVersion.Version?

@Html.Raw(Markdig.Markdown.ToHtml(Model.BetaVersion.Description))
-

See the release notes and mod compatibility list for more info.

+

See the release notes and mod compatibility list for more info.

} diff --git a/src/SMAPI.Web/Views/Index/Privacy.cshtml b/src/SMAPI.Web/Views/Index/Privacy.cshtml index 914384a8..fe4d773a 100644 --- a/src/SMAPI.Web/Views/Index/Privacy.cshtml +++ b/src/SMAPI.Web/Views/Index/Privacy.cshtml @@ -8,7 +8,7 @@ } -← back to SMAPI page +← back to SMAPI page

SMAPI is an open-source and non-profit project. Your privacy is important, so this page explains what information SMAPI uses and transmits. This page is informational only, it's not a legal document.

@@ -34,7 +34,7 @@

Log parser

-

The log parser page lets you store a log file for analysis and sharing. The log data is stored indefinitely in an obfuscated form as unlisted pastes in Pastebin. No personal information is stored by the log parser beyond what you choose to upload, but see web logging and the Pastebin Privacy Statement.

+

The log parser page lets you store a log file for analysis and sharing. The log data is stored indefinitely in an obfuscated form as unlisted pastes in Pastebin. No personal information is stored by the log parser beyond what you choose to upload, but see web logging and the Pastebin Privacy Statement.

Multiplayer sync

As part of its multiplayer API, SMAPI transmits basic context to players you connect to (mainly your OS, SMAPI version, game version, and installed mods). This is used to enable multiplayer features like inter-mod messages, compatibility checks, etc. Although this information is normally hidden from players, it may be visible due to mods or configuration changes.

diff --git a/src/SMAPI.Web/Views/JsonValidator/Index.cshtml b/src/SMAPI.Web/Views/JsonValidator/Index.cshtml index 3143fad9..41dec929 100644 --- a/src/SMAPI.Web/Views/JsonValidator/Index.cshtml +++ b/src/SMAPI.Web/Views/JsonValidator/Index.cshtml @@ -3,8 +3,8 @@ @{ // get view data - string curPageUrl = new Uri(new Uri(Model.SectionUrl), $"{Model.SchemaName}/{Model.PasteID}").ToString(); - string newUploadUrl = Model.SchemaName != null ? new Uri(new Uri(Model.SectionUrl), Model.SchemaName).ToString() : Model.SectionUrl; + string curPageUrl = this.Url.Action("Index", "JsonValidator", new { schemaName = Model.SchemaName, id = Model.PasteID }); + string newUploadUrl = this.Url.Action("Index", "JsonValidator", new { schemaName = Model.SchemaName }); string schemaDisplayName = null; bool isValidSchema = Model.SchemaName != null && Model.SchemaFormats.TryGetValue(Model.SchemaName, out schemaDisplayName) && schemaDisplayName != "None"; @@ -34,8 +34,8 @@ } @@ -70,7 +70,7 @@ else if (Model.PasteID != null) @if (Model.Content == null) {

Upload a JSON file

-
+
  1. Choose the JSON format:
    diff --git a/src/SMAPI.Web/Views/LogParser/Index.cshtml b/src/SMAPI.Web/Views/LogParser/Index.cshtml index df2ac115..07e18421 100644 --- a/src/SMAPI.Web/Views/LogParser/Index.cshtml +++ b/src/SMAPI.Web/Views/LogParser/Index.cshtml @@ -32,7 +32,7 @@ showSections: @Json.Serialize(Enum.GetNames(typeof(LogSection)).ToDictionary(section => section, section => false), noFormatting), showLevels: @Json.Serialize(defaultFilters, noFormatting), enableFilters: @Json.Serialize(!Model.ShowRaw) - }, '@Model.SectionUrl'); + }, '@this.Url.Action("Index", "LogParser")'); }); } @@ -49,8 +49,8 @@ else if (Model.ParseError != null) { @@ -58,8 +58,8 @@ else if (Model.ParseError != null) else if (Model.ParsedLog?.IsValid == true) { } @@ -127,7 +127,7 @@ else if (Model.ParsedLog?.IsValid == true)

    How do I share my log?

    - +
    1. Drag the file onto this textbox (or paste the text in):
      @@ -322,12 +322,12 @@ else if (Model.ParsedLog?.IsValid == true) } - view raw log + view raw log } else {
      @Model.ParsedLog.RawText
      - view parsed log + view parsed log } } diff --git a/src/SMAPI.Web/Views/Shared/_Layout.cshtml b/src/SMAPI.Web/Views/Shared/_Layout.cshtml index 87a22f06..e4b6ca94 100644 --- a/src/SMAPI.Web/Views/Shared/_Layout.cshtml +++ b/src/SMAPI.Web/Views/Shared/_Layout.cshtml @@ -15,15 +15,15 @@
      diff --git a/src/SMAPI.Web/appsettings.Development.json b/src/SMAPI.Web/appsettings.Development.json index 8e863591..6b32f4ab 100644 --- a/src/SMAPI.Web/appsettings.Development.json +++ b/src/SMAPI.Web/appsettings.Development.json @@ -9,10 +9,6 @@ */ { "Site": { - "RootUrl": "http://localhost:59482/", - "ModListUrl": "http://localhost:59482/mods/", - "LogParserUrl": "http://localhost:59482/log/", - "JsonValidatorUrl": "http://localhost:59482/json/", "BetaEnabled": false, "BetaBlurb": null }, diff --git a/src/SMAPI.Web/appsettings.json b/src/SMAPI.Web/appsettings.json index 3b6f8fbd..f81587ef 100644 --- a/src/SMAPI.Web/appsettings.json +++ b/src/SMAPI.Web/appsettings.json @@ -16,10 +16,6 @@ }, "Site": { - "RootUrl": null, - "ModListUrl": null, - "LogParserUrl": null, - "JsonValidatorUrl": null, "BetaEnabled": null, "BetaBlurb": null }, @@ -72,7 +68,6 @@ "ModUpdateCheck": { "SuccessCacheMinutes": 60, - "ErrorCacheMinutes": 5, - "CompatibilityPageUrl": "https://mods.smapi.io" + "ErrorCacheMinutes": 5 } } diff --git a/src/SMAPI.sln b/src/SMAPI.sln index 73852d30..82e5cc2f 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -78,6 +78,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Toolkit.CoreInterface EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web", "SMAPI.Web\SMAPI.Web.csproj", "{80EFD92F-728F-41E0-8A5B-9F6F49A91899}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMAPI.Web.LegacyRedirects", "SMAPI.Web.LegacyRedirects\SMAPI.Web.LegacyRedirects.csproj", "{159AA5A5-35C2-488C-B23F-1613C80594AE}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution SMAPI.Internal\SMAPI.Internal.projitems*{85208f8d-6fd1-4531-be05-7142490f59fe}*SharedItemsImports = 13 @@ -131,6 +133,10 @@ Global {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Debug|Any CPU.Build.0 = Debug|Any CPU {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.ActiveCfg = Release|Any CPU {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.Build.0 = Release|Any CPU + {159AA5A5-35C2-488C-B23F-1613C80594AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {159AA5A5-35C2-488C-B23F-1613C80594AE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {159AA5A5-35C2-488C-B23F-1613C80594AE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {159AA5A5-35C2-488C-B23F-1613C80594AE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/SMAPI/Framework/ModLoading/ModResolver.cs b/src/SMAPI/Framework/ModLoading/ModResolver.cs index 5ea21710..e73bc47d 100644 --- a/src/SMAPI/Framework/ModLoading/ModResolver.cs +++ b/src/SMAPI/Framework/ModLoading/ModResolver.cs @@ -87,7 +87,7 @@ namespace StardewModdingAPI.Framework.ModLoading updateUrls.Add(mod.DataRecord.AlternativeUrl); // default update URL - updateUrls.Add("https://mods.smapi.io"); + updateUrls.Add("https://smapi.io/mods"); // build error string error = $"{reasonPhrase}. Please check for a "; diff --git a/src/SMAPI/Framework/Models/SConfig.cs b/src/SMAPI/Framework/Models/SConfig.cs index b778af5d..53939f8c 100644 --- a/src/SMAPI/Framework/Models/SConfig.cs +++ b/src/SMAPI/Framework/Models/SConfig.cs @@ -23,7 +23,7 @@ namespace StardewModdingAPI.Framework.Models #endif [nameof(UseBetaChannel)] = Constants.ApiVersion.IsPrerelease(), [nameof(GitHubProjectName)] = "Pathoschild/SMAPI", - [nameof(WebApiBaseUrl)] = "https://api.smapi.io", + [nameof(WebApiBaseUrl)] = "https://smapi.io/api/", [nameof(VerboseLogging)] = false, [nameof(LogNetworkTraffic)] = false, [nameof(DumpMetadata)] = false diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index afb82679..f1873391 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -299,7 +299,7 @@ namespace StardewModdingAPI.Framework if (File.Exists(Constants.FatalCrashMarker)) { this.Monitor.Log("The game crashed last time you played. That can be due to bugs in the game, but if it happens repeatedly you can ask for help here: https://community.playstarbound.com/threads/108375/.", LogLevel.Error); - this.Monitor.Log("If you ask for help, make sure to share your SMAPI log: https://log.smapi.io.", LogLevel.Error); + this.Monitor.Log("If you ask for help, make sure to share your SMAPI log: https://smapi.io/log.", LogLevel.Error); this.Monitor.Log("Press any key to delete the crash data and continue playing.", LogLevel.Info); Console.ReadKey(); File.Delete(Constants.FatalCrashLog); @@ -962,7 +962,7 @@ namespace StardewModdingAPI.Framework } catch (IncompatibleInstructionException) // details already in trace logs { - string[] updateUrls = new[] { modDatabase.GetModPageUrlFor(manifest.UniqueID), "https://mods.smapi.io" }.Where(p => p != null).ToArray(); + string[] updateUrls = new[] { modDatabase.GetModPageUrlFor(manifest.UniqueID), "https://smapi.io/mods" }.Where(p => p != null).ToArray(); errorReasonPhrase = $"it's no longer compatible. Please check for a new version at {string.Join(" or ", updateUrls)}"; return false; } diff --git a/src/SMAPI/SMAPI.config.json b/src/SMAPI/SMAPI.config.json index bccac678..a7381b91 100644 --- a/src/SMAPI/SMAPI.config.json +++ b/src/SMAPI/SMAPI.config.json @@ -52,7 +52,7 @@ The default values are mirrored in StardewModdingAPI.Framework.Models.SConfig to * Note: the protocol will be changed to http:// on Linux/Mac due to OpenSSL issues with the * game's bundled Mono. */ - "WebApiBaseUrl": "https://api.smapi.io", + "WebApiBaseUrl": "https://smapi.io/api/", /** * Whether SMAPI should log network traffic (may be very verbose). Best combined with VerboseLogging, which includes network metadata. -- cgit From d07495c2dc1ed2f2af343705a8c4381e4e9cff18 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 2 Dec 2019 21:23:41 -0500 Subject: fix JSON Validator issues --- docs/release-notes.md | 7 +++++-- src/SMAPI.Web/Controllers/JsonValidatorController.cs | 2 +- src/SMAPI.Web/wwwroot/Content/js/json-validator.js | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index dcce70c9..acb1e97c 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -3,11 +3,14 @@ # Release notes ## Upcoming release -* For the web UI: - * If a log can't be uploaded to Pastebin (e.g. due to rate limits), it'll be uploaded to Amazon S3 instead. Logs uploaded to S3 will expire after one month. +* For players: * Improved compatibility with some Linux terminals (thanks to archification and DanielHeath!). * Updated translations. Thanks to berkayylmao (added Turkish), feathershine (added Chinese), and Osiris901 (added Russian)! +* For the web UI: + * If a log can't be uploaded to Pastebin (e.g. due to rate limits), it'll be uploaded to Amazon S3 instead. Logs uploaded to S3 will expire after one month. + * Fixed JSON validator not letting you drag & drop a file. + ## 3.0 Released 26 November 2019 for Stardew Valley 1.4. diff --git a/src/SMAPI.Web/Controllers/JsonValidatorController.cs b/src/SMAPI.Web/Controllers/JsonValidatorController.cs index 9e3e81b8..40599abc 100644 --- a/src/SMAPI.Web/Controllers/JsonValidatorController.cs +++ b/src/SMAPI.Web/Controllers/JsonValidatorController.cs @@ -151,7 +151,7 @@ namespace StardewModdingAPI.Web.Controllers return this.View("Index", new JsonValidatorModel(result.ID, schemaName, this.SchemaFormats).SetUploadError($"Pastebin error: {result.Error ?? "unknown error"}")); // redirect to view - return this.Redirect(this.Url.PlainAction("Index", "LogParser", new { schemaName = schemaName, id = result.ID })); + return this.Redirect(this.Url.PlainAction("Index", "JsonValidator", new { schemaName = schemaName, id = result.ID })); } diff --git a/src/SMAPI.Web/wwwroot/Content/js/json-validator.js b/src/SMAPI.Web/wwwroot/Content/js/json-validator.js index 5499cef6..76b5f6d4 100644 --- a/src/SMAPI.Web/wwwroot/Content/js/json-validator.js +++ b/src/SMAPI.Web/wwwroot/Content/js/json-validator.js @@ -142,6 +142,7 @@ smapi.jsonValidator = function (sectionUrl, pasteID) { }); // upload form + var submit = $("#submit"); var input = $("#input"); if (input.length) { // disable submit if it's empty -- cgit From abf5f274549fa25365e6633950b0c04f1b5daa91 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 2 Dec 2019 22:37:03 -0500 Subject: add support for semver 2.0 build metadata, update for SDV 1.4.0.1 --- docs/release-notes.md | 4 ++ src/SMAPI.Tests/Utilities/SemanticVersionTests.cs | 56 ++++++++++++++-------- .../ISemanticVersion.cs | 3 ++ src/SMAPI.Toolkit/SemanticVersion.cs | 32 +++++++++---- src/SMAPI/Framework/GameVersion.cs | 20 ++++++-- src/SMAPI/SemanticVersion.cs | 10 ++-- 6 files changed, 90 insertions(+), 35 deletions(-) (limited to 'docs') diff --git a/docs/release-notes.md b/docs/release-notes.md index acb1e97c..e6214a37 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -4,6 +4,7 @@ ## Upcoming release * For players: + * Updated for Stardew Valley 1.4.0.1. * Improved compatibility with some Linux terminals (thanks to archification and DanielHeath!). * Updated translations. Thanks to berkayylmao (added Turkish), feathershine (added Chinese), and Osiris901 (added Russian)! @@ -11,6 +12,9 @@ * If a log can't be uploaded to Pastebin (e.g. due to rate limits), it'll be uploaded to Amazon S3 instead. Logs uploaded to S3 will expire after one month. * Fixed JSON validator not letting you drag & drop a file. +* For modders: + * `SemanticVersion` now supports [semver 2.0](https://semver.org/) build metadata. + ## 3.0 Released 26 November 2019 for Stardew Valley 1.4. diff --git a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs index c91ec27f..48afcaa2 100644 --- a/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs +++ b/src/SMAPI.Tests/Utilities/SemanticVersionTests.cs @@ -25,44 +25,50 @@ namespace SMAPI.Tests.Utilities [TestCase("1.2.3-some-tag.4", ExpectedResult = "1.2.3-some-tag.4")] [TestCase("1.2.3-SoME-tAg.4", ExpectedResult = "1.2.3-SoME-tAg.4")] [TestCase("1.2.3-some-tag.4 ", ExpectedResult = "1.2.3-some-tag.4")] + [TestCase("1.2.3-some-tag.4+build.004", ExpectedResult = "1.2.3-some-tag.4+build.004")] + [TestCase("1.2+3.4.5-build.004", ExpectedResult = "1.2.0+3.4.5-build.004")] public string Constructor_FromString(string input) { return new SemanticVersion(input).ToString(); } [Test(Description = "Assert that the constructor sets the expected values for all valid versions when constructed from the individual numbers.")] - [TestCase(1, 0, 0, null, ExpectedResult = "1.0.0")] - [TestCase(3000, 4000, 5000, null, ExpectedResult = "3000.4000.5000")] - [TestCase(1, 2, 3, "", ExpectedResult = "1.2.3")] - [TestCase(1, 2, 3, " ", ExpectedResult = "1.2.3")] - [TestCase(1, 2, 3, "0", ExpectedResult = "1.2.3-0")] - [TestCase(1, 2, 3, "some-tag.4", ExpectedResult = "1.2.3-some-tag.4")] - [TestCase(1, 2, 3, "sOMe-TaG.4", ExpectedResult = "1.2.3-sOMe-TaG.4")] - [TestCase(1, 2, 3, "some-tag.4 ", ExpectedResult = "1.2.3-some-tag.4")] - public string Constructor_FromParts(int major, int minor, int patch, string tag) + [TestCase(1, 0, 0, null, null, ExpectedResult = "1.0.0")] + [TestCase(3000, 4000, 5000, null, null, ExpectedResult = "3000.4000.5000")] + [TestCase(1, 2, 3, "", null, ExpectedResult = "1.2.3")] + [TestCase(1, 2, 3, " ", null, ExpectedResult = "1.2.3")] + [TestCase(1, 2, 3, "0", null, ExpectedResult = "1.2.3-0")] + [TestCase(1, 2, 3, "some-tag.4", null, ExpectedResult = "1.2.3-some-tag.4")] + [TestCase(1, 2, 3, "sOMe-TaG.4", null, ExpectedResult = "1.2.3-sOMe-TaG.4")] + [TestCase(1, 2, 3, "some-tag.4 ", null, ExpectedResult = "1.2.3-some-tag.4")] + [TestCase(1, 2, 3, "some-tag.4 ", "build.004", ExpectedResult = "1.2.3-some-tag.4+build.004")] + [TestCase(1, 2, 0, null, "3.4.5-build.004", ExpectedResult = "1.2.0+3.4.5-build.004")] + public string Constructor_FromParts(int major, int minor, int patch, string prerelease, string build) { // act - ISemanticVersion version = new SemanticVersion(major, minor, patch, tag); + ISemanticVersion version = new SemanticVersion(major, minor, patch, prerelease, build); // assert Assert.AreEqual(major, version.MajorVersion, "The major version doesn't match the given value."); Assert.AreEqual(minor, version.MinorVersion, "The minor version doesn't match the given value."); Assert.AreEqual(patch, version.PatchVersion, "The patch version doesn't match the given value."); - Assert.AreEqual(string.IsNullOrWhiteSpace(tag) ? null : tag.Trim(), version.PrereleaseTag, "The tag doesn't match the given value."); + Assert.AreEqual(string.IsNullOrWhiteSpace(prerelease) ? null : prerelease.Trim(), version.PrereleaseTag, "The prerelease tag doesn't match the given value."); + Assert.AreEqual(string.IsNullOrWhiteSpace(build) ? null : build.Trim(), version.BuildMetadata, "The build metadata doesn't match the given value."); return version.ToString(); } [Test(Description = "Assert that the constructor throws the expected exception for invalid versions when constructed from the individual numbers.")] - [TestCase(0, 0, 0, null)] - [TestCase(-1, 0, 0, null)] - [TestCase(0, -1, 0, null)] - [TestCase(0, 0, -1, null)] - [TestCase(1, 0, 0, "-tag")] - [TestCase(1, 0, 0, "tag spaces")] - [TestCase(1, 0, 0, "tag~")] - public void Constructor_FromParts_WithInvalidValues(int major, int minor, int patch, string tag) + [TestCase(0, 0, 0, null, null)] + [TestCase(-1, 0, 0, null, null)] + [TestCase(0, -1, 0, null, null)] + [TestCase(0, 0, -1, null, null)] + [TestCase(1, 0, 0, "-tag", null)] + [TestCase(1, 0, 0, "tag spaces", null)] + [TestCase(1, 0, 0, "tag~", null)] + [TestCase(1, 0, 0, null, "build~")] + public void Constructor_FromParts_WithInvalidValues(int major, int minor, int patch, string prerelease, string build) { - this.AssertAndLogException(() => new SemanticVersion(major, minor, patch, tag)); + this.AssertAndLogException(() => new SemanticVersion(major, minor, patch, prerelease, build)); } [Test(Description = "Assert that the constructor sets the expected values for all valid versions when constructed from an assembly version.")] @@ -98,6 +104,7 @@ namespace SMAPI.Tests.Utilities [TestCase("1.2.3--some-tag")] [TestCase("1.2.3-some-tag...")] [TestCase("1.2.3-some-tag...4")] + [TestCase("1.2.3-some-tag.4+build...4")] [TestCase("apple")] [TestCase("-apple")] [TestCase("-5")] @@ -119,6 +126,8 @@ namespace SMAPI.Tests.Utilities [TestCase("1.0-beta", "1.0-beta", ExpectedResult = 0)] [TestCase("1.0-beta.10", "1.0-beta.10", ExpectedResult = 0)] [TestCase("1.0-beta", "1.0-beta ", ExpectedResult = 0)] + [TestCase("1.0-beta+build.001", "1.0-beta+build.001", ExpectedResult = 0)] + [TestCase("1.0-beta+build.001", "1.0-beta+build.006", ExpectedResult = 0)] // build metadata must not affect precedence // less than [TestCase("0.5.7", "0.5.8", ExpectedResult = -1)] @@ -156,6 +165,8 @@ namespace SMAPI.Tests.Utilities [TestCase("1.0-beta", "1.0-beta", ExpectedResult = false)] [TestCase("1.0-beta.10", "1.0-beta.10", ExpectedResult = false)] [TestCase("1.0-beta", "1.0-beta ", ExpectedResult = false)] + [TestCase("1.0-beta+build.001", "1.0-beta+build.001", ExpectedResult = false)] // build metadata must not affect precedence + [TestCase("1.0-beta+build.001", "1.0-beta+build.006", ExpectedResult = false)] // build metadata must not affect precedence // less than [TestCase("0.5.7", "0.5.8", ExpectedResult = true)] @@ -192,6 +203,8 @@ namespace SMAPI.Tests.Utilities [TestCase("1.0-beta", "1.0-beta", ExpectedResult = false)] [TestCase("1.0-beta.10", "1.0-beta.10", ExpectedResult = false)] [TestCase("1.0-beta", "1.0-beta ", ExpectedResult = false)] + [TestCase("1.0-beta+build.001", "1.0-beta+build.001", ExpectedResult = false)] // build metadata must not affect precedence + [TestCase("1.0-beta+build.001", "1.0-beta+build.006", ExpectedResult = false)] // build metadata must not affect precedence // less than [TestCase("0.5.7", "0.5.8", ExpectedResult = false)] @@ -279,6 +292,8 @@ namespace SMAPI.Tests.Utilities [TestCase("1.11")] [TestCase("1.2")] [TestCase("1.2.15")] + [TestCase("1.4.0.1")] + [TestCase("1.4.0.6")] public void GameVersion(string versionStr) { // act @@ -286,7 +301,6 @@ namespace SMAPI.Tests.Utilities // assert Assert.AreEqual(versionStr, version.ToString(), "The game version did not round-trip to the same value."); - Assert.IsTrue(version.IsOlderThan(new SemanticVersion("1.2.30")), "The game version should be considered older than the later semantic versions."); } diff --git a/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs b/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs index 4ec87d7c..b8572d50 100644 --- a/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs +++ b/src/SMAPI.Toolkit.CoreInterfaces/ISemanticVersion.cs @@ -20,6 +20,9 @@ namespace StardewModdingAPI /// An optional prerelease tag. string PrereleaseTag { get; } + /// Optional build metadata. This is ignored when determining version precedence. + string BuildMetadata { get; } + /********* ** Accessors diff --git a/src/SMAPI.Toolkit/SemanticVersion.cs b/src/SMAPI.Toolkit/SemanticVersion.cs index 2ce3578e..4955dcae 100644 --- a/src/SMAPI.Toolkit/SemanticVersion.cs +++ b/src/SMAPI.Toolkit/SemanticVersion.cs @@ -7,8 +7,7 @@ namespace StardewModdingAPI.Toolkit /// /// The implementation is defined by Semantic Version 2.0 (https://semver.org/), with a few deviations: /// - short-form "x.y" versions are supported (equivalent to "x.y.0"); - /// - hyphens are synonymous with dots in prerelease tags (like "-unofficial.3-pathoschild"); - /// - +build suffixes are not supported; + /// - hyphens are synonymous with dots in prerelease tags and build metadata (like "-unofficial.3-pathoschild"); /// - and "-unofficial" in prerelease tags is always lower-precedence (e.g. "1.0-beta" is newer than "1.0-unofficial"). /// public class SemanticVersion : ISemanticVersion @@ -16,11 +15,11 @@ namespace StardewModdingAPI.Toolkit /********* ** Fields *********/ - /// A regex pattern matching a valid prerelease tag. + /// A regex pattern matching a valid prerelease or build metadata tag. internal const string TagPattern = @"(?>[a-z0-9]+[\-\.]?)+"; /// A regex pattern matching a version within a larger string. - internal const string UnboundedVersionPattern = @"(?>(?0|[1-9]\d*))\.(?>(?0|[1-9]\d*))(?>(?:\.(?0|[1-9]\d*))?)(?:-(?" + SemanticVersion.TagPattern + "))?"; + internal const string UnboundedVersionPattern = @"(?>(?0|[1-9]\d*))\.(?>(?0|[1-9]\d*))(?>(?:\.(?0|[1-9]\d*))?)(?:-(?" + SemanticVersion.TagPattern + "))?(?:\\+(?" + SemanticVersion.TagPattern + "))?"; /// A regular expression matching a semantic version string. /// This pattern is derived from the BNF documentation in the semver repo, with deviations to support the Stardew Valley mod conventions (see remarks on ). @@ -42,6 +41,9 @@ namespace StardewModdingAPI.Toolkit /// An optional prerelease tag. public string PrereleaseTag { get; } + /// Optional build metadata. This is ignored when determining version precedence. + public string BuildMetadata { get; } + /********* ** Public methods @@ -51,12 +53,14 @@ namespace StardewModdingAPI.Toolkit /// The minor version incremented for backwards-compatible changes. /// The patch version for backwards-compatible fixes. /// An optional prerelease tag. - public SemanticVersion(int major, int minor, int patch, string prereleaseTag = null) + /// Optional build metadata. This is ignored when determining version precedence. + public SemanticVersion(int major, int minor, int patch, string prereleaseTag = null, string buildMetadata = null) { this.MajorVersion = major; this.MinorVersion = minor; this.PatchVersion = patch; this.PrereleaseTag = this.GetNormalizedTag(prereleaseTag); + this.BuildMetadata = this.GetNormalizedTag(buildMetadata); this.AssertValid(); } @@ -94,6 +98,7 @@ namespace StardewModdingAPI.Toolkit this.MinorVersion = match.Groups["minor"].Success ? int.Parse(match.Groups["minor"].Value) : 0; this.PatchVersion = match.Groups["patch"].Success ? int.Parse(match.Groups["patch"].Value) : 0; this.PrereleaseTag = match.Groups["prerelease"].Success ? this.GetNormalizedTag(match.Groups["prerelease"].Value) : null; + this.BuildMetadata = match.Groups["buildmetadata"].Success ? this.GetNormalizedTag(match.Groups["buildmetadata"].Value) : null; this.AssertValid(); } @@ -175,6 +180,8 @@ namespace StardewModdingAPI.Toolkit string version = $"{this.MajorVersion}.{this.MinorVersion}.{this.PatchVersion}"; if (this.PrereleaseTag != null) version += $"-{this.PrereleaseTag}"; + if (this.BuildMetadata != null) + version += $"+{this.BuildMetadata}"; return version; } @@ -200,7 +207,7 @@ namespace StardewModdingAPI.Toolkit /********* ** Private methods *********/ - /// Get a normalized build tag. + /// Get a normalized prerelease or build tag. /// The tag to normalize. private string GetNormalizedTag(string tag) { @@ -277,12 +284,21 @@ namespace StardewModdingAPI.Toolkit throw new FormatException($"{this} isn't a valid semantic version. The major, minor, and patch numbers can't be negative."); if (this.MajorVersion == 0 && this.MinorVersion == 0 && this.PatchVersion == 0) throw new FormatException($"{this} isn't a valid semantic version. At least one of the major, minor, and patch numbers must be more than zero."); + if (this.PrereleaseTag != null) { if (this.PrereleaseTag.Trim() == "") - throw new FormatException($"{this} isn't a valid semantic version. The tag cannot be a blank string (but may be omitted)."); + throw new FormatException($"{this} isn't a valid semantic version. The prerelease tag cannot be a blank string (but may be omitted)."); if (!Regex.IsMatch(this.PrereleaseTag, $"^{SemanticVersion.TagPattern}$", RegexOptions.IgnoreCase)) - throw new FormatException($"{this} isn't a valid semantic version. The tag is invalid."); + throw new FormatException($"{this} isn't a valid semantic version. The prerelease tag is invalid."); + } + + if (this.BuildMetadata != null) + { + if (this.BuildMetadata.Trim() == "") + throw new FormatException($"{this} isn't a valid semantic version. The build metadata cannot be a blank string (but may be omitted)."); + if (!Regex.IsMatch(this.BuildMetadata, $"^{SemanticVersion.TagPattern}$", RegexOptions.IgnoreCase)) + throw new FormatException($"{this} isn't a valid semantic version. The build metadata is invalid."); } } } diff --git a/src/SMAPI/Framework/GameVersion.cs b/src/SMAPI/Framework/GameVersion.cs index cd88895c..29cfbc39 100644 --- a/src/SMAPI/Framework/GameVersion.cs +++ b/src/SMAPI/Framework/GameVersion.cs @@ -52,20 +52,34 @@ namespace StardewModdingAPI.Framework /// The game version string. private static string GetSemanticVersionString(string gameVersion) { - return GameVersion.VersionMap.TryGetValue(gameVersion, out string semanticVersion) - ? semanticVersion - : gameVersion; + // mapped version + if (GameVersion.VersionMap.TryGetValue(gameVersion, out string semanticVersion)) + return semanticVersion; + + // special case: four-part versions + string[] parts = gameVersion.Split('.'); + if (parts.Length == 4) + return $"{parts[0]}.{parts[1]}.{parts[2]}+{parts[3]}"; + + return gameVersion; } /// Convert a semantic version string to the equivalent game version string. /// The semantic version string. private static string GetGameVersionString(string semanticVersion) { + // mapped versions foreach (var mapping in GameVersion.VersionMap) { if (mapping.Value.Equals(semanticVersion, StringComparison.InvariantCultureIgnoreCase)) return mapping.Key; } + + // special case: four-part versions + string[] parts = semanticVersion.Split('.', '+'); + if (parts.Length == 4) + return $"{parts[0]}.{parts[1]}.{parts[2]}.{parts[3]}"; + return semanticVersion; } } diff --git a/src/SMAPI/SemanticVersion.cs b/src/SMAPI/SemanticVersion.cs index 0db41673..2a33ecef 100644 --- a/src/SMAPI/SemanticVersion.cs +++ b/src/SMAPI/SemanticVersion.cs @@ -28,6 +28,9 @@ namespace StardewModdingAPI /// An optional prerelease tag. public string PrereleaseTag => this.Version.PrereleaseTag; + /// Optional build metadata. This is ignored when determining version precedence. + public string BuildMetadata => this.Version.BuildMetadata; + /********* ** Public methods @@ -36,10 +39,11 @@ namespace StardewModdingAPI /// The major version incremented for major API changes. /// The minor version incremented for backwards-compatible changes. /// The patch version for backwards-compatible bug fixes. - /// An optional build tag. + /// An optional prerelease tag. + /// Optional build metadata. This is ignored when determining version precedence. [JsonConstructor] - public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, string build = null) - : this(new Toolkit.SemanticVersion(majorVersion, minorVersion, patchVersion, build)) { } + public SemanticVersion(int majorVersion, int minorVersion, int patchVersion, string prerelease = null, string build = null) + : this(new Toolkit.SemanticVersion(majorVersion, minorVersion, patchVersion, prerelease, build)) { } /// Construct an instance. /// The semantic version string. -- cgit From 1128451acf56cf479864047c0bb8bb18e232fa00 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 2 Dec 2019 22:47:42 -0500 Subject: prepare for release --- build/common.targets | 2 +- docs/release-notes.md | 6 ++++-- src/SMAPI.Mods.ConsoleCommands/manifest.json | 4 ++-- src/SMAPI.Mods.SaveBackup/manifest.json | 4 ++-- src/SMAPI.sln | 3 +-- src/SMAPI/Constants.cs | 2 +- 6 files changed, 11 insertions(+), 10 deletions(-) (limited to 'docs') diff --git a/build/common.targets b/build/common.targets index 10cdbe2c..e738bab0 100644 --- a/build/common.targets +++ b/build/common.targets @@ -4,7 +4,7 @@ - 3.0.0 + 3.0.1 SMAPI $(AssemblySearchPaths);{GAC} diff --git a/docs/release-notes.md b/docs/release-notes.md index e6214a37..1c106542 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,7 +1,8 @@ ← [README](README.md) # Release notes -## Upcoming release +## 3.0.1 +Released 02 December 2019 for Stardew Valley 1.4.0.1. * For players: * Updated for Stardew Valley 1.4.0.1. @@ -9,7 +10,8 @@ * Updated translations. Thanks to berkayylmao (added Turkish), feathershine (added Chinese), and Osiris901 (added Russian)! * For the web UI: - * If a log can't be uploaded to Pastebin (e.g. due to rate limits), it'll be uploaded to Amazon S3 instead. Logs uploaded to S3 will expire after one month. + * Rebuilt web infrastructure to handle higher traffic. + * If a log can't be uploaded to Pastebin (e.g. due to rate limits), it's now uploaded to Amazon S3 instead. Logs uploaded to S3 expire after one month. * Fixed JSON validator not letting you drag & drop a file. * For modders: diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index 802de3a6..badea825 100644 --- a/src/SMAPI.Mods.ConsoleCommands/manifest.json +++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json @@ -1,9 +1,9 @@ { "Name": "Console Commands", "Author": "SMAPI", - "Version": "3.0.0", + "Version": "3.0.1", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "3.0.0" + "MinimumApiVersion": "3.0.1" } diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json index eddd3443..252c359f 100644 --- a/src/SMAPI.Mods.SaveBackup/manifest.json +++ b/src/SMAPI.Mods.SaveBackup/manifest.json @@ -1,9 +1,9 @@ { "Name": "Save Backup", "Author": "SMAPI", - "Version": "3.0.0", + "Version": "3.0.1", "Description": "Automatically backs up all your saves once per day into its folder.", "UniqueID": "SMAPI.SaveBackup", "EntryDll": "SaveBackup.dll", - "MinimumApiVersion": "3.0.0" + "MinimumApiVersion": "3.0.1" } diff --git a/src/SMAPI.sln b/src/SMAPI.sln index 82e5cc2f..62eaa777 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -28,7 +28,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{09CF91E5 ProjectSection(SolutionItems) = preProject ..\build\common.targets = ..\build\common.targets ..\build\find-game-folder.targets = ..\build\find-game-folder.targets - ..\build\GlobalAssemblyInfo.cs = ..\build\GlobalAssemblyInfo.cs ..\build\prepare-install-package.targets = ..\build\prepare-install-package.targets ..\build\prepare-nuget-package.targets = ..\build\prepare-nuget-package.targets EndProjectSection @@ -78,7 +77,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Toolkit.CoreInterface EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web", "SMAPI.Web\SMAPI.Web.csproj", "{80EFD92F-728F-41E0-8A5B-9F6F49A91899}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SMAPI.Web.LegacyRedirects", "SMAPI.Web.LegacyRedirects\SMAPI.Web.LegacyRedirects.csproj", "{159AA5A5-35C2-488C-B23F-1613C80594AE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web.LegacyRedirects", "SMAPI.Web.LegacyRedirects\SMAPI.Web.LegacyRedirects.csproj", "{159AA5A5-35C2-488C-B23F-1613C80594AE}" EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 9b113733..7fdfb8d0 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -20,7 +20,7 @@ namespace StardewModdingAPI ** Public ****/ /// SMAPI's current semantic version. - public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.0.0"); + public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.0.1"); /// The minimum supported version of Stardew Valley. public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.4.0"); -- cgit