OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/supervised_user/supervised_user_bookmarks_handler.h" |
| 6 |
| 7 #include "base/logging.h" |
| 8 #include "base/strings/string_number_conversions.h" |
| 9 #include "base/values.h" |
| 10 #include "components/url_fixer/url_fixer.h" |
| 11 |
| 12 namespace { |
| 13 |
| 14 // Keys of relevant managed user settings. |
| 15 const char kKeyLink[] = "SupervisedBookmarkLink"; |
| 16 const char kKeyFolder[] = "SupervisedBookmarkFolder"; |
| 17 |
| 18 // Keys for elements of the bookmarks json tree. |
| 19 const char kId[] = "id"; |
| 20 const char kName[] = "name"; |
| 21 const char kUrl[] = "url"; |
| 22 const char kChildren[] = "children"; |
| 23 |
| 24 bool ExtractId(const std::string& key, int* id) { |
| 25 // |key| can be either "<ID>:<Value>" (for links and for "parentID:name" |
| 26 // pairs) or just "<ID>" (for folders). |
| 27 std::string id_str = key.substr(0, key.find_first_of(':')); |
| 28 if (!base::StringToInt(id_str, id)) { |
| 29 LOG(WARNING) << "Failed to parse id from " << key; |
| 30 return false; |
| 31 } |
| 32 LOG_IF(WARNING, *id < 0) << "IDs should be >= 0, but got " |
| 33 << *id << " from " << key; |
| 34 return true; |
| 35 } |
| 36 |
| 37 bool ExtractValue(const std::string& key, std::string* value) { |
| 38 // |key| must be "<ID>:<Value>". |
| 39 size_t pos = key.find_first_of(':'); |
| 40 if (pos == std::string::npos) { |
| 41 LOG(WARNING) << "Failed to parse value from " << key; |
| 42 return false; |
| 43 } |
| 44 *value = key.substr(pos + 1); |
| 45 return true; |
| 46 } |
| 47 |
| 48 bool ExtractIdAndValue(const std::string& key, int* id, std::string* value) { |
| 49 return ExtractId(key, id) && ExtractValue(key, value); |
| 50 } |
| 51 |
| 52 // Recursively searches the tree from |root| for a folder with the given |id|. |
| 53 // Returns the list of children of that folder if found, otherwise returns null. |
| 54 base::ListValue* FindFolder(base::ListValue* root, int id) { |
| 55 if (id == 0) // We're looking for the root folder. Assume this is it. |
| 56 return root; |
| 57 |
| 58 for (size_t i = 0; i < root->GetSize(); ++i) { |
| 59 base::DictionaryValue* item = nullptr; |
| 60 root->GetDictionary(i, &item); |
| 61 DCHECK_NE(item, (base::DictionaryValue*)nullptr); |
| 62 |
| 63 base::ListValue* children; |
| 64 if (!item->GetList(kChildren, &children)) |
| 65 continue; // Skip bookmarks. Only interested in folders. |
| 66 |
| 67 // Is this it? |
| 68 int node_id; |
| 69 if (item->GetInteger(kId, &node_id) && node_id == id) |
| 70 return children; |
| 71 |
| 72 // Recurse. |
| 73 base::ListValue* result = FindFolder(children, id); |
| 74 if (result) |
| 75 return result; |
| 76 } |
| 77 return nullptr; |
| 78 } |
| 79 |
| 80 } // namespace |
| 81 |
| 82 SupervisedUserBookmarksHandler::Folder::Folder( |
| 83 int id, const std::string& name, int parent_id) |
| 84 : id(id), name(name), parent_id(parent_id) { |
| 85 } |
| 86 |
| 87 SupervisedUserBookmarksHandler::Link::Link( |
| 88 const std::string& url, const std::string& name, int parent_id) |
| 89 : url(url), name(name), parent_id(parent_id) { |
| 90 } |
| 91 |
| 92 SupervisedUserBookmarksHandler::SupervisedUserBookmarksHandler() { |
| 93 } |
| 94 |
| 95 SupervisedUserBookmarksHandler::~SupervisedUserBookmarksHandler() { |
| 96 } |
| 97 |
| 98 scoped_ptr<base::ListValue> SupervisedUserBookmarksHandler::BuildBookmarksTree( |
| 99 const base::DictionaryValue& settings) { |
| 100 SupervisedUserBookmarksHandler handler; |
| 101 handler.ParseSettings(settings); |
| 102 return handler.BuildTree(); |
| 103 } |
| 104 |
| 105 void SupervisedUserBookmarksHandler::ParseSettings( |
| 106 const base::DictionaryValue& settings) { |
| 107 const base::DictionaryValue* folders; |
| 108 if (settings.GetDictionary(kKeyFolder, &folders)) |
| 109 ParseFolders(*folders); |
| 110 |
| 111 const base::DictionaryValue* links; |
| 112 if (settings.GetDictionary(kKeyLink, &links)) |
| 113 ParseLinks(*links); |
| 114 } |
| 115 |
| 116 void SupervisedUserBookmarksHandler::ParseFolders( |
| 117 const base::DictionaryValue& folders) { |
| 118 for (base::DictionaryValue::Iterator it(folders); !it.IsAtEnd(); |
| 119 it.Advance()) { |
| 120 int id; |
| 121 if (!ExtractId(it.key(), &id)) |
| 122 continue; |
| 123 std::string value; |
| 124 it.value().GetAsString(&value); |
| 125 std::string name; |
| 126 int parent_id; |
| 127 if (!ExtractIdAndValue(value, &parent_id, &name)) |
| 128 continue; |
| 129 folders_.push_back(Folder(id, name, parent_id)); |
| 130 } |
| 131 } |
| 132 |
| 133 void SupervisedUserBookmarksHandler::ParseLinks( |
| 134 const base::DictionaryValue& links) { |
| 135 for (base::DictionaryValue::Iterator it(links); !it.IsAtEnd(); it.Advance()) { |
| 136 std::string url; |
| 137 if (!ExtractValue(it.key(), &url)) |
| 138 continue; |
| 139 std::string value; |
| 140 it.value().GetAsString(&value); |
| 141 std::string name; |
| 142 int parent_id; |
| 143 if (!ExtractIdAndValue(value, &parent_id, &name)) |
| 144 continue; |
| 145 links_.push_back(Link(url, name, parent_id)); |
| 146 } |
| 147 } |
| 148 |
| 149 scoped_ptr<base::ListValue> SupervisedUserBookmarksHandler::BuildTree() { |
| 150 root_.reset(new base::ListValue); |
| 151 AddFoldersToTree(); |
| 152 AddLinksToTree(); |
| 153 return root_.Pass(); |
| 154 } |
| 155 |
| 156 void SupervisedUserBookmarksHandler::AddFoldersToTree() { |
| 157 // Go over all folders and try inserting them into the correct position in the |
| 158 // tree. This requires the respective parent folder to be there already. Since |
| 159 // the parent might appear later in |folders_|, we might need multiple rounds |
| 160 // until all folders can be added successfully. |
| 161 // To avoid an infinite loop in the case of a non-existing parent, we take |
| 162 // care to stop when no folders could be added in a round. |
| 163 std::vector<Folder> folders = folders_; |
| 164 std::vector<Folder> folders_failed; |
| 165 while (!folders.empty() && folders.size() != folders_failed.size()) { |
| 166 folders_failed.clear(); |
| 167 for (const auto& folder : folders) { |
| 168 scoped_ptr<base::DictionaryValue> node(new base::DictionaryValue); |
| 169 node->SetIntegerWithoutPathExpansion(kId, folder.id); |
| 170 node->SetStringWithoutPathExpansion(kName, folder.name); |
| 171 node->SetWithoutPathExpansion(kChildren, new base::ListValue); |
| 172 if (!AddNodeToTree(folder.parent_id, node.Pass())) |
| 173 folders_failed.push_back(folder); |
| 174 } |
| 175 folders.swap(folders_failed); |
| 176 } |
| 177 if (!folders_failed.empty()) { |
| 178 LOG(WARNING) << "SupervisedUserBookmarksHandler::AddFoldersToTree" |
| 179 << " failed adding the following folders (id,name,parent):"; |
| 180 for (const Folder& folder : folders_failed) { |
| 181 LOG(WARNING) << folder.id << ", " << folder.name << ", " |
| 182 << folder.parent_id; |
| 183 } |
| 184 } |
| 185 } |
| 186 |
| 187 void SupervisedUserBookmarksHandler::AddLinksToTree() { |
| 188 for (const auto& link : links_) { |
| 189 scoped_ptr<base::DictionaryValue> node(new base::DictionaryValue); |
| 190 GURL url = url_fixer::FixupURL(link.url, std::string()); |
| 191 if (!url.is_valid()) { |
| 192 LOG(WARNING) << "Got invalid URL: " << link.url; |
| 193 continue; |
| 194 } |
| 195 node->SetStringWithoutPathExpansion(kUrl, url.spec()); |
| 196 node->SetStringWithoutPathExpansion(kName, link.name); |
| 197 if (!AddNodeToTree(link.parent_id, node.Pass())) { |
| 198 LOG(WARNING) << "SupervisedUserBookmarksHandler::AddLinksToTree" |
| 199 << " failed to add link (url,name,parent): " |
| 200 << link.url << ", " << link.name << ", " << link.parent_id; |
| 201 } |
| 202 } |
| 203 } |
| 204 |
| 205 bool SupervisedUserBookmarksHandler::AddNodeToTree( |
| 206 int parent_id, |
| 207 scoped_ptr<base::DictionaryValue> node) { |
| 208 base::ListValue* parent = FindFolder(root_.get(), parent_id); |
| 209 if (!parent) |
| 210 return false; |
| 211 parent->Append(node.release()); |
| 212 return true; |
| 213 } |
OLD | NEW |