diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index 3abb1bb39a..61e587b569 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -110,6 +110,7 @@ internal class PluginInstallerWindow : Window, IDisposable private bool feedbackModalIncludeException = false; private IPluginManifest? feedbackPlugin = null; private bool feedbackIsTesting = false; + private bool feedbackIsCustomRepo = false; private int updatePluginCount = 0; private List? updatedPlugins; @@ -1071,6 +1072,11 @@ private void DrawFeedbackModal() ImGui.TextColored(ImGuiColors.DalamudRed, Locs.FeedbackModal_ContactInformationWarning); + if (this.feedbackPlugin?.FeedbackWebhook != null && this.feedbackIsCustomRepo) + { + ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Locs.FeedbackModal_IPAddressWarning); + } + ImGui.Spacing(); ImGui.Checkbox(Locs.FeedbackModal_IncludeLastError, ref this.feedbackModalIncludeException); @@ -1101,6 +1107,7 @@ private void DrawFeedbackModal() Task.Run(async () => await BugBait.SendFeedback( this.feedbackPlugin, this.feedbackIsTesting, + this.feedbackIsCustomRepo, this.feedbackModalBody, this.feedbackModalContact, this.feedbackModalIncludeException)) @@ -2444,10 +2451,13 @@ private void DrawAvailablePlugin(RemotePluginManifest manifest, int index) ImGuiHelpers.ScaledDummy(3); } - if (!manifest.SourceRepo.IsThirdParty && manifest.AcceptsFeedback && !isOutdated) + var feedbackEligible = manifest.AcceptsFeedback && + (!manifest.SourceRepo.IsThirdParty || manifest.FeedbackWebhook != null); + + if (feedbackEligible && !isOutdated) { ImGui.SameLine(); - this.DrawSendFeedbackButton(manifest, false, true); + this.DrawSendFeedbackButton(manifest, false, manifest.SourceRepo.IsThirdParty, true); } ImGuiHelpers.ScaledDummy(5); @@ -2717,16 +2727,12 @@ private void DrawInstalledPlugin(LocalPlugin plugin, int index, RemotePluginMani ImGui.SameLine(); ImGui.TextColored(ImGuiColors.DalamudGrey3, downloadText); - var acceptsFeedback = - this.pluginListAvailable.Any(x => x.InternalName == plugin.InternalName && x.AcceptsFeedback); - var isThirdParty = plugin.IsThirdParty; - var canFeedback = !isThirdParty && - !plugin.IsDev && + var canFeedback = !plugin.IsDev && !plugin.IsOrphaned && (plugin.Manifest.DalamudApiLevel == PluginManager.DalamudApiLevel || (plugin.Manifest.TestingDalamudApiLevel == PluginManager.DalamudApiLevel && hasTestingAvailable)) && - acceptsFeedback && + plugin.Manifest.AcceptsFeedback && (!plugin.IsThirdParty || plugin.Manifest.FeedbackWebhook != null) && availablePluginUpdate == default; // Installed from @@ -2793,7 +2799,7 @@ private void DrawInstalledPlugin(LocalPlugin plugin, int index, RemotePluginMani if (canFeedback) { ImGui.SameLine(); - this.DrawSendFeedbackButton(plugin.Manifest, plugin.IsTesting, false); + this.DrawSendFeedbackButton(plugin.Manifest, plugin.IsTesting, plugin.IsThirdParty, false); } if (availablePluginUpdate != default && !plugin.IsDev) @@ -3275,7 +3281,7 @@ private void DrawOpenPluginSettingsButton(LocalPlugin plugin) } } - private void DrawSendFeedbackButton(IPluginManifest manifest, bool isTesting, bool big) + private void DrawSendFeedbackButton(IPluginManifest manifest, bool isTesting, bool isCustomRepo, bool big) { var clicked = big ? ImGuiComponents.IconButtonWithText(FontAwesomeIcon.Comment, Locs.FeedbackModal_Title) : @@ -3286,6 +3292,7 @@ private void DrawSendFeedbackButton(IPluginManifest manifest, bool isTesting, bo this.feedbackPlugin = manifest; this.feedbackModalOnNextFrame = true; this.feedbackIsTesting = isTesting; + this.feedbackIsCustomRepo = isCustomRepo; } if (ImGui.IsItemHovered()) @@ -3753,7 +3760,7 @@ private void ResortPlugins() case PluginSortKind.EnabledDisabled: this.pluginListAvailable.Sort((p1, p2) => { - bool IsEnabled(PluginManifest manifest) + bool IsEnabled(IPluginManifest manifest) { return this.pluginListInstalled.Any(x => x.Manifest.InternalName == manifest.InternalName); } @@ -4255,6 +4262,8 @@ public static string Notifications_UpdatesInstalled(List upd public static string FeedbackModal_Hint => Loc.Localize("InstallerFeedbackHint", "All plugin developers will be able to see your feedback.\nPlease never include any personal or revealing information.\nIf you chose to include the last error message, information like your Windows username may be included.\n\nThe collected feedback is not stored on our end and immediately relayed to Discord."); + public static string FeedbackModal_IPAddressWarning => Loc.Localize("InstallerFeedbackIPAddressWarning", "This plugin is configured to send feedback to a server defined by its maintainer, which may log your IP address. Please ensure you trust the author of this plugin!"); + public static string FeedbackModal_NotificationSuccess => Loc.Localize("InstallerFeedbackNotificationSuccess", "Your feedback was sent successfully!"); public static string FeedbackModal_NotificationError => Loc.Localize("InstallerFeedbackNotificationError", "Your feedback could not be sent."); diff --git a/Dalamud/Plugin/Internal/Types/Manifest/IPluginManifest.cs b/Dalamud/Plugin/Internal/Types/Manifest/IPluginManifest.cs index 4b09513977..4efdb0f555 100644 --- a/Dalamud/Plugin/Internal/Types/Manifest/IPluginManifest.cs +++ b/Dalamud/Plugin/Internal/Types/Manifest/IPluginManifest.cs @@ -16,7 +16,7 @@ public interface IPluginManifest /// Gets the public name of the plugin. /// public string Name { get; } - + /// /// Gets a punchline of the plugins functions. /// @@ -26,7 +26,7 @@ public interface IPluginManifest /// Gets the author/s of the plugin. /// public string Author { get; } - + /// /// Gets a value indicating whether the plugin can be unloaded asynchronously. /// @@ -41,17 +41,17 @@ public interface IPluginManifest /// Gets the assembly version of the plugin's testing variant. /// public Version? TestingAssemblyVersion { get; } - + /// /// Gets the DIP17 channel name. /// public string? Dip17Channel { get; } - + /// /// Gets the last time this plugin was updated. /// public long LastUpdate { get; } - + /// /// Gets a changelog, null if none exists. /// @@ -88,17 +88,28 @@ public interface IPluginManifest /// Gets an URL to the website or source code of the plugin. /// public string? RepoUrl { get; } - + /// /// Gets a description of the plugins functions. /// public string? Description { get; } + /// + /// Gets a value indicating whether this plugin accepts feedback. + /// + public bool AcceptsFeedback { get; } + /// /// Gets a message that is shown to users when sending feedback. /// public string? FeedbackMessage { get; } + /// + /// Gets the URL to submit plugin feedback to. + /// For mainline plugins, the WebServices API will be responsible for relaying feedback regardless of this value. + /// + public string? FeedbackWebhook { get; } + /// /// Gets a value indicating whether the plugin is only available for testing. /// diff --git a/Dalamud/Plugin/Internal/Types/Manifest/RemotePluginManifest.cs b/Dalamud/Plugin/Internal/Types/Manifest/RemotePluginManifest.cs index e3d99a85a3..658ba35d34 100644 --- a/Dalamud/Plugin/Internal/Types/Manifest/RemotePluginManifest.cs +++ b/Dalamud/Plugin/Internal/Types/Manifest/RemotePluginManifest.cs @@ -16,7 +16,7 @@ internal record RemotePluginManifest : PluginManifest /// [JsonIgnore] public PluginRepository SourceRepo { get; set; } = null!; - + /// /// Gets or sets the changelog to be shown when obtaining the testing version of the plugin. /// diff --git a/Dalamud/Plugin/Internal/Types/PluginManifest.cs b/Dalamud/Plugin/Internal/Types/PluginManifest.cs index 01951c8a64..2b6ac8ddbd 100644 --- a/Dalamud/Plugin/Internal/Types/PluginManifest.cs +++ b/Dalamud/Plugin/Internal/Types/PluginManifest.cs @@ -145,14 +145,15 @@ internal record PluginManifest : IPluginManifest /// public string? IconUrl { get; init; } - /// - /// Gets a value indicating whether this plugin accepts feedback. - /// + /// public bool AcceptsFeedback { get; init; } = true; /// public string? FeedbackMessage { get; init; } + /// + public string? FeedbackWebhook { get; init; } + /// [JsonProperty("_Dip17Channel")] public string? Dip17Channel { get; init; } diff --git a/Dalamud/Support/BugBait.cs b/Dalamud/Support/BugBait.cs index c82e5e652c..3a33c8c77d 100644 --- a/Dalamud/Support/BugBait.cs +++ b/Dalamud/Support/BugBait.cs @@ -14,7 +14,7 @@ namespace Dalamud.Support; /// internal static class BugBait { - private const string BugBaitUrl = "https://kiko.goats.dev/feedback"; + private const string BugBaitUrl = "https://api.dalamud.dev/feedback"; /// /// Send feedback to Discord. @@ -25,7 +25,7 @@ internal static class BugBait /// The reporter name. /// Whether or not the most recent exception to occur should be included in the report. /// A representing the asynchronous operation. - public static async Task SendFeedback(IPluginManifest plugin, bool isTesting, string content, string reporter, bool includeException) + public static async Task SendFeedback(IPluginManifest plugin, bool isTesting, bool isCustomRepo, string content, string reporter, bool includeException) { if (content.IsNullOrWhitespace()) return; @@ -43,11 +43,13 @@ public static async Task SendFeedback(IPluginManifest plugin, bool isTesting, st { model.Exception = Troubleshooting.LastException == null ? "Was included, but none happened" : Troubleshooting.LastException?.ToString(); } - + var httpClient = Service.Get().SharedHttpClient; + var feedbackUrl = !isCustomRepo ? BugBaitUrl : plugin.FeedbackWebhook ?? BugBaitUrl; + var postContent = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json"); - var response = await httpClient.PostAsync(BugBaitUrl, postContent); + var response = await httpClient.PostAsync(feedbackUrl, postContent); response.EnsureSuccessStatusCode(); }