Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(541)

Side by Side Diff: chrome/browser/ui/app_list/search/people/people_provider.cc

Issue 23874015: Implement people search. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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/ui/app_list/search/people/people_provider.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/callback.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/values.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/search/search.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service.h"
19 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
20 #include "chrome/browser/ui/app_list/search/common/json_response_fetcher.h"
21 #include "chrome/browser/ui/app_list/search/people/people_result.h"
22 #include "google_apis/gaia/gaia_constants.h"
23 #include "url/gurl.h"
24
25 namespace app_list {
26
27 namespace {
28
29 const char kKeyItems[] = "items";
30 const char kKeyId[] = "person.id";
31 const char kKeyNames[] = "person.names";
32 const char kKeyDisplayName[] = "displayName";
33 const char kKeySortKeys[] = "person.sortKeys";
34 const char kKeyInteractionRank[] = "interactionRank";
35 const char kKeyImages[] = "person.images";
36 const char kKeyUrl[] = "url";
37
38 const char kAccessTokenField[] = "access_token";
39 const char kQueryField[] = "query";
40 const char kPeopleSearchUrl[] =
41 "https://www.googleapis.com/plus/v2whitelisted/people/autocomplete";
42
43 // Get's the value associated with the key in the first dictionary in the list.
44 std:: string GetFirstValue(const ListValue& list, const char key[]) {
xiyuan 2013/09/04 23:15:41 remove space after "::"
rkc 2013/09/04 23:48:02 Done.
45 ListValue::const_iterator it = list.begin();
46 if (it == list.end())
47 std::string();
xiyuan 2013/09/04 23:15:41 return std::string();
rkc 2013/09/04 23:48:02 Whoops, thanks for catching that! Done.
48
49 base::DictionaryValue* dict;
50 if (!(*it)->GetAsDictionary(&dict))
51 return std::string();;
xiyuan 2013/09/04 23:15:41 nit: nuke one ';'
rkc 2013/09/04 23:48:02 Done.
52
53 std::string value;
54 if (!dict || !dict->GetString(key, &value))
55 return std::string();
56
57 return value;
58 }
59
60 } // namespace
61
62 PeopleProvider::PeopleProvider(Profile* profile)
63 : WebserviceSearchProvider(profile),
64 people_search_url_(kPeopleSearchUrl),
65 running_as_test_(false) {
66 oauth2_scope_.insert(GaiaConstants::kPeopleSearchOAuth2Scope);
67 }
68
69 PeopleProvider::~PeopleProvider() {}
70
71 void PeopleProvider::Start(const base::string16& query) {
72 ClearResults();
73 if (!IsValidQuery(query)) {
74 query_.clear();
75 return;
76 }
77
78 query_ = UTF16ToUTF8(query);
79 if (!people_search_) {
80 people_search_.reset(new JSONResponseFetcher(
81 base::Bind(&PeopleProvider::OnPeopleSearchFetched,
82 base::Unretained(this)),
83 profile_->GetRequestContext()));
84 }
85
86 if (!running_as_test_) {
87 // We start with reqesting the access token. Once the token is fetched,
88 // we'll create the full query URL and fetch it.
89 StartThrottledQuery(base::Bind(&PeopleProvider::RequestAccessToken,
xiyuan 2013/09/04 23:15:41 Is it possible to reuse the previously fetched |ac
rkc 2013/09/04 23:48:02 Possibly, but it seemed cleaner to re-request the
90 base::Unretained(this)));
91 } else {
92 // Running in a test, skip requesting the access token, straight away
93 // start our query.
94 StartThrottledQuery(base::Bind(&PeopleProvider::StartQuery,
95 base::Unretained(this)));
96 }
97 }
98
99 void PeopleProvider::Stop() {
100 if (people_search_)
101 people_search_->Stop();
102 }
103
104 void PeopleProvider::OnGetTokenSuccess(
105 const OAuth2TokenService::Request* request,
106 const std::string& access_token,
107 const base::Time& expiration_time) {
108 DCHECK_EQ(access_token_request_, request);
109 access_token_request_.reset();
110 access_token_ = access_token;
111 StartQuery();
112 }
113
114 void PeopleProvider::OnGetTokenFailure(
115 const OAuth2TokenService::Request* request,
116 const GoogleServiceAuthError& error) {
117 DCHECK_EQ(access_token_request_, request);
118 access_token_request_.reset();
119 }
120
121 void PeopleProvider::RequestAccessToken() {
122 // Only one active request at a time.
123 if (access_token_request_ != NULL)
124 return;
125
126 OAuth2TokenService* token_service =
127 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
128 access_token_request_ = token_service->StartRequest(oauth2_scope_, this);
129 }
130
131 void PeopleProvider::InvalidateToken() {
xiyuan 2013/09/04 23:15:41 This seems not used.
rkc 2013/09/04 23:48:02 Removed. Added a TODO to JSONRepsonseFetcher to al
132 OAuth2TokenService* token_service =
133 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
134 DCHECK(token_service);
135 token_service->InvalidateToken(oauth2_scope_, access_token_);
136 access_token_.clear();
137 }
138
139 GURL PeopleProvider::GetQueryUrl(const std::string& query) {
140 std::string access_token_pair = std::string(kAccessTokenField) +
141 "=" + access_token_;
142 std::string query_pair = std::string(kQueryField) + "=" + query;
143
144 return GURL(std::string(people_search_url_) +
145 "?" + access_token_pair + "&" + query_pair);
xiyuan 2013/09/04 23:15:41 Use net::AppendQueryParameter to construct URL pro
rkc 2013/09/04 23:48:02 Done.
146 }
147
148 void PeopleProvider::StartQuery() {
149 // |query_| can be NULL when the query is scheduled but then canceled.
150 if (!people_search_ || query_.empty())
151 return;
152
153 GURL url = GetQueryUrl(query_);
154 people_search_->Start(url);
155 }
156
157 void PeopleProvider::OnPeopleSearchFetched(
158 scoped_ptr<base::DictionaryValue> json) {
159 ProcessPeopleSearchResults(json.get());
160
161 if (!people_search_fetched_callback_.is_null())
162 people_search_fetched_callback_.Run();
163 }
164
165 void PeopleProvider::ProcessPeopleSearchResults(
166 const base::DictionaryValue* json) {
167 const base::ListValue* item_list = NULL;
168 if (!json ||
169 !json->GetList(kKeyItems, &item_list) ||
170 !item_list ||
171 item_list->empty()) {
172 return;
173 }
174
xiyuan 2013/09/04 23:15:41 ClearResults(); to remove existing results from pr
rkc 2013/09/04 23:48:02 Done.
175 for (ListValue::const_iterator it = item_list->begin();
176 it != item_list->end();
177 ++it) {
178 const base::DictionaryValue* dict;
179 if (!(*it)->GetAsDictionary(&dict))
180 continue;
181
182 scoped_ptr<ChromeSearchResult> result(CreateResult(*dict));
183 if (!result)
184 continue;
185
186 Add(result.Pass());
187 }
188 }
189
190 scoped_ptr<ChromeSearchResult> PeopleProvider::CreateResult(
191 const base::DictionaryValue& dict) {
192 scoped_ptr<ChromeSearchResult> result;
193
194 std::string id;
195 if (!dict.GetString(kKeyId, &id))
196 return result.Pass();
197
198 // Get the display name.
199 const base::ListValue* names;
200 if (!dict.GetList(kKeyNames, &names))
201 return result.Pass();
202 std::string display_name;
203 display_name = GetFirstValue(*names, kKeyDisplayName);
204
205 // Get the interaction rank.
206 const base::DictionaryValue* sort_keys;
207 if (!dict.GetDictionary(kKeySortKeys, &sort_keys))
208 return result.Pass();
209 std::string interaction_rank_string;
210 if (!sort_keys->GetString(kKeyInteractionRank, &interaction_rank_string))
211 return result.Pass();
212
213 double interaction_rank;
214 if (!base::StringToDouble(interaction_rank_string, &interaction_rank))
215 return result.Pass();
216
217 // If there has been no interaction with this user, the result
218 // is meaningless, hence discard it.
219 if (interaction_rank == 0.0)
220 return result.Pass();
221
222 // Get the image URL.
223 const base::ListValue* images;
224 if (!dict.GetList(kKeyImages, &images))
225 return result.Pass();
226 std::string image_url_string;
227 image_url_string = GetFirstValue(*images, kKeyUrl);
228
229 if (id.empty() ||
230 display_name.empty() ||
231 interaction_rank_string.empty() ||
232 image_url_string.empty()) {
233 return result.Pass();
234 }
235
236 GURL image_url(image_url_string);
237 if (!image_url.is_valid())
238 return result.Pass();
239
240 result.reset(new PeopleResult(
241 profile_, id, display_name, interaction_rank, image_url));
242 return result.Pass();
243 }
244
245 void PeopleProvider::SetupForTest(
246 const base::Closure& people_search_fetched_callback,
247 const std::string& people_search_url) {
248 people_search_fetched_callback_ = people_search_fetched_callback;
249 people_search_url_ = people_search_url;
250 running_as_test_ = true;
251 }
252
253 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698