diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 15 | ||||
-rw-r--r-- | chrome/browser/policy/configuration_policy_reader.cc | 30 | ||||
-rw-r--r-- | chrome/browser/policy/configuration_policy_reader.h | 45 | ||||
-rw-r--r-- | chrome/browser/resources/policy.css | 15 | ||||
-rw-r--r-- | chrome/browser/resources/policy.html | 130 | ||||
-rw-r--r-- | chrome/browser/resources/policy.js | 175 | ||||
-rw-r--r-- | chrome/browser/ui/webui/policy_ui.cc | 171 | ||||
-rw-r--r-- | chrome/browser/ui/webui/policy_ui.h | 47 |
8 files changed, 531 insertions, 97 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index c1a3199..98d4421 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -4232,9 +4232,15 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_POLICY_USER_POLICIES" desc="The title for the user policies status box."> User policies </message> - <message name="IDS_POLICY_ENROLLMENT_DOMAIN" desc="The label for the enrollment domain in the status boxes."> + <message name="IDS_POLICY_ENROLLMENT_DOMAIN" desc="The label for the enrollment domain in the device policies status box."> Enrollment domain: </message> + <message name="IDS_POLICY_CLIENT_ID" desc="The label for the client ids in the status boxes."> + Client Id: + </message> + <message name="IDS_POLICY_USERNAME" desc="The label for the username in the user policies status box."> + User: + </message> <message name="IDS_POLICY_LAST_FETCHED" desc="The label for the last fetched time in the status boxes."> Last fetched: </message> @@ -4269,7 +4275,12 @@ Keep your key file in a safe place. You will need it to create new versions of y <message name="IDS_POLICY_ENTRY_STATUS" desc="The table header for the column in policy table that contains the status of the policy."> Status </message> - + <message name="IDS_POLICY_SHOW_MORE" desc="The text for the link that expands a policy value or policy status table cell."> + [Show more] + </message> + <message name="IDS_POLICY_HIDE" desc="The text for the link that hides overflowing text in a policy value or policy status table cell."> + [Hide] + </message> <!-- about:flags --> <message name="IDS_FLAGS_LONG_TITLE" desc="Long version of the title for the about:flags page."> Careful, these experiments may bite diff --git a/chrome/browser/policy/configuration_policy_reader.cc b/chrome/browser/policy/configuration_policy_reader.cc index c8bf7e1..f9e39b8 100644 --- a/chrome/browser/policy/configuration_policy_reader.cc +++ b/chrome/browser/policy/configuration_policy_reader.cc @@ -120,6 +120,14 @@ void ConfigurationPolicyReader::OnProviderGoingAway() { provider_ = NULL; } +void ConfigurationPolicyReader::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void ConfigurationPolicyReader::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + // static ConfigurationPolicyReader* ConfigurationPolicyReader::CreateManagedPlatformPolicyReader() { @@ -176,6 +184,8 @@ void ConfigurationPolicyReader::Refresh() { scoped_ptr<ConfigurationPolicyStatusKeeper> new_keeper( new ConfigurationPolicyStatusKeeper(provider_, policy_level_)); policy_keeper_.reset(new_keeper.release()); + + FOR_EACH_OBSERVER(Observer, observers_, OnPolicyValuesChanged()); } // PolicyStatus @@ -192,11 +202,25 @@ PolicyStatus::PolicyStatus(ConfigurationPolicyReader* managed_platform, PolicyStatus::~PolicyStatus() { } -ListValue* PolicyStatus::GetPolicyStatusList(bool* any_policies_sent) const { +void PolicyStatus::AddObserver(Observer* observer) const { + managed_platform_->AddObserver(observer); + managed_cloud_->AddObserver(observer); + recommended_platform_->AddObserver(observer); + recommended_cloud_->AddObserver(observer); +} + +void PolicyStatus::RemoveObserver(Observer* observer) const { + managed_platform_->RemoveObserver(observer); + managed_cloud_->RemoveObserver(observer); + recommended_platform_->RemoveObserver(observer); + recommended_cloud_->RemoveObserver(observer); +} + +ListValue* PolicyStatus::GetPolicyStatusList(bool* any_policies_set) const { ListValue* result = new ListValue(); std::vector<DictionaryValue*> unsent_policies; - *any_policies_sent = false; + *any_policies_set = false; const PolicyDefinitionList* supported_policies = ConfigurationPolicyPrefStore::GetChromePolicyDefinitionList(); const PolicyDefinitionList::Entry* policy = supported_policies->begin; @@ -210,7 +234,7 @@ ListValue* PolicyStatus::GetPolicyStatusList(bool* any_policies_sent) const { string16()); unsent_policies.push_back(info.GetDictionaryValue()); } else { - *any_policies_sent = true; + *any_policies_set = true; } } diff --git a/chrome/browser/policy/configuration_policy_reader.h b/chrome/browser/policy/configuration_policy_reader.h index 372ff28..25b9c8a 100644 --- a/chrome/browser/policy/configuration_policy_reader.h +++ b/chrome/browser/policy/configuration_policy_reader.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_POLICY_CONFIGURATION_POLICY_READER_H_ #pragma once +#include "base/observer_list.h" #include "base/scoped_ptr.h" #include "base/values.h" #include "chrome/browser/policy/configuration_policy_provider.h" @@ -21,6 +22,18 @@ class ConfigurationPolicyStatusKeeper; // about:policy UI. class ConfigurationPolicyReader : public ConfigurationPolicyProvider::Observer { public: + + // Observer class for the ConfigurationPolicyReader. Observer objects are + // notified when policy values have changed. + class Observer { + public: + // Called on an observer when the policy values have changed. + virtual void OnPolicyValuesChanged() = 0; + + protected: + virtual ~Observer() {} + }; + ConfigurationPolicyReader(ConfigurationPolicyProvider* provider, PolicyStatusInfo::PolicyLevel policy_level); virtual ~ConfigurationPolicyReader(); @@ -29,21 +42,21 @@ class ConfigurationPolicyReader : public ConfigurationPolicyProvider::Observer { virtual void OnUpdatePolicy(); virtual void OnProviderGoingAway(); + // Methods to handle Observers. |observer| must be non-NULL. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + // Creates a ConfigurationPolicyReader that reads managed platform policy. - static ConfigurationPolicyReader* - CreateManagedPlatformPolicyReader(); + static ConfigurationPolicyReader* CreateManagedPlatformPolicyReader(); // Creates a ConfigurationPolicyReader that reads managed cloud policy. - static ConfigurationPolicyReader* - CreateManagedCloudPolicyReader(); + static ConfigurationPolicyReader* CreateManagedCloudPolicyReader(); // Creates a ConfigurationPolicyReader that reads recommended platform policy. - static ConfigurationPolicyReader* - CreateRecommendedPlatformPolicyReader(); + static ConfigurationPolicyReader* CreateRecommendedPlatformPolicyReader(); // Creates a ConfigurationPolicyReader that reads recommended cloud policy. - static ConfigurationPolicyReader* - CreateRecommendedCloudPolicyReader(); + static ConfigurationPolicyReader* CreateRecommendedCloudPolicyReader(); // Returns a pointer to a DictionaryValue object containing policy status // information for the UI. Ownership of the return value is acquired by the @@ -70,6 +83,9 @@ class ConfigurationPolicyReader : public ConfigurationPolicyProvider::Observer { // Current policy status. scoped_ptr<ConfigurationPolicyStatusKeeper> policy_keeper_; + // The list of observers for this ConfigurationPolicyReader. + ObserverList<Observer, true> observers_; + ConfigurationPolicyObserverRegistrar registrar_; DISALLOW_COPY_AND_ASSIGN(ConfigurationPolicyReader); @@ -80,17 +96,24 @@ class ConfigurationPolicyReader : public ConfigurationPolicyProvider::Observer { // about:policy UI can display. class PolicyStatus { public: + typedef ConfigurationPolicyReader::Observer Observer; PolicyStatus(ConfigurationPolicyReader* managed_platform, ConfigurationPolicyReader* managed_cloud, ConfigurationPolicyReader* recommended_platform, ConfigurationPolicyReader* recommended_cloud); ~PolicyStatus(); + // Adds an observer to each one of the ConfigurationPolicyReaders. + void AddObserver(Observer* observer) const; + + // Removes an observer from each one of the ConfigurationPolicyReaders. + void RemoveObserver(Observer* observer) const; + // Returns a ListValue pointer containing the status information of all - // policies supported by the client. |any_policies_sent| is set to true if + // policies supported by the client. |any_policies_set| is set to true if // there are policies in the list that were sent by a provider, otherwise // it is set to false. This is for the about:policy UI to display. - ListValue* GetPolicyStatusList(bool* any_policies_sent) const; + ListValue* GetPolicyStatusList(bool* any_policies_set) const; // Returns a string16 containing the actual name of the policy corresponding // to |policy_type|. Returns an empty string if there is no such policy_type @@ -105,7 +128,7 @@ class PolicyStatus { // |list| as it is returned by the different ConfigurationPolicyReader // objects. Returns true if a policy was added and false otherwise. bool AddPolicyFromReaders(ConfigurationPolicyType policy, - ListValue* list) const; + ListValue* list) const; scoped_ptr<ConfigurationPolicyReader> managed_platform_; scoped_ptr<ConfigurationPolicyReader> managed_cloud_; diff --git a/chrome/browser/resources/policy.css b/chrome/browser/resources/policy.css index 2fa9a1b..e572247 100644 --- a/chrome/browser/resources/policy.css +++ b/chrome/browser/resources/policy.css @@ -141,3 +141,18 @@ legend { text-overflow: ellipsis; width: 20%; } + +.toggler { + color: #808080; +} + +.collapsed { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.expanded { + overflow: visible; + word-wrap: break-word; +} diff --git a/chrome/browser/resources/policy.html b/chrome/browser/resources/policy.html index db547b4..05d38a9 100644 --- a/chrome/browser/resources/policy.html +++ b/chrome/browser/resources/policy.html @@ -5,52 +5,85 @@ <title i18n-content="policyTitle"></title> <link rel="stylesheet" href="chrome://resources/css/button.css"> <link rel="stylesheet" href="policy.css"> +<link rel="stylesheet" href="webui.css"> <script src="chrome://policy/strings.js"></script> <script src="chrome://resources/js/cr.js"></script> <script src="chrome://resources/js/cr/ui.js"></script> -<script src="chrome://resources/js/local_strings.js"></script> <script src="chrome://resources/js/i18n_template.js"></script> <script src="chrome://resources/js/i18n_process.js"></script> <script src="chrome://resources/js/jstemplate_compiled.js"></script> <script src="chrome://resources/js/util.js"></script> <script src="policy.js"></script> </head> -<body i18n-values=".style.fontFamily:fontfamily;"> +<body i18n-values=".style.fontFamily:fontfamily; .style.fontSize:fontsize"> <div class="header"> <h1 id="about-policy-title" i18n-content="policyTitle"></h1> </div> <div id="main-content"> - <section id="status-section"> - <div class="separator"> - <span id="status-title" i18n-content="statusPaneTitle"></span> - <div id="fetch-policies"> - <button id="fetch-policies-button" i18n-content="fetchPoliciesText"> - </button> + <div id="data-template"> + <section id="status-section" jsselect="status" hidden + jsdisplay="displayStatusSection"> + <div class="separator"> + <span id="status-title" i18n-content="statusPaneTitle"></span> + <div id="fetch-policies"> + <button id="fetch-policies-button" i18n-content="fetchPoliciesText"> + </button> + </div> </div> - </div> - <div id="status-pane"> - <fieldset class="status-box"> - <legend i18n-content="devicePoliciesBoxTitle"></legend> - <ul> - <li i18n-content="enrollmentDomainText"></li> - <li i18n-content="lastFetchedText"></li> - <li i18n-content="fetchIntervalText"></li> - <li i18n-content="serverStatusText"></li> - </ul> - </fieldset> - <fieldset class="status-box"> - <legend i18n-content="userPoliciesBoxTitle"></legend> - <ul> - <li i18n-content="enrollmentDomainText"></li> - <li i18n-content="lastFetchedText"></li> - <li i18n-content="fetchIntervalText"></li> - <li i18n-content="serverStatusText"></li> - </ul> - </fielset> - </div> - </section> - <section id="policies-section"> - <div id="policiesTemplate"> + <div id="status-pane"> + <fieldset class="status-box"> + <legend i18n-content="devicePoliciesBoxTitle"></legend> + <ul> + <li> + <span i18n-content="enrollmentDomainText"></span> + <span jscontent="devicePolicyDomain"></span> + </li> + <li> + <span i18n-content="clientIdText"></span> + <span jscontent="deviceId"></span> + </li> + <li> + <span i18n-content="lastFetchedText"></span> + <span jscontent="deviceLastFetchTime"></span> + </li> + <li> + <span i18n-content="fetchIntervalText"></span> + <span jscontent="deviceFetchInterval"></span> + </li> + <li> + <span i18n-content="serverStatusText"></span> + <span jscontent="deviceStatusMessage"></span> + </li> + </ul> + </fieldset> + <fieldset class="status-box"> + <legend i18n-content="userPoliciesBoxTitle"></legend> + <ul> + <li> + <span i18n-content="usernameText"></span> + <span jscontent="user"></span> + </li> + <li> + <span i18n-content="clientIdText"></span> + <span jscontent="userId"></span> + </li> + <li> + <span i18n-content="lastFetchedText"></span> + <span jscontent="userLastFetchTime"></span> + </li> + <li> + <span i18n-content="fetchIntervalText"></span> + <span jscontent="userFetchInterval"></span> + </li> + <li> + <span i18n-content="serverStatusText"></span> + <span jscontent="userStatusMessage"></span> + </li> + </ul> + </fielset> + </div> + </section> + <section id="policies-section"> <div class="separator"> <span id="policies-title" i18n-content="policyTitle"></span> <div id="unsent-policies-control"> @@ -66,11 +99,10 @@ </div> </div> <div> - <div id="no-policies" jsdisplay="!anyPoliciesSet"> + <div id="no-policies" hidden jsdisplay="!anyPoliciesSet"> <div id="no-policies-text" i18n-content="noPoliciesSet"></div> </div> - <div id="policies" - jsvalues=".style.display: anyPoliciesSet ? + <div id="policies" jsvalues=".style.display: anyPoliciesSet ? '': 'none'"> <table id="policy-table"> <tr> @@ -83,29 +115,43 @@ <tr jsselect="policies" jsvalues=".className: $this.set ? 'policy-set': 'policy-unset'; - .style.display: Policy.shouldDisplayPolicy($this) ? - '': 'none'"> + .style.visibility: Policy.shouldDisplayPolicy($this) ? + 'visible': 'hidden'"> <td> <span class="policy-type" jscontent="sourceType"></span> </td> <td> <span class="policy-level" jscontent="level"></span> </td> - <td> + <td class="collapsed"> <span class="policy-name" jscontent="name"></span> </td> <td> - <span class="policy-value" jscontent="value"></span> + <div class="text-container collapsed"> + <span class="cell-text" jscontent="value"></span> + </div> + <a class="toggler expand" style="display: none" + jsdisplay="Policy.shouldShowExpand(this)" + i18n-content="showMoreText"></a> + <a class="toggler collapse" style="display: none" + i18n-content="hideText"></a> </td> <td> - <span class="policy-status" jscontent="status"></span> + <div class="text-container collapsed"> + <span class="cell-text" jscontent="status"></span> + </div> + <a class="toggler expand" style="display: none" + jsdisplay="Policy.shouldShowExpand(this)" + i18n-content="showMoreText"></a> + <a class="toggler collapse" style="display: none" + i18n-content="hideText"></a> </td> </tr> </table> </div> </div> - </div> - </section> + </section> + </div> </div> </body> </html> diff --git a/chrome/browser/resources/policy.js b/chrome/browser/resources/policy.js index db4f404..c86611d 100644 --- a/chrome/browser/resources/policy.js +++ b/chrome/browser/resources/policy.js @@ -2,13 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var localStrings = new LocalStrings(); - /** * This variable structure is here to document the structure that the template * expects to correctly populate the page. */ -var policyDataformat = { +var policyDataFormat = { + // Whether any of the policies in 'policies' have a value. + 'anyPoliciesSet': true, + + // False if the policy information is being sent due to an initial page load + // and true if it is being sent due to a change of policy values. + 'isPolicyUpdate': false, 'policies': [ { 'level': 'managed', @@ -16,10 +20,22 @@ var policyDataformat = { 'set': true, 'sourceType': 'Device', 'status': 'ok', - 'value': true, - }, + 'value': true + } ], - 'anyPoliciesSet': true + 'status': { + 'deviceFetchInterval': '8min', + 'deviceId': 'D2AC39A2-3C8FC-E2C0-E45D2DC3782C', + 'deviceLastFetchTime': '9:50 PM', + 'devicePolicyDomain': 'google.com', + 'deviceStatusMessage': 'OK', + 'displayStatusSection': true, + 'user': 'simo@google.com', + 'userFetchInterval': '8min', + 'userId': 'D2AC39A2-3C8FC-E2C0-E45D2DC3782C', + 'userLastFetchTime': '9:50 PM', + 'userStatusMessage': 'OK' + } }; cr.define('policies', function() { @@ -45,23 +61,28 @@ cr.define('policies', function() { searchTerm_: '', /** - * Takes the |policyData| input argument which represents data about the - * policies supported by the device/client and populates the html jstemplate - * with that data. It expects an object structure like the above. - * @param {Object} policyData Detailed info about policies + * Takes the |policyData| argument and populates the page with this data. It + * expects an object structure like the policyDataFormat above. + * @param {Object} policyData Detailed info about policies. */ renderTemplate: function(policyData) { this.noActivePolicies_ = !policyData.anyPoliciesSet; + if (this.noActivePolicies_) + $('no-policies').hidden = false; + if (policyData.status.displayStatusSection) + $('status-section').hidden = false;; + // This is the javascript code that processes the template: var input = new JsEvalContext(policyData); - var output = $('policiesTemplate'); + var output = $('data-template'); jstProcess(input, output); + this.setToggleEventHandlers_(); }, /** * Filters the table of policies by name. - * @param {string} term The search string + * @param {string} term The search string. */ filterTable: function(term) { this.searchTerm_ = term.toLowerCase(); @@ -104,41 +125,149 @@ cr.define('policies', function() { // Filter table again in case a search was active. this.filterTable(this.searchTerm_); + }, + + /** + * Set event handlers for the "Show more"/"Hide" links generated by + * jstemplate. + * @private + */ + setToggleEventHandlers_: function() { + var toggles = document.querySelectorAll('.policy-set * .toggler'); + for (var i = 0; i < toggles.length; i++) { + toggles[i].onclick = function() { + Policy.getInstance().toggleCellExpand_(this); + }; + } + }, + + /** + * Expands or collapses a table cell that has overflowing text. + * @param {Object} toggler The toggler that was clicked on. + * @private + */ + toggleCellExpand_: function(toggler) { + var tableCell = toggler.parentElement; + var textContainer = tableCell.querySelector('.text-container'); + + if (textContainer.collapsed) + this.expandCell_(textContainer); + else + this.collapseCell_(textContainer); + + textContainer.collapsed = !textContainer.collapsed; + var expand = tableCell.querySelector('.expand'); + var collapse = tableCell.querySelector('.collapse'); + expand.style.display = textContainer.collapsed ? '' : 'none'; + collapse.style.display = textContainer.collapsed ? 'none' : ''; + }, + + /** + * Collapses all expanded table cells and updates the visibility of the + * toggles accordingly. Should be called before the policy information in + * the table is updated. + */ + collapseExpandedCells: function() { + var toggles = document.querySelectorAll('.policy-set * .toggler'); + for (var i = 0; i < toggles.length; i++) + toggles[i].style.display = 'none'; + + var textContainers = document.querySelectorAll('.expanded'); + for (var i = 0; i < textContainers.length; i++) + this.collapseCell_(textContainers[i]); + }, + + /** + * Expands a table cell so that all the text it contains is visible. + * @param {Object} textContainer The cell's div element that contains the + * text. + * @private + */ + expandCell_: function(textContainer) { + textContainer.classList.remove('collapsed'); + textContainer.classList.add('expanded'); + }, + + /** + * Collapses a table cell so that overflowing text is hidden. + * @param {Object} textContainer The cell's div element that contains the + * text. + * @private + */ + collapseCell_: function(textContainer) { + textContainer.classList.remove('expanded'); + textContainer.classList.add('collapsed'); } }; /** - * Asks the C++ PolicyUIHandler to get details about policies. The - * PolicyDOMHandler should reply to returnPolicyData() (below). + * Asks the C++ PolicyUIHandler to get details about policies and status + * information. The PolicyUIHandler should reply to returnData() (below). */ - Policy.requestPolicyData = function() { - chrome.send('requestPolicyData'); + Policy.requestData = function() { + chrome.send('requestData'); }; /** - * Called by the C++ PolicyUIHandler when it has the requested policy data. + * Called by the C++ PolicyUIHandler when it has the requested data. + * @param {Object} policyData The policy information in the format described + * by the policyDataFormat. */ - Policy.returnPolicyData = function(policyData) { - Policy.getInstance().renderTemplate(policyData); + Policy.returnData = function(policyData) { + if (policyData.isPolicyUpdate) { + Policy.getInstance().collapseExpandedCells(); + Policy.getInstance().renderTemplate(policyData); + Policy.getInstance().updatePolicyVisibility(); + } else { + Policy.getInstance().renderTemplate(policyData); + } + }; + + /** + * Asks the C++ PolicyUIHandler to re-fetch policy information. + */ + Policy.triggerPolicyFetch = function() { + chrome.send('fetchPolicy'); }; /** * Determines whether a policy should be visible or not. - * @param {policy} policy information in the format given by above the - * PolicyDataFormat + * @param {Object} policy An entry in the 'policies' array given by the above + * PolicyDataFormat. */ Policy.shouldDisplayPolicy = function(policy) { return $('toggle-unsent-policies').checked || policy.set; }; /** - * Initializes the page and loads the list of policies. + * Returns true if the "Show more" toggle should appear in a table cell and + * false if not. + * @param {Object} expandToggle The "Show more" DOM element. + */ + Policy.shouldShowExpand = function(expandToggle) { + var textContainer = + expandToggle.parentNode.querySelector('.text-container'); + textContainer.collapsed = true; + var cellText = textContainer.querySelector('.cell-text'); + + // If the text is wider than the text container, the expand toggler should + // appear. + return textContainer.offsetWidth < cellText.offsetWidth; + }; + + /** + * Initializes the page and loads the list of policies and the policy + * status data. */ Policy.initialize = function() { i18nTemplate.process(document, templateData); - Policy.requestPolicyData(); + Policy.requestData(); // Set HTML event handlers. + $('fetch-policies-button').onclick = function(event) { + Policy.triggerPolicyFetch(); + } + $('toggle-unsent-policies').onchange = function(event) { Policy.getInstance().updatePolicyVisibility(); }; diff --git a/chrome/browser/ui/webui/policy_ui.cc b/chrome/browser/ui/webui/policy_ui.cc index 99ebb3e..b412d6f 100644 --- a/chrome/browser/ui/webui/policy_ui.cc +++ b/chrome/browser/ui/webui/policy_ui.cc @@ -4,9 +4,17 @@ #include "chrome/browser/ui/webui/policy_ui.h" -#include "chrome/browser/policy/policy_status_info.h" +#include "base/i18n/time_formatting.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/policy/browser_policy_connector.h" +#include "chrome/browser/policy/cloud_policy_cache_base.h" +#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/webui/chrome_web_ui_data_source.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/time_format.h" #include "chrome/common/url_constants.h" #include "content/browser/tab_contents/tab_contents.h" #include "grit/browser_resources.h" @@ -26,6 +34,8 @@ ChromeWebUIDataSource* CreatePolicyUIHTMLSource() { IDS_POLICY_USER_POLICIES); source->AddLocalizedString("enrollmentDomainText", IDS_POLICY_ENROLLMENT_DOMAIN); + source->AddLocalizedString("clientIdText", IDS_POLICY_CLIENT_ID); + source->AddLocalizedString("usernameText", IDS_POLICY_USERNAME); source->AddLocalizedString("lastFetchedText", IDS_POLICY_LAST_FETCHED); source->AddLocalizedString("fetchIntervalText", IDS_POLICY_FETCH_INTERVAL); source->AddLocalizedString("serverStatusText", IDS_POLICY_SERVER_STATUS); @@ -39,6 +49,8 @@ ChromeWebUIDataSource* CreatePolicyUIHTMLSource() { source->AddLocalizedString("policyValueTableHeader", IDS_POLICY_ENTRY_VALUE); source->AddLocalizedString("policyStatusTableHeader", IDS_POLICY_ENTRY_STATUS); + source->AddLocalizedString("showMoreText", IDS_POLICY_SHOW_MORE); + source->AddLocalizedString("hideText", IDS_POLICY_HIDE); source->set_json_path("strings.js"); // Add required resources. @@ -57,20 +69,23 @@ ChromeWebUIDataSource* CreatePolicyUIHTMLSource() { PolicyUIHandler::PolicyUIHandler() { policy::ConfigurationPolicyReader* managed_platform = - ConfigurationPolicyReader::CreateManagedPlatformPolicyReader(); + policy::ConfigurationPolicyReader::CreateManagedPlatformPolicyReader(); policy::ConfigurationPolicyReader* managed_cloud = - ConfigurationPolicyReader::CreateManagedCloudPolicyReader(); + policy::ConfigurationPolicyReader::CreateManagedCloudPolicyReader(); policy::ConfigurationPolicyReader* recommended_platform = - ConfigurationPolicyReader::CreateRecommendedPlatformPolicyReader(); + policy::ConfigurationPolicyReader:: + CreateRecommendedPlatformPolicyReader(); policy::ConfigurationPolicyReader* recommended_cloud = - ConfigurationPolicyReader::CreateRecommendedCloudPolicyReader(); + policy::ConfigurationPolicyReader::CreateRecommendedCloudPolicyReader(); policy_status_.reset(new policy::PolicyStatus(managed_platform, managed_cloud, recommended_platform, recommended_cloud)); + policy_status_->AddObserver(this); } PolicyUIHandler::~PolicyUIHandler() { + policy_status_->RemoveObserver(this); } WebUIMessageHandler* PolicyUIHandler::Attach(WebUI* web_ui) { @@ -78,17 +93,149 @@ WebUIMessageHandler* PolicyUIHandler::Attach(WebUI* web_ui) { } void PolicyUIHandler::RegisterMessages() { - web_ui_->RegisterMessageCallback("requestPolicyData", - NewCallback(this, &PolicyUIHandler::HandleRequestPolicyData)); + web_ui_->RegisterMessageCallback("requestData", + NewCallback(this, &PolicyUIHandler::HandleRequestData)); + web_ui_->RegisterMessageCallback("fetchPolicy", + NewCallback(this, &PolicyUIHandler::HandleFetchPolicy)); } -void PolicyUIHandler::HandleRequestPolicyData(const ListValue* args) { - bool any_policies_sent; - ListValue* list = policy_status_->GetPolicyStatusList(&any_policies_sent); +void PolicyUIHandler::OnPolicyValuesChanged() { + SendDataToUI(true); +} + +void PolicyUIHandler::HandleRequestData(const ListValue* args) { + SendDataToUI(false); +} + +void PolicyUIHandler::HandleFetchPolicy(const ListValue* args) { + if (FetchPolicyIfTokensAvailable()) + SendDataToUI(true); +} + +void PolicyUIHandler::SendDataToUI(bool is_policy_update) { DictionaryValue results; + bool any_policies_set; + ListValue* list = policy_status_->GetPolicyStatusList(&any_policies_set); results.Set("policies", list); - results.SetBoolean("anyPoliciesSet", any_policies_sent); - web_ui_->CallJavascriptFunction("Policy.returnPolicyData", results); + results.SetBoolean("anyPoliciesSet", any_policies_set); + DictionaryValue* dict = GetStatusData(); + results.Set("status", dict); + results.SetBoolean("isPolicyUpdate", is_policy_update); + + web_ui_->CallJavascriptFunction("Policy.returnData", results); +} + +DictionaryValue* PolicyUIHandler::GetStatusData() { + DictionaryValue* results = new DictionaryValue(); + policy::BrowserPolicyConnector* connector = + g_browser_process->browser_policy_connector(); + + policy::CloudPolicySubsystem* device_subsystem = + connector->device_cloud_policy_subsystem(); + policy::CloudPolicySubsystem* user_subsystem = + connector->user_cloud_policy_subsystem(); + + // If no CloudPolicySubsystem is available, the status section is not + // displayed and we can return here. + if (!device_subsystem || !user_subsystem) { + results->SetBoolean("displayStatusSection", false); + return results; + } else { + results->SetBoolean("displayStatusSection", true); + } + + // Get the server status message and the time at which policy was last fetched + // for both user and device policy from the appropriate CloudPolicySubsystem. + results->SetString("deviceStatusMessage", + CreateStatusMessageString(device_subsystem->error_details())); + results->SetString("deviceLastFetchTime", GetLastFetchTime(device_subsystem)); + results->SetString("userStatusMessage", + CreateStatusMessageString(user_subsystem->error_details())); + results->SetString("userLastFetchTime", GetLastFetchTime(user_subsystem)); + + // Get enterprise domain and username (only on ChromeOS). +#if defined (OS_CHROMEOS) + chromeos::UserManager::User user = + chromeos::UserManager::Get()->logged_in_user(); + results->SetString("devicePolicyDomain", + ASCIIToUTF16(connector->GetEnterpriseDomain())); + results->SetString("user", ASCIIToUTF16(user.email())); +#else + results->SetString("devicePolicyDomain", string16()); + results->SetString("user", string16()); +#endif + + // Get the device ids for both user and device policy from the appropriate + // CloudPolicyDataStore. + results->SetString("deviceId", + GetDeviceId(connector->GetDeviceCloudPolicyDataStore())); + results->SetString("userId", + GetDeviceId(connector->GetUserCloudPolicyDataStore())); + + // Get the policy refresh rate for both user and device policy from the + // appropriate preference. + results->SetString("deviceFetchInterval", + GetPolicyFetchInterval(prefs::kDevicePolicyRefreshRate)); + results->SetString("userFetchInterval", + GetPolicyFetchInterval(prefs::kUserPolicyRefreshRate)); + + return results; +} + +bool PolicyUIHandler::FetchPolicyIfTokensAvailable() { + policy::BrowserPolicyConnector* connector = + g_browser_process->browser_policy_connector(); + const policy::CloudPolicyDataStore* device_data_store = + connector->GetDeviceCloudPolicyDataStore(); + const policy::CloudPolicyDataStore* user_data_store = + connector->GetUserCloudPolicyDataStore(); + + bool fetch_device_policy = + device_data_store && !device_data_store->device_token().empty(); + bool fetch_user_policy = + user_data_store && !user_data_store->device_token().empty(); + + if (fetch_device_policy) + connector->FetchDevicePolicy(); + + if (fetch_user_policy) + connector->FetchUserPolicy(); + + return fetch_device_policy || fetch_user_policy; +} + +string16 PolicyUIHandler::GetLastFetchTime( + policy::CloudPolicySubsystem* subsystem) { + policy::CloudPolicyCacheBase* cache_base = + subsystem->GetCloudPolicyCacheBase(); + base::TimeDelta time_delta = + base::Time::NowFromSystemTime() - cache_base->last_policy_refresh_time(); + + return TimeFormat::TimeElapsed(time_delta); +} + +string16 PolicyUIHandler::GetDeviceId( + const policy::CloudPolicyDataStore* data_store) { + return data_store ? ASCIIToUTF16(data_store->device_id()) : string16(); +} + +string16 PolicyUIHandler::GetPolicyFetchInterval(const char* refresh_pref) { + PrefService* prefs = g_browser_process->local_state(); + return TimeFormat::TimeRemainingShort( + base::TimeDelta::FromMilliseconds(prefs->GetInteger(refresh_pref))); +} + +// static +string16 PolicyUIHandler::CreateStatusMessageString( + policy::CloudPolicySubsystem::ErrorDetails error_details) { + static string16 error_to_string[] = { ASCIIToUTF16("OK."), + ASCIIToUTF16("Network error."), + ASCIIToUTF16("Network error."), + ASCIIToUTF16("Bad DMToken."), + ASCIIToUTF16("Local error."), + ASCIIToUTF16("Signature mismatch.") }; + DCHECK(static_cast<size_t>(error_details) < arraysize(error_to_string)); + return error_to_string[error_details]; } //////////////////////////////////////////////////////////////////////////////// diff --git a/chrome/browser/ui/webui/policy_ui.h b/chrome/browser/ui/webui/policy_ui.h index f773a4b..52e0ad2 100644 --- a/chrome/browser/ui/webui/policy_ui.h +++ b/chrome/browser/ui/webui/policy_ui.h @@ -7,13 +7,17 @@ #pragma once #include "base/scoped_ptr.h" +#include "base/time.h" #include "base/values.h" +#include "chrome/browser/policy/cloud_policy_data_store.h" +#include "chrome/browser/policy/cloud_policy_subsystem.h" #include "chrome/browser/policy/configuration_policy_reader.h" #include "chrome/browser/ui/webui/chrome_web_ui.h" #include "content/common/notification_observer.h" // The base class handler of Javascript messages of the about:policy page. -class PolicyUIHandler : public WebUIMessageHandler { +class PolicyUIHandler : public WebUIMessageHandler, + public policy::PolicyStatus::Observer { public: PolicyUIHandler(); virtual ~PolicyUIHandler(); @@ -22,11 +26,46 @@ class PolicyUIHandler : public WebUIMessageHandler { virtual WebUIMessageHandler* Attach(WebUI* web_ui) OVERRIDE; virtual void RegisterMessages() OVERRIDE; + // policy::ConfigurationPolicyReader::Observer implementation. + virtual void OnPolicyValuesChanged() OVERRIDE; + private: - typedef policy::ConfigurationPolicyReader ConfigurationPolicyReader; - // Callback for the "requestPolicyData" message. - void HandleRequestPolicyData(const ListValue* args); + // Callback for the "requestData" message. The parameter |args| is unused. + void HandleRequestData(const ListValue* args); + + // Callback for the "fetchPolicy" message. The parameter |args| is unused. + void HandleFetchPolicy(const ListValue* args); + + // Send requested data to UI. |is_policy_update| should be set to true when + // policy data is pushed to the UI without having been requested by a + // javascript message and to false otherwise. + void SendDataToUI(bool is_policy_update); + + // Returns a DictionaryValue pointer containing information about the status + // of the policy system. The caller acquires ownership of the returned + // DictionaryValue pointer. + DictionaryValue* GetStatusData(); + + // Fetches policy if the appropriate device tokens are available. Returns + // true, if any policy was fetched (device or user). Returns false otherwise. + bool FetchPolicyIfTokensAvailable(); + + // Returns the time at which policy was last fetched by the + // CloudPolicySubsystem |subsystem| in string form. + string16 GetLastFetchTime(policy::CloudPolicySubsystem* subsystem); + + // Reads the device id from |data_store| and returns it as a string16. + string16 GetDeviceId(const policy::CloudPolicyDataStore* data_store); + + // Reads the policy fetch interval from the preferences specified by + // |refresh_pref| and returns it as a string16. + string16 GetPolicyFetchInterval(const char* refresh_pref); + + // Returns the string corresponding to the CloudPolicySubsystem::ErrorDetails + // enum value |error_details|. + static string16 CreateStatusMessageString( + policy::CloudPolicySubsystem::ErrorDetails error_details); scoped_ptr<policy::PolicyStatus> policy_status_; |