Add screenshot support for webcompat reports
This commit is contained in:
@@ -57,7 +57,6 @@ class WebcompatReporterDialogDelegate : public ui::WebDialogDelegate {
|
||||
void OnDialogClosed(const std::string& json_retval) override;
|
||||
void OnCloseContents(WebContents* source, bool* out_close_dialog) override;
|
||||
bool ShouldShowDialogTitle() const override;
|
||||
|
||||
private:
|
||||
base::Value::Dict params_;
|
||||
};
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
|
||||
#include "base/metrics/histogram_macros.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/task/thread_pool.h"
|
||||
#include "brave/browser/brave_browser_process.h"
|
||||
#include "brave/browser/ui/brave_shields_data_controller.h"
|
||||
#include "brave/browser/ui/webui/brave_webui_source.h"
|
||||
#include "brave/browser/ui/webui/webcompat_reporter/webcompat_reporter_dialog.h"
|
||||
#include "brave/components/brave_shields/content/browser/ad_block_service.h"
|
||||
@@ -20,18 +21,19 @@
|
||||
#include "brave/components/brave_shields/core/browser/filter_list_catalog_entry.h"
|
||||
#include "brave/components/brave_shields/core/common/pref_names.h"
|
||||
#include "brave/components/brave_vpn/common/buildflags/buildflags.h"
|
||||
#include "brave/components/constants/webui_url_constants.h"
|
||||
#include "brave/components/webcompat_reporter/browser/fields.h"
|
||||
#include "brave/components/webcompat_reporter/browser/webcompat_report_uploader.h"
|
||||
#include "brave/components/webcompat_reporter/resources/grit/webcompat_reporter_generated_map.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ui/browser.h"
|
||||
#include "chrome/browser/ui/browser_finder.h"
|
||||
#include "components/grit/brave_components_resources.h"
|
||||
#include "components/language/core/browser/pref_names.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "content/public/browser/render_widget_host_view.h"
|
||||
#include "content/public/browser/web_ui_data_source.h"
|
||||
#include "content/public/browser/web_ui_message_handler.h"
|
||||
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
||||
#include "ui/web_dialogs/web_dialog_delegate.h"
|
||||
#include "ui/gfx/codec/png_codec.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
#if BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
@@ -43,34 +45,28 @@ namespace webcompat_reporter {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char kUISourceHistogramName[] = "Brave.Webcompat.UISource";
|
||||
constexpr char kUISourceHistogramName[] = "Brave.Webcompat.UISource";
|
||||
constexpr int kMaxScreenshotPixelCount = 1280 * 720;
|
||||
|
||||
class WebcompatReporterDOMHandler : public content::WebUIMessageHandler {
|
||||
public:
|
||||
explicit WebcompatReporterDOMHandler(Profile* profile);
|
||||
WebcompatReporterDOMHandler(const WebcompatReporterDOMHandler&) = delete;
|
||||
WebcompatReporterDOMHandler& operator=(const WebcompatReporterDOMHandler&) =
|
||||
delete;
|
||||
~WebcompatReporterDOMHandler() override;
|
||||
|
||||
// WebUIMessageHandler implementation.
|
||||
void RegisterMessages() override;
|
||||
|
||||
private:
|
||||
void InitAdditionalParameters(Profile* profile);
|
||||
void HandleSubmitReport(const base::Value::List& args);
|
||||
|
||||
std::unique_ptr<webcompat_reporter::WebcompatReportUploader> uploader_;
|
||||
std::string ad_block_list_names_;
|
||||
std::string languages_;
|
||||
bool language_farbling_enabled_ = true;
|
||||
bool brave_vpn_connected_ = false;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
WebcompatReporterDOMHandler::WebcompatReporterDOMHandler(Profile* profile)
|
||||
: uploader_(std::make_unique<webcompat_reporter::WebcompatReportUploader>(
|
||||
: ui_task_runner_(base::SequencedTaskRunner::GetCurrentDefault()),
|
||||
uploader_(std::make_unique<webcompat_reporter::WebcompatReportUploader>(
|
||||
profile->GetURLLoaderFactory())) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
InitAdditionalParameters(profile);
|
||||
|
||||
auto* browser = chrome::FindLastActiveWithProfile(profile);
|
||||
if (!browser) {
|
||||
return;
|
||||
}
|
||||
auto* web_contents = browser->tab_strip_model()->GetActiveWebContents();
|
||||
if (!web_contents) {
|
||||
return;
|
||||
}
|
||||
render_widget_host_view_ = web_contents->GetTopLevelRenderWidgetHostView();
|
||||
}
|
||||
|
||||
void WebcompatReporterDOMHandler::InitAdditionalParameters(Profile* profile) {
|
||||
@@ -91,19 +87,21 @@ void WebcompatReporterDOMHandler::InitAdditionalParameters(Profile* profile) {
|
||||
}
|
||||
}
|
||||
|
||||
ad_block_list_names_ = base::JoinString(ad_block_list_names, ",");
|
||||
pending_report_.ad_block_list_names =
|
||||
base::JoinString(ad_block_list_names, ",");
|
||||
|
||||
#if BUILDFLAG(ENABLE_BRAVE_VPN)
|
||||
brave_vpn::BraveVpnService* vpn_service =
|
||||
brave_vpn::BraveVpnServiceFactory::GetForProfile(profile);
|
||||
if (vpn_service != nullptr) {
|
||||
brave_vpn_connected_ = vpn_service->IsConnected();
|
||||
pending_report_.brave_vpn_connected = vpn_service->IsConnected();
|
||||
}
|
||||
#endif
|
||||
|
||||
PrefService* profile_prefs = profile->GetPrefs();
|
||||
languages_ = profile_prefs->GetString(language::prefs::kAcceptLanguages);
|
||||
language_farbling_enabled_ =
|
||||
pending_report_.languages =
|
||||
profile_prefs->GetString(language::prefs::kAcceptLanguages);
|
||||
pending_report_.language_farbling =
|
||||
profile_prefs->GetBoolean(brave_shields::prefs::kReduceLanguageEnabled);
|
||||
}
|
||||
|
||||
@@ -116,6 +114,58 @@ void WebcompatReporterDOMHandler::RegisterMessages() {
|
||||
base::Unretained(this)));
|
||||
}
|
||||
|
||||
void WebcompatReporterDOMHandler::CaptureScreenshot() {
|
||||
CHECK(render_widget_host_view_);
|
||||
|
||||
auto output_size = render_widget_host_view_->GetVisibleViewportSize();
|
||||
auto original_area = output_size.GetArea();
|
||||
|
||||
if (original_area > kMaxScreenshotPixelCount) {
|
||||
// Scale image down if it's too big
|
||||
float output_scale =
|
||||
std::sqrt(static_cast<float>(kMaxScreenshotPixelCount) / original_area);
|
||||
output_size = gfx::ScaleToRoundedSize(output_size, output_scale);
|
||||
}
|
||||
|
||||
render_widget_host_view_->CopyFromSurface(
|
||||
{}, output_size,
|
||||
base::BindOnce(
|
||||
[](base::WeakPtr<WebcompatReporterDOMHandler> handler,
|
||||
scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
|
||||
const SkBitmap& bitmap) {
|
||||
ui_task_runner->PostTask(
|
||||
FROM_HERE, base::BindOnce(&WebcompatReporterDOMHandler::
|
||||
HandleCapturedScreenshotBitmap,
|
||||
handler, bitmap));
|
||||
},
|
||||
weak_ptr_factory_.GetWeakPtr(), ui_task_runner_));
|
||||
}
|
||||
|
||||
void WebcompatReporterDOMHandler::HandleCapturedScreenshotBitmap(
|
||||
SkBitmap bitmap) {
|
||||
if (bitmap.drawsNothing()) {
|
||||
uploader_->SubmitReport(pending_report_);
|
||||
}
|
||||
base::ThreadPool::PostTaskAndReplyWithResult(
|
||||
FROM_HERE,
|
||||
base::BindOnce(
|
||||
[](SkBitmap bitmap) {
|
||||
std::vector<unsigned char> png_output;
|
||||
return gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &png_output)
|
||||
? std::optional(png_output)
|
||||
: std::nullopt;
|
||||
},
|
||||
bitmap),
|
||||
base::BindOnce(&WebcompatReporterDOMHandler::HandleEncodedScreenshotPNG,
|
||||
weak_ptr_factory_.GetWeakPtr()));
|
||||
}
|
||||
|
||||
void WebcompatReporterDOMHandler::HandleEncodedScreenshotPNG(
|
||||
std::optional<std::vector<unsigned char>> encoded_png) {
|
||||
pending_report_.screenshot_png = encoded_png;
|
||||
uploader_->SubmitReport(pending_report_);
|
||||
}
|
||||
|
||||
void WebcompatReporterDOMHandler::HandleSubmitReport(
|
||||
const base::Value::List& args) {
|
||||
DCHECK_EQ(args.size(), 1U);
|
||||
@@ -125,6 +175,8 @@ void WebcompatReporterDOMHandler::HandleSubmitReport(
|
||||
|
||||
const base::Value::Dict& submission_args = args[0].GetDict();
|
||||
|
||||
const auto attach_screenshot =
|
||||
submission_args.FindBool(kAttachScreenshotField);
|
||||
const std::string* url_arg = submission_args.FindString(kSiteURLField);
|
||||
const std::string* ad_block_setting_arg =
|
||||
submission_args.FindString(kAdBlockSettingField);
|
||||
@@ -132,44 +184,39 @@ void WebcompatReporterDOMHandler::HandleSubmitReport(
|
||||
submission_args.FindString(kFPBlockSettingField);
|
||||
const base::Value* details_arg = submission_args.Find(kDetailsField);
|
||||
const base::Value* contact_arg = submission_args.Find(kContactField);
|
||||
bool shields_enabled =
|
||||
pending_report_.shields_enabled =
|
||||
submission_args.FindBool(kShieldsEnabledField).value_or(false);
|
||||
|
||||
auto ui_source_int = submission_args.FindInt(kUISourceField);
|
||||
const auto ui_source_int = submission_args.FindInt(kUISourceField);
|
||||
if (ui_source_int) {
|
||||
UISource ui_source = static_cast<UISource>(*ui_source_int);
|
||||
UMA_HISTOGRAM_ENUMERATION(kUISourceHistogramName, ui_source);
|
||||
}
|
||||
|
||||
std::string url;
|
||||
std::string ad_block_setting;
|
||||
std::string fp_block_setting;
|
||||
base::Value details;
|
||||
base::Value contact;
|
||||
|
||||
if (url_arg != nullptr) {
|
||||
url = *url_arg;
|
||||
pending_report_.report_url = GURL(*url_arg);
|
||||
}
|
||||
if (ad_block_setting_arg != nullptr) {
|
||||
ad_block_setting = *ad_block_setting_arg;
|
||||
pending_report_.ad_block_setting = *ad_block_setting_arg;
|
||||
}
|
||||
if (fp_block_setting_arg != nullptr) {
|
||||
fp_block_setting = *fp_block_setting_arg;
|
||||
pending_report_.fp_block_setting = *fp_block_setting_arg;
|
||||
}
|
||||
if (details_arg != nullptr) {
|
||||
details = details_arg->Clone();
|
||||
pending_report_.details = details_arg->Clone();
|
||||
}
|
||||
if (contact_arg != nullptr) {
|
||||
contact = contact_arg->Clone();
|
||||
pending_report_.contact = contact_arg->Clone();
|
||||
}
|
||||
|
||||
uploader_->SubmitReport(GURL(url), shields_enabled, ad_block_setting,
|
||||
fp_block_setting, ad_block_list_names_, languages_,
|
||||
language_farbling_enabled_, brave_vpn_connected_,
|
||||
details, contact);
|
||||
}
|
||||
if (attach_screenshot && *attach_screenshot && render_widget_host_view_) {
|
||||
CaptureScreenshot();
|
||||
// Screenshot callbacks will handle upload.
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
uploader_->SubmitReport(pending_report_);
|
||||
}
|
||||
|
||||
WebcompatReporterUI::WebcompatReporterUI(content::WebUI* web_ui,
|
||||
const std::string& name)
|
||||
|
||||
@@ -6,16 +6,54 @@
|
||||
#ifndef BRAVE_BROWSER_UI_WEBUI_WEBCOMPAT_REPORTER_WEBCOMPAT_REPORTER_UI_H_
|
||||
#define BRAVE_BROWSER_UI_WEBUI_WEBCOMPAT_REPORTER_WEBCOMPAT_REPORTER_UI_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "brave/components/webcompat_reporter/browser/webcompat_report_uploader.h"
|
||||
#include "chrome/browser/profiles/profile.h"
|
||||
#include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
|
||||
#include "content/public/browser/web_ui_message_handler.h"
|
||||
|
||||
namespace content {
|
||||
class RenderWidgetHostView;
|
||||
class WebUI;
|
||||
}
|
||||
|
||||
namespace webcompat_reporter {
|
||||
|
||||
class WebcompatReporterDOMHandler : public content::WebUIMessageHandler {
|
||||
public:
|
||||
explicit WebcompatReporterDOMHandler(Profile* profile);
|
||||
WebcompatReporterDOMHandler(const WebcompatReporterDOMHandler&) = delete;
|
||||
WebcompatReporterDOMHandler& operator=(const WebcompatReporterDOMHandler&) =
|
||||
delete;
|
||||
~WebcompatReporterDOMHandler() override;
|
||||
|
||||
// WebUIMessageHandler implementation.
|
||||
void RegisterMessages() override;
|
||||
|
||||
private:
|
||||
void InitAdditionalParameters(Profile* profile);
|
||||
|
||||
void CaptureScreenshot();
|
||||
void HandleCapturedScreenshotBitmap(SkBitmap bitmap);
|
||||
void HandleEncodedScreenshotPNG(
|
||||
std::optional<std::vector<unsigned char>> encoded_png);
|
||||
|
||||
void HandleSubmitReport(const base::Value::List& args);
|
||||
|
||||
raw_ptr<content::RenderWidgetHostView> render_widget_host_view_;
|
||||
scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
|
||||
std::unique_ptr<webcompat_reporter::WebcompatReportUploader> uploader_;
|
||||
|
||||
Report pending_report_;
|
||||
|
||||
base::WeakPtrFactory<WebcompatReporterDOMHandler> weak_ptr_factory_{this};
|
||||
};
|
||||
|
||||
class WebcompatReporterUI : public ConstrainedWebDialogUI {
|
||||
public:
|
||||
WebcompatReporterUI(content::WebUI* web_ui, const std::string& host);
|
||||
|
||||
@@ -437,6 +437,7 @@
|
||||
<message name="IDS_BRAVE_WEBCOMPATREPORTER_REPORT_DETAILS" desc="Placeholder text for the optional details field in the broken website report">Additional details (optional)</message>
|
||||
<message name="IDS_BRAVE_WEBCOMPATREPORTER_REPORT_CONTACT_LABEL" desc="Label for the optional contact information field in the broken website report">Contact me at: (optional)</message>
|
||||
<message name="IDS_BRAVE_WEBCOMPATREPORTER_REPORT_CONTACT_PLACEHOLDER" desc="Placeholder text for the optional contact information field in the broken website report">Email, Twitter, etc.</message>
|
||||
<message name="IDS_BRAVE_WEBCOMPATREPORTER_ATTACH_SCREENSHOT_LABEL" desc="Label for the checkbox for attaching a screenshot with the broken website report">Include screenshot of the current page</message>
|
||||
<message name="IDS_BRAVE_WEBCOMPATREPORTER_CANCEL" desc="Text for button to cancel sending a broken website report">Cancel</message>
|
||||
<message name="IDS_BRAVE_WEBCOMPATREPORTER_SUBMIT" desc="Text for button to submit a broken website report">Submit</message>
|
||||
<message name="IDS_BRAVE_WEBCOMPATREPORTER_THANK_YOU" desc="Thanks the user for submitting a report of a broken website">Thank you!</message>
|
||||
|
||||
@@ -17,6 +17,7 @@ inline constexpr char kShieldsEnabledField[] = "shieldsEnabled";
|
||||
inline constexpr char kLanguagesField[] = "languages";
|
||||
inline constexpr char kLanguageFarblingField[] = "languageFarblingEnabled";
|
||||
inline constexpr char kBraveVPNEnabledField[] = "braveVPNEnabled";
|
||||
inline constexpr char kAttachScreenshotField[] = "attachScreenshot";
|
||||
|
||||
inline constexpr char kSiteURLField[] = "url";
|
||||
inline constexpr char kDomainField[] = "domain";
|
||||
|
||||
@@ -9,16 +9,13 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/environment.h"
|
||||
#include "base/json/json_writer.h"
|
||||
#include "brave/components/brave_referrals/browser/brave_referrals_service.h"
|
||||
#include "brave/components/brave_stats/browser/brave_stats_updater_util.h"
|
||||
#include "brave/components/webcompat_reporter/browser/fields.h"
|
||||
#include "brave/components/webcompat_reporter/buildflags/buildflags.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "net/base/load_flags.h"
|
||||
#include "net/base/privacy_mode.h"
|
||||
#include "net/base/mime_util.h"
|
||||
#include "services/network/public/cpp/resource_request.h"
|
||||
#include "services/network/public/cpp/shared_url_loader_factory.h"
|
||||
#include "services/network/public/cpp/simple_url_loader.h"
|
||||
@@ -28,57 +25,86 @@
|
||||
|
||||
namespace webcompat_reporter {
|
||||
|
||||
namespace {
|
||||
constexpr char kJsonContentType[] = "application/json";
|
||||
constexpr char kPngContentType[] = "image/png";
|
||||
constexpr char kMultipartContentTypePrefix[] = "multipart/form-data; boundary=";
|
||||
|
||||
constexpr char kReportDetailsMultipartName[] = "report-details";
|
||||
constexpr char kScreenshotMultipartName[] = "screenshot";
|
||||
constexpr char kScreenshotMultipartFilename[] = "screenshot.png";
|
||||
} // namespace
|
||||
|
||||
Report::Report() = default;
|
||||
Report::~Report() = default;
|
||||
|
||||
WebcompatReportUploader::WebcompatReportUploader(
|
||||
scoped_refptr<network::SharedURLLoaderFactory> factory)
|
||||
: shared_url_loader_factory_(std::move(factory)) {}
|
||||
|
||||
WebcompatReportUploader::~WebcompatReportUploader() = default;
|
||||
|
||||
void WebcompatReportUploader::SubmitReport(
|
||||
const GURL& report_url,
|
||||
const bool shields_enabled,
|
||||
const std::string& ad_block_setting,
|
||||
const std::string& fp_block_setting,
|
||||
const std::string& ad_block_list_names,
|
||||
const std::string& languages,
|
||||
const bool language_farbling,
|
||||
const bool brave_vpn_connected,
|
||||
const base::Value& details,
|
||||
const base::Value& contact) {
|
||||
void WebcompatReportUploader::SubmitReport(const Report& report) {
|
||||
std::string api_key = brave_stats::GetAPIKey();
|
||||
|
||||
const GURL upload_url(BUILDFLAG(WEBCOMPAT_REPORT_ENDPOINT));
|
||||
|
||||
url::Origin report_url_origin = url::Origin::Create(report_url);
|
||||
url::Origin report_url_origin = url::Origin::Create(report.report_url);
|
||||
|
||||
base::Value::Dict post_data_obj;
|
||||
post_data_obj.Set(kSiteURLField, report_url.spec());
|
||||
post_data_obj.Set(kDomainField, report_url_origin.Serialize());
|
||||
post_data_obj.Set(kDetailsField, details.Clone());
|
||||
post_data_obj.Set(kContactField, contact.Clone());
|
||||
base::Value::Dict report_details_dict;
|
||||
report_details_dict.Set(kSiteURLField, report.report_url.spec());
|
||||
report_details_dict.Set(kDomainField, report_url_origin.Serialize());
|
||||
report_details_dict.Set(kDetailsField, report.details.Clone());
|
||||
report_details_dict.Set(kContactField, report.contact.Clone());
|
||||
|
||||
post_data_obj.Set(kShieldsEnabledField, shields_enabled);
|
||||
post_data_obj.Set(kAdBlockSettingField, ad_block_setting);
|
||||
post_data_obj.Set(kFPBlockSettingField, fp_block_setting);
|
||||
post_data_obj.Set(kAdBlockListsField, ad_block_list_names);
|
||||
post_data_obj.Set(kLanguagesField, languages);
|
||||
post_data_obj.Set(kLanguageFarblingField, language_farbling);
|
||||
post_data_obj.Set(kBraveVPNEnabledField, brave_vpn_connected);
|
||||
report_details_dict.Set(kShieldsEnabledField, report.shields_enabled);
|
||||
report_details_dict.Set(kAdBlockSettingField, report.ad_block_setting);
|
||||
report_details_dict.Set(kFPBlockSettingField, report.fp_block_setting);
|
||||
report_details_dict.Set(kAdBlockListsField, report.ad_block_list_names);
|
||||
report_details_dict.Set(kLanguagesField, report.languages);
|
||||
report_details_dict.Set(kLanguageFarblingField, report.language_farbling);
|
||||
report_details_dict.Set(kBraveVPNEnabledField, report.brave_vpn_connected);
|
||||
|
||||
post_data_obj.Set(kApiKeyField, base::Value(api_key));
|
||||
report_details_dict.Set(kApiKeyField, base::Value(api_key));
|
||||
|
||||
std::string post_data;
|
||||
base::JSONWriter::Write(post_data_obj, &post_data);
|
||||
std::string report_details_json;
|
||||
base::JSONWriter::Write(report_details_dict, &report_details_json);
|
||||
|
||||
WebcompatReportUploader::CreateAndStartURLLoader(upload_url, post_data);
|
||||
if (report.screenshot_png && !report.screenshot_png->empty()) {
|
||||
std::string multipart_boundary = net::GenerateMimeMultipartBoundary();
|
||||
std::string content_type = kMultipartContentTypePrefix + multipart_boundary;
|
||||
std::string multipart_data;
|
||||
|
||||
net::AddMultipartValueForUpload(kReportDetailsMultipartName,
|
||||
report_details_json, multipart_boundary,
|
||||
kJsonContentType, &multipart_data);
|
||||
|
||||
std::string screenshot_png_str;
|
||||
screenshot_png_str = std::string(report.screenshot_png->begin(),
|
||||
report.screenshot_png->end());
|
||||
net::AddMultipartValueForUploadWithFileName(
|
||||
kScreenshotMultipartName, kScreenshotMultipartFilename,
|
||||
screenshot_png_str, multipart_boundary, kPngContentType,
|
||||
&multipart_data);
|
||||
|
||||
net::AddMultipartFinalDelimiterForUpload(multipart_boundary,
|
||||
&multipart_data);
|
||||
|
||||
WebcompatReportUploader::CreateAndStartURLLoader(upload_url, content_type,
|
||||
multipart_data);
|
||||
return;
|
||||
}
|
||||
|
||||
WebcompatReportUploader::CreateAndStartURLLoader(upload_url, kJsonContentType,
|
||||
report_details_json);
|
||||
}
|
||||
|
||||
void WebcompatReportUploader::CreateAndStartURLLoader(
|
||||
const GURL& upload_url,
|
||||
const std::string& content_type,
|
||||
const std::string& post_data) {
|
||||
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
||||
|
||||
std::string content_type = "application/json";
|
||||
auto resource_request = std::make_unique<network::ResourceRequest>();
|
||||
// upload_url only includes the origin and path, and not the fragment or
|
||||
// query. The fragment and query are removed from the URL in
|
||||
@@ -100,8 +126,8 @@ void WebcompatReportUploader::CreateAndStartURLLoader(
|
||||
"Though the 'Report a Broken Site' option of the help menu or"
|
||||
"the Brave Shields panel."
|
||||
data: "Broken URL, IP address, Shields settings, language settings,"
|
||||
"Brave VPN connection status; user provided additional details"
|
||||
"and contact information."
|
||||
"Brave VPN connection status, user-provided additional details,"
|
||||
"optional screenshot and contact information."
|
||||
destination: OTHER
|
||||
destination_other: "Brave developers"
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/values.h"
|
||||
@@ -21,6 +22,24 @@ class SimpleURLLoader;
|
||||
|
||||
namespace webcompat_reporter {
|
||||
|
||||
struct Report {
|
||||
Report();
|
||||
~Report();
|
||||
|
||||
GURL report_url;
|
||||
bool shields_enabled;
|
||||
std::string ad_block_setting;
|
||||
std::string fp_block_setting;
|
||||
std::string ad_block_list_names;
|
||||
std::string languages;
|
||||
bool language_farbling;
|
||||
bool brave_vpn_connected;
|
||||
base::Value details;
|
||||
base::Value contact;
|
||||
|
||||
std::optional<std::vector<unsigned char>> screenshot_png;
|
||||
};
|
||||
|
||||
class WebcompatReportUploader {
|
||||
public:
|
||||
explicit WebcompatReportUploader(
|
||||
@@ -29,21 +48,13 @@ class WebcompatReportUploader {
|
||||
WebcompatReportUploader& operator=(const WebcompatReportUploader&) = delete;
|
||||
~WebcompatReportUploader();
|
||||
|
||||
void SubmitReport(const GURL& report_url,
|
||||
const bool shields_enabled,
|
||||
const std::string& ad_block_setting,
|
||||
const std::string& fp_block_setting,
|
||||
const std::string& ad_block_list_names,
|
||||
const std::string& languages,
|
||||
const bool language_farbling,
|
||||
const bool brave_vpn_connected,
|
||||
const base::Value& details,
|
||||
const base::Value& contact);
|
||||
void SubmitReport(const Report& report);
|
||||
|
||||
private:
|
||||
std::unique_ptr<network::SimpleURLLoader> simple_url_loader_;
|
||||
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
|
||||
void CreateAndStartURLLoader(const GURL& upload_url,
|
||||
const std::string& content_type,
|
||||
const std::string& post_data);
|
||||
void OnSimpleURLLoaderComplete(std::unique_ptr<std::string> response_body);
|
||||
};
|
||||
|
||||
@@ -14,10 +14,11 @@ export const setDialogArgs = (dialogArgs: WebcompatReporter.DialogArgs) => {
|
||||
})
|
||||
}
|
||||
|
||||
export const onSubmitReport = (details: string, contact: string) =>
|
||||
export const onSubmitReport = (details: string, contact: string, attachScreenshot: boolean) =>
|
||||
action(types.WEBCOMPATREPORTER_ON_SUBMIT_REPORT, {
|
||||
details,
|
||||
contact
|
||||
contact,
|
||||
attachScreenshot
|
||||
})
|
||||
|
||||
export const onClose = () =>
|
||||
|
||||
@@ -16,6 +16,8 @@ import {
|
||||
SideBySideButtons,
|
||||
PaddedButton,
|
||||
Input,
|
||||
Checkbox,
|
||||
CheckboxLabel,
|
||||
TextArea,
|
||||
FieldCtr,
|
||||
InputLabel
|
||||
@@ -26,19 +28,20 @@ import { getLocale } from '../../../common/locale'
|
||||
|
||||
interface Props {
|
||||
siteUrl: string
|
||||
onSubmitReport: (details: string, contact: string) => void
|
||||
onSubmitReport: (details: string, contact: string, attachScreenshot: boolean) => void
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
interface State {
|
||||
details: string
|
||||
contact: string
|
||||
attachScreenshot: boolean
|
||||
}
|
||||
|
||||
export default class ReportView extends React.PureComponent<Props, State> {
|
||||
constructor (props: Props) {
|
||||
super(props)
|
||||
this.state = { details: '', contact: '' }
|
||||
this.state = { details: '', contact: '', attachScreenshot: true }
|
||||
}
|
||||
|
||||
render () {
|
||||
@@ -47,7 +50,7 @@ export default class ReportView extends React.PureComponent<Props, State> {
|
||||
onSubmitReport,
|
||||
onClose
|
||||
} = this.props
|
||||
const { details, contact } = this.state
|
||||
const { details, contact, attachScreenshot } = this.state
|
||||
return (
|
||||
<ModalLayout>
|
||||
<TextSection>
|
||||
@@ -78,6 +81,17 @@ export default class ReportView extends React.PureComponent<Props, State> {
|
||||
id='contact-info'
|
||||
/>
|
||||
</FieldCtr>
|
||||
<FieldCtr>
|
||||
<Checkbox
|
||||
onChange={(ev) => this.setState({ attachScreenshot: ev.target.checked })}
|
||||
type='checkbox'
|
||||
checked={attachScreenshot}
|
||||
id='attach-screenshot'
|
||||
/>
|
||||
<CheckboxLabel htmlFor='attach-screenshot'>
|
||||
{getLocale('attachScreenshotLabel')}
|
||||
</CheckboxLabel>
|
||||
</FieldCtr>
|
||||
<SideBySideButtons>
|
||||
<PaddedButton
|
||||
text={getLocale('cancel')}
|
||||
@@ -91,7 +105,7 @@ export default class ReportView extends React.PureComponent<Props, State> {
|
||||
level={'primary'}
|
||||
type={'accent'}
|
||||
size={'small'}
|
||||
onClick={() => onSubmitReport(details, contact)}
|
||||
onClick={() => onSubmitReport(details, contact, attachScreenshot)}
|
||||
/>
|
||||
</SideBySideButtons>
|
||||
</ModalLayout>
|
||||
|
||||
@@ -30,17 +30,19 @@ export default class WebcompatReportModal extends React.PureComponent<Props, {}>
|
||||
onClose
|
||||
} = this.props
|
||||
return (
|
||||
<RectangularCard>
|
||||
{submitted ? (
|
||||
<ConfirmationView/>
|
||||
) : (
|
||||
<ReportView
|
||||
siteUrl={siteUrl}
|
||||
onSubmitReport={onSubmitReport}
|
||||
onClose={onClose}
|
||||
/>
|
||||
)}
|
||||
</RectangularCard>
|
||||
<div onContextMenu={(e: React.MouseEvent<HTMLDivElement>) => e.preventDefault()}>
|
||||
<RectangularCard>
|
||||
{submitted ? (
|
||||
<ConfirmationView/>
|
||||
) : (
|
||||
<ReportView
|
||||
siteUrl={siteUrl}
|
||||
onSubmitReport={onSubmitReport}
|
||||
onClose={onClose}
|
||||
/>
|
||||
)}
|
||||
</RectangularCard>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ export const SuccessIcon = styled(CheckCircleIcon)`
|
||||
|
||||
export const RectangularCard = styled(Card)<CardProps>`
|
||||
border-radius: 0;
|
||||
user-select: none;
|
||||
`
|
||||
|
||||
export const Input = styled.input`
|
||||
@@ -83,6 +84,12 @@ export const Input = styled.input`
|
||||
}
|
||||
`
|
||||
|
||||
export const Checkbox = styled(Input)`
|
||||
width: unset;
|
||||
margin-right: 6px;
|
||||
vertical-align: middle;
|
||||
`
|
||||
|
||||
export const InputLabel = styled.label`
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
@@ -92,6 +99,10 @@ export const InputLabel = styled.label`
|
||||
padding-bottom: 4px;
|
||||
`
|
||||
|
||||
export const CheckboxLabel = styled(InputLabel)`
|
||||
display: unset;
|
||||
`
|
||||
|
||||
export const TextArea = styled.textarea`
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
||||
@@ -20,6 +20,8 @@ export {
|
||||
NonInteractiveURL,
|
||||
SuccessIcon,
|
||||
Input,
|
||||
Checkbox,
|
||||
CheckboxLabel,
|
||||
TextArea,
|
||||
InputLabel
|
||||
} from './display'
|
||||
|
||||
@@ -25,7 +25,8 @@ const webcompatReporterReducer: Reducer<WebcompatReporter.State | undefined> = (
|
||||
{
|
||||
...state.dialogArgs,
|
||||
additionalDetails: action.payload.details || null,
|
||||
contactInfo: action.payload.contact || null
|
||||
contactInfo: action.payload.contact || null,
|
||||
attachScreenshot: action.payload.attachScreenshot || false
|
||||
}
|
||||
])
|
||||
state = {
|
||||
|
||||
@@ -1050,6 +1050,8 @@ base::span<const webui::LocalizedString> GetWebUILocalizedStrings(
|
||||
IDS_BRAVE_WEBCOMPATREPORTER_REPORT_CONTACT_PLACEHOLDER},
|
||||
{"reportContactLabel",
|
||||
IDS_BRAVE_WEBCOMPATREPORTER_REPORT_CONTACT_LABEL},
|
||||
{"attachScreenshotLabel",
|
||||
IDS_BRAVE_WEBCOMPATREPORTER_ATTACH_SCREENSHOT_LABEL},
|
||||
{"cancel", IDS_BRAVE_WEBCOMPATREPORTER_CANCEL},
|
||||
{"submit", IDS_BRAVE_WEBCOMPATREPORTER_SUBMIT},
|
||||
// Confirmation modal
|
||||
|
||||
Reference in New Issue
Block a user