Commit 1c92b3fd authored by Anthony Vallee-Dubois's avatar Anthony Vallee-Dubois Committed by Chromium LUCI CQ

Add custom message related fields to content analysis dialog

Bug: 1166369
Change-Id: I32459ec22d8a4a6bd57d8ae0a17a3850a365fc57
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2625914
Commit-Queue: anthonyvd <anthonyvd@chromium.org>
Reviewed-by: default avatarDominique Fauteux-Chapleau <domfc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#843330}
parent 191677c8
...@@ -10954,6 +10954,12 @@ Please help our engineers fix this problem. Tell us what happened right before y ...@@ -10954,6 +10954,12 @@ Please help our engineers fix this problem. Tell us what happened right before y
=1 {This file is encrypted. Ask its owner to decrypt.} =1 {This file is encrypted. Ask its owner to decrypt.}
other {Some of these files are encrypted. Ask their owner to decrypt.}} other {Some of these files are encrypted. Ask their owner to decrypt.}}
</message> </message>
<message name="IDS_DEEP_SCANNING_DIALOG_CUSTOM_MESSAGE" desc="Message shown around the custom message provided by the administrator when deep scanning returns a failure.">
Your administrator says "<ph name="CUSTOM_MESSAGE">$1<ex>Please don't upload this type of data.</ex></ph>".
</message>
<message name="IDS_DEEP_SCANNING_DIALOG_CUSTOM_MESSAGE_LEARN_MORE_LINK" desc="Text value of the link passed for the custom message set by the administrator when deep scanning returns a failure.">
Learn more
</message>
<!-- Deep scanning open now dialog strings --> <!-- Deep scanning open now dialog strings -->
......
1d4a27fcac3fdb3ebd93f07c16e91791422d0da2
\ No newline at end of file
1d4a27fcac3fdb3ebd93f07c16e91791422d0da2
\ No newline at end of file
...@@ -61,6 +61,23 @@ AnalysisServiceSettings::AnalysisServiceSettings( ...@@ -61,6 +61,23 @@ AnalysisServiceSettings::AnalysisServiceSettings(
settings_value.FindBoolKey(kKeyBlockUnsupportedFileTypes).value_or(false); settings_value.FindBoolKey(kKeyBlockUnsupportedFileTypes).value_or(false);
minimum_data_size_ = minimum_data_size_ =
settings_value.FindIntKey(kKeyMinimumDataSize).value_or(100); settings_value.FindIntKey(kKeyMinimumDataSize).value_or(100);
const base::Value* custom_messages =
settings_value.FindListKey(kKeyCustomMessages);
if (custom_messages && custom_messages->is_list() &&
!custom_messages->GetList().empty()) {
// As of now, this list can only contain one value. At some point, it
// might be necessary to iterate further in order to find the most
// appropriate message, for instance by considering the message and
// browser's locales or other signals.
const base::Value& value = custom_messages->GetList()[0];
const std::string* message = value.FindStringKey(kKeyCustomMessagesMessage);
custom_message_text_ = message ? *message : "";
const std::string* url =
value.FindStringKey(kKeyCustomMessagesLearnMoreUrl);
custom_message_learn_more_url_ = url ? GURL(*url) : GURL();
}
} }
// static // static
...@@ -108,6 +125,8 @@ base::Optional<AnalysisSettings> AnalysisServiceSettings::GetAnalysisSettings( ...@@ -108,6 +125,8 @@ base::Optional<AnalysisSettings> AnalysisServiceSettings::GetAnalysisSettings(
settings.analysis_url = GURL(service_provider_->analysis_url()); settings.analysis_url = GURL(service_provider_->analysis_url());
DCHECK(settings.analysis_url.is_valid()); DCHECK(settings.analysis_url.is_valid());
settings.minimum_data_size = minimum_data_size_; settings.minimum_data_size = minimum_data_size_;
settings.custom_message_text = custom_message_text_;
settings.custom_message_learn_more_url = custom_message_learn_more_url_;
return settings; return settings;
} }
......
...@@ -95,6 +95,8 @@ class AnalysisServiceSettings { ...@@ -95,6 +95,8 @@ class AnalysisServiceSettings {
bool block_large_files_ = false; bool block_large_files_ = false;
bool block_unsupported_file_types_ = false; bool block_unsupported_file_types_ = false;
size_t minimum_data_size_ = 100; size_t minimum_data_size_ = 100;
std::string custom_message_text_;
GURL custom_message_learn_more_url_;
}; };
} // namespace enterprise_connectors } // namespace enterprise_connectors
......
...@@ -29,6 +29,9 @@ constexpr char kKeyBlockLargeFiles[] = "block_large_files"; ...@@ -29,6 +29,9 @@ constexpr char kKeyBlockLargeFiles[] = "block_large_files";
constexpr char kKeyBlockUnsupportedFileTypes[] = "block_unsupported_file_types"; constexpr char kKeyBlockUnsupportedFileTypes[] = "block_unsupported_file_types";
constexpr char kKeyMinimumDataSize[] = "minimum_data_size"; constexpr char kKeyMinimumDataSize[] = "minimum_data_size";
constexpr char kKeyEnabledEventNames[] = "enabled_event_names"; constexpr char kKeyEnabledEventNames[] = "enabled_event_names";
constexpr char kKeyCustomMessages[] = "custom_messages";
constexpr char kKeyCustomMessagesMessage[] = "message";
constexpr char kKeyCustomMessagesLearnMoreUrl[] = "learn_more_url";
enum class ReportingConnector { enum class ReportingConnector {
SECURITY_EVENT, SECURITY_EVENT,
...@@ -56,6 +59,8 @@ struct AnalysisSettings { ...@@ -56,6 +59,8 @@ struct AnalysisSettings {
bool block_password_protected_files = false; bool block_password_protected_files = false;
bool block_large_files = false; bool block_large_files = false;
bool block_unsupported_file_types = false; bool block_unsupported_file_types = false;
std::string custom_message_text;
GURL custom_message_learn_more_url;
// Minimum text size for BulkDataEntry scans. 0 means no minimum. // Minimum text size for BulkDataEntry scans. 0 means no minimum.
size_t minimum_data_size = 100; size_t minimum_data_size = 100;
......
...@@ -294,6 +294,9 @@ void ContentAnalysisDelegate::CreateForWebContents( ...@@ -294,6 +294,9 @@ void ContentAnalysisDelegate::CreateForWebContents(
Factory* testing_factory = GetFactoryStorage(); Factory* testing_factory = GetFactoryStorage();
bool wait_for_verdict = data.settings.block_until_verdict == bool wait_for_verdict = data.settings.block_until_verdict ==
enterprise_connectors::BlockUntilVerdict::BLOCK; enterprise_connectors::BlockUntilVerdict::BLOCK;
std::string custom_message_text = data.settings.custom_message_text;
GURL custom_message_learn_more_url =
data.settings.custom_message_learn_more_url;
// Using new instead of std::make_unique<> to access non public constructor. // Using new instead of std::make_unique<> to access non public constructor.
auto delegate = auto delegate =
...@@ -571,7 +574,8 @@ bool ContentAnalysisDelegate::UpdateDialog() { ...@@ -571,7 +574,8 @@ bool ContentAnalysisDelegate::UpdateDialog() {
if (!dialog_) if (!dialog_)
return false; return false;
dialog_->ShowResult(final_result_); dialog_->ShowResult(final_result_, data_.settings.custom_message_text,
data_.settings.custom_message_learn_more_url);
return true; return true;
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "ui/views/border.h" #include "ui/views/border.h"
#include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/image_view.h" #include "ui/views/controls/image_view.h"
#include "ui/views/controls/link.h"
#include "ui/views/controls/textfield/textfield.h" #include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/throbber.h" #include "ui/views/controls/throbber.h"
#include "ui/views/layout/box_layout.h" #include "ui/views/layout/box_layout.h"
...@@ -212,6 +213,14 @@ void ContentAnalysisDialog::CancelButtonCallback() { ...@@ -212,6 +213,14 @@ void ContentAnalysisDialog::CancelButtonCallback() {
delegate_->Cancel(is_warning()); delegate_->Cancel(is_warning());
} }
void ContentAnalysisDialog::LearnMoreLinkClickedCallback(
const ui::Event& event) {
web_contents_->OpenURL(
content::OpenURLParams(final_learn_more_url_, content::Referrer(),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_LINK, false));
}
void ContentAnalysisDialog::SuccessCallback() { void ContentAnalysisDialog::SuccessCallback() {
#if defined(USE_AURA) #if defined(USE_AURA)
if (web_contents_) { if (web_contents_) {
...@@ -268,6 +277,15 @@ views::View* ContentAnalysisDialog::GetContentsView() { ...@@ -268,6 +277,15 @@ views::View* ContentAnalysisDialog::GetContentsView() {
// Add the side icon. // Add the side icon.
icon_and_message_row->AddChildView(CreateSideIcon()); icon_and_message_row->AddChildView(CreateSideIcon());
auto message_and_link_column = std::make_unique<views::View>();
auto* column_layout = message_and_link_column->SetLayoutManager(
std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
column_layout->set_main_axis_alignment(
views::BoxLayout::MainAxisAlignment::kCenter);
column_layout->set_cross_axis_alignment(
views::BoxLayout::CrossAxisAlignment::kStart);
// Add the message. // Add the message.
auto label = std::make_unique<DeepScanningMessageView>(this); auto label = std::make_unique<DeepScanningMessageView>(this);
label->SetText(GetDialogMessage()); label->SetText(GetDialogMessage());
...@@ -275,8 +293,21 @@ views::View* ContentAnalysisDialog::GetContentsView() { ...@@ -275,8 +293,21 @@ views::View* ContentAnalysisDialog::GetContentsView() {
label->SetMultiLine(true); label->SetMultiLine(true);
label->SetVerticalAlignment(gfx::ALIGN_MIDDLE); label->SetVerticalAlignment(gfx::ALIGN_MIDDLE);
label->SetHorizontalAlignment(gfx::ALIGN_LEFT); label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
message_ = icon_and_message_row->AddChildView(std::move(label)); message_ = message_and_link_column->AddChildView(std::move(label));
// Add the Learn More link but hide it so it can only be displayed when
// required.
auto learn_more_link =
std::make_unique<views::Link>(l10n_util::GetStringUTF16(
IDS_DEEP_SCANNING_DIALOG_CUSTOM_MESSAGE_LEARN_MORE_LINK));
learn_more_link->SetCallback(base::BindRepeating(
&ContentAnalysisDialog::LearnMoreLinkClickedCallback,
base::Unretained(this)));
learn_more_link->SetVisible(false);
learn_more_link_ =
message_and_link_column->AddChildView(std::move(learn_more_link));
icon_and_message_row->AddChildView(std::move(message_and_link_column));
layout->AddView(std::move(icon_and_message_row)); layout->AddView(std::move(icon_and_message_row));
// Add padding to distance the message from the button(s). // Add padding to distance the message from the button(s).
...@@ -306,9 +337,14 @@ void ContentAnalysisDialog::WebContentsDestroyed() { ...@@ -306,9 +337,14 @@ void ContentAnalysisDialog::WebContentsDestroyed() {
} }
void ContentAnalysisDialog::ShowResult( void ContentAnalysisDialog::ShowResult(
ContentAnalysisDelegate::FinalResult result) { ContentAnalysisDelegate::FinalResult result,
const std::string& custom_message,
const GURL& learn_more_url) {
DCHECK(is_pending()); DCHECK(is_pending());
final_result_ = result; final_result_ = result;
final_custom_message_ = custom_message;
final_learn_more_url_ = learn_more_url;
switch (final_result_) { switch (final_result_) {
case ContentAnalysisDelegate::FinalResult::ENCRYPTED_FILES: case ContentAnalysisDelegate::FinalResult::ENCRYPTED_FILES:
case ContentAnalysisDelegate::FinalResult::LARGE_FILES: case ContentAnalysisDelegate::FinalResult::LARGE_FILES:
...@@ -373,6 +409,14 @@ void ContentAnalysisDialog::UpdateDialog() { ...@@ -373,6 +409,14 @@ void ContentAnalysisDialog::UpdateDialog() {
message_->SetText(new_message); message_->SetText(new_message);
message_->GetViewAccessibility().AnnounceText(std::move(new_message)); message_->GetViewAccessibility().AnnounceText(std::move(new_message));
// Update the visibility of the Learn More link, which should only be visible
// if the dialog is in the warning or failure state, and there's a link to
// display.
learn_more_link_->SetVisible(
(dialog_status_ == DeepScanningDialogStatus::FAILURE ||
dialog_status_ == DeepScanningDialogStatus::WARNING) &&
(final_learn_more_url_.is_valid() && !final_learn_more_url_.is_empty()));
// Resize the dialog's height. This is needed since the text might take more // Resize the dialog's height. This is needed since the text might take more
// lines after changing. // lines after changing.
int text_height = message_->GetRequiredLines() * message_->GetLineHeight(); int text_height = message_->GetRequiredLines() * message_->GetLineHeight();
...@@ -432,7 +476,7 @@ void ContentAnalysisDialog::Resize(int height_to_add) { ...@@ -432,7 +476,7 @@ void ContentAnalysisDialog::Resize(int height_to_add) {
bounds_animator_->SetAnimationDuration(kResizeAnimationDuration); bounds_animator_->SetAnimationDuration(kResizeAnimationDuration);
DCHECK(widget->GetRootView()); DCHECK(widget->GetRootView());
DCHECK_EQ(widget->GetRootView()->children().size(), 1u); DCHECK_EQ(widget->GetRootView()->children().size(), 2u);
views::View* view_to_resize = widget->GetRootView()->children()[0]; views::View* view_to_resize = widget->GetRootView()->children()[0];
// Start the animation. // Start the animation.
...@@ -603,6 +647,11 @@ base::string16 ContentAnalysisDialog::GetPendingMessage() const { ...@@ -603,6 +647,11 @@ base::string16 ContentAnalysisDialog::GetPendingMessage() const {
base::string16 ContentAnalysisDialog::GetFailureMessage() const { base::string16 ContentAnalysisDialog::GetFailureMessage() const {
DCHECK(is_failure()); DCHECK(is_failure());
// If the admin has specified a custom message for this failure, it takes
// precedence over the generic ones.
if (has_custom_message())
return GetCustomMessage();
if (final_result_ == ContentAnalysisDelegate::FinalResult::LARGE_FILES) { if (final_result_ == ContentAnalysisDelegate::FinalResult::LARGE_FILES) {
return l10n_util::GetPluralStringFUTF16( return l10n_util::GetPluralStringFUTF16(
IDS_DEEP_SCANNING_DIALOG_LARGE_FILE_FAILURE_MESSAGE, files_count_); IDS_DEEP_SCANNING_DIALOG_LARGE_FILE_FAILURE_MESSAGE, files_count_);
...@@ -619,6 +668,12 @@ base::string16 ContentAnalysisDialog::GetFailureMessage() const { ...@@ -619,6 +668,12 @@ base::string16 ContentAnalysisDialog::GetFailureMessage() const {
base::string16 ContentAnalysisDialog::GetWarningMessage() const { base::string16 ContentAnalysisDialog::GetWarningMessage() const {
DCHECK(is_warning()); DCHECK(is_warning());
// If the admin has specified a custom message for this warning, it takes
// precedence over the generic one.
if (has_custom_message())
return GetCustomMessage();
return l10n_util::GetPluralStringFUTF16( return l10n_util::GetPluralStringFUTF16(
IDS_DEEP_SCANNING_DIALOG_UPLOAD_WARNING_MESSAGE, files_count_); IDS_DEEP_SCANNING_DIALOG_UPLOAD_WARNING_MESSAGE, files_count_);
} }
...@@ -629,6 +684,13 @@ base::string16 ContentAnalysisDialog::GetSuccessMessage() const { ...@@ -629,6 +684,13 @@ base::string16 ContentAnalysisDialog::GetSuccessMessage() const {
IDS_DEEP_SCANNING_DIALOG_SUCCESS_MESSAGE, files_count_); IDS_DEEP_SCANNING_DIALOG_SUCCESS_MESSAGE, files_count_);
} }
base::string16 ContentAnalysisDialog::GetCustomMessage() const {
DCHECK(is_warning() || is_failure());
DCHECK(has_custom_message());
return l10n_util::GetStringFUTF16(IDS_DEEP_SCANNING_DIALOG_CUSTOM_MESSAGE,
base::ASCIIToUTF16(final_custom_message_));
}
const gfx::ImageSkia* ContentAnalysisDialog::GetTopImage() const { const gfx::ImageSkia* ContentAnalysisDialog::GetTopImage() const {
const bool use_dark = color_utils::IsDark(GetBackgroundColor(GetWidget())); const bool use_dark = color_utils::IsDark(GetBackgroundColor(GetWidget()));
const bool treat_as_text_paste = const bool treat_as_text_paste =
......
...@@ -27,6 +27,7 @@ class ImageSkia; ...@@ -27,6 +27,7 @@ class ImageSkia;
namespace views { namespace views {
class ImageView; class ImageView;
class Label; class Label;
class Link;
class Throbber; class Throbber;
class Widget; class Widget;
} // namespace views } // namespace views
...@@ -123,7 +124,9 @@ class ContentAnalysisDialog : public views::DialogDelegate, ...@@ -123,7 +124,9 @@ class ContentAnalysisDialog : public views::DialogDelegate,
// Updates the dialog with the result, and simply delete it from memory if // Updates the dialog with the result, and simply delete it from memory if
// nothing should be shown. // nothing should be shown.
void ShowResult(ContentAnalysisDelegate::FinalResult result); void ShowResult(ContentAnalysisDelegate::FinalResult result,
const std::string& custom_message,
const GURL& learn_more_url);
// Accessors to simplify |dialog_status_| checking. // Accessors to simplify |dialog_status_| checking.
inline bool is_success() const { inline bool is_success() const {
...@@ -144,6 +147,13 @@ class ContentAnalysisDialog : public views::DialogDelegate, ...@@ -144,6 +147,13 @@ class ContentAnalysisDialog : public views::DialogDelegate,
return dialog_status_ == DeepScanningDialogStatus::PENDING; return dialog_status_ == DeepScanningDialogStatus::PENDING;
} }
bool has_custom_message() const { return !final_custom_message_.empty(); }
bool has_learn_more_url() const {
return !final_learn_more_url_.is_empty() &&
final_learn_more_url_.is_valid();
}
// Returns the side image's logo color depending on |dialog_status_|. // Returns the side image's logo color depending on |dialog_status_|.
SkColor GetSideImageLogoColor() const; SkColor GetSideImageLogoColor() const;
...@@ -202,11 +212,14 @@ class ContentAnalysisDialog : public views::DialogDelegate, ...@@ -202,11 +212,14 @@ class ContentAnalysisDialog : public views::DialogDelegate,
// Returns the appropriate success message depending on |files_count_|. // Returns the appropriate success message depending on |files_count_|.
base::string16 GetSuccessMessage() const; base::string16 GetSuccessMessage() const;
base::string16 GetCustomMessage() const;
// Show the dialog. Sets |shown_| to true. // Show the dialog. Sets |shown_| to true.
void Show(); void Show();
void AcceptButtonCallback(); void AcceptButtonCallback();
void CancelButtonCallback(); void CancelButtonCallback();
void LearnMoreLinkClickedCallback(const ui::Event& event);
// This callback used by DialogDelegate::SetCancelCallback and is used to // This callback used by DialogDelegate::SetCancelCallback and is used to
// ensure the auto-closing success dialog handles focus correctly. // ensure the auto-closing success dialog handles focus correctly.
...@@ -222,6 +235,7 @@ class ContentAnalysisDialog : public views::DialogDelegate, ...@@ -222,6 +235,7 @@ class ContentAnalysisDialog : public views::DialogDelegate,
DeepScanningSideIconImageView* side_icon_image_ = nullptr; DeepScanningSideIconImageView* side_icon_image_ = nullptr;
DeepScanningSideIconSpinnerView* side_icon_spinner_ = nullptr; DeepScanningSideIconSpinnerView* side_icon_spinner_ = nullptr;
DeepScanningMessageView* message_ = nullptr; DeepScanningMessageView* message_ = nullptr;
views::Link* learn_more_link_ = nullptr;
bool shown_ = false; bool shown_ = false;
...@@ -233,6 +247,8 @@ class ContentAnalysisDialog : public views::DialogDelegate, ...@@ -233,6 +247,8 @@ class ContentAnalysisDialog : public views::DialogDelegate,
// Used to show the appropriate message. // Used to show the appropriate message.
ContentAnalysisDelegate::FinalResult final_result_ = ContentAnalysisDelegate::FinalResult final_result_ =
ContentAnalysisDelegate::FinalResult::SUCCESS; ContentAnalysisDelegate::FinalResult::SUCCESS;
std::string final_custom_message_;
GURL final_learn_more_url_;
// Used to animate dialog height changes. // Used to animate dialog height changes.
std::unique_ptr<views::BoundsAnimator> bounds_animator_; std::unique_ptr<views::BoundsAnimator> bounds_animator_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment