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

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 "net/base/url_util.h"
24 #include "url/gurl.h"
25
26 namespace app_list {
27
28 namespace {
29
30 const char kKeyItems[] = "items";
31 const char kKeyId[] = "person.id";
32 const char kKeyNames[] = "person.names";
33 const char kKeyDisplayName[] = "displayName";
34 const char kKeySortKeys[] = "person.sortKeys";
35 const char kKeyInteractionRank[] = "interactionRank";
36 const char kKeyImages[] = "person.images";
37 const char kKeyUrl[] = "url";
38
39 const char kAccessTokenField[] = "access_token";
40 const char kQueryField[] = "query";
41 const char kPeopleSearchUrl[] =
42 "https://www.googleapis.com/plus/v2whitelisted/people/autocomplete";
43
44 // Get's the value associated with the key in the first dictionary in the list.
45 std::string GetFirstValue(const ListValue& list, const char key[]) {
46 ListValue::const_iterator it = list.begin();
47 if (it == list.end())
48 return std::string();
49
50 base::DictionaryValue* dict;
51 if (!(*it)->GetAsDictionary(&dict))
52 return std::string();
53
54 std::string value;
55 if (!dict || !dict->GetString(key, &value))
56 return std::string();
57
58 return value;
59 }
60
61 } // namespace
62
63 PeopleProvider::PeopleProvider(Profile* profile)
64 : WebserviceSearchProvider(profile),
65 people_search_url_(kPeopleSearchUrl),
66 skip_request_token_for_test_(false) {
67 oauth2_scope_.insert(GaiaConstants::kPeopleSearchOAuth2Scope);
zel 2013/09/05 21:27:50 no reason to have this as GaiaConstants, since it
rkc 2013/09/05 21:57:25 Done.
68 }
69
70 PeopleProvider::~PeopleProvider() {}
71
72 void PeopleProvider::Start(const base::string16& query) {
73 ClearResults();
74 if (!IsValidQuery(query)) {
75 query_.clear();
76 return;
77 }
78
79 query_ = UTF16ToUTF8(query);
80 if (!people_search_) {
81 people_search_.reset(new JSONResponseFetcher(
82 base::Bind(&PeopleProvider::OnPeopleSearchFetched,
83 base::Unretained(this)),
84 profile_->GetRequestContext()));
85 }
86
87 if (!skip_request_token_for_test_) {
88 // We start with reqesting the access token. Once the token is fetched,
89 // we'll create the full query URL and fetch it.
90 StartThrottledQuery(base::Bind(&PeopleProvider::RequestAccessToken,
91 base::Unretained(this)));
92 } else {
93 // Running in a test, skip requesting the access token, straight away
94 // start our query.
95 StartThrottledQuery(base::Bind(&PeopleProvider::StartQuery,
96 base::Unretained(this)));
97 }
98 }
99
100 void PeopleProvider::Stop() {
101 if (people_search_)
102 people_search_->Stop();
103 }
104
105 void PeopleProvider::OnGetTokenSuccess(
106 const OAuth2TokenService::Request* request,
107 const std::string& access_token,
108 const base::Time& expiration_time) {
109 DCHECK_EQ(access_token_request_, request);
110 access_token_request_.reset();
111 access_token_ = access_token;
112 StartQuery();
113 }
114
115 void PeopleProvider::OnGetTokenFailure(
116 const OAuth2TokenService::Request* request,
117 const GoogleServiceAuthError& error) {
118 DCHECK_EQ(access_token_request_, request);
119 access_token_request_.reset();
120 }
121
122 void PeopleProvider::RequestAccessToken() {
123 // Only one active request at a time.
124 if (access_token_request_ != NULL)
125 return;
126
127 OAuth2TokenService* token_service =
128 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
129 access_token_request_ = token_service->StartRequest(oauth2_scope_, this);
130 }
131
132 GURL PeopleProvider::GetQueryUrl(const std::string& query) {
133 GURL people_search_url = people_search_url_;
134 people_search_url = net::AppendQueryParameter(people_search_url,
135 kAccessTokenField,
136 access_token_);
137 people_search_url = net::AppendQueryParameter(people_search_url,
138 kQueryField,
139 query);
140
141 return people_search_url;
142 }
143
144 void PeopleProvider::StartQuery() {
145 // |query_| can be NULL when the query is scheduled but then canceled.
146 if (!people_search_ || query_.empty())
147 return;
148
149 GURL url = GetQueryUrl(query_);
150 people_search_->Start(url);
151 }
152
153 void PeopleProvider::OnPeopleSearchFetched(
154 scoped_ptr<base::DictionaryValue> json) {
155 ProcessPeopleSearchResults(json.get());
156
157 if (!people_search_fetched_callback_.is_null())
158 people_search_fetched_callback_.Run();
159 }
160
161 void PeopleProvider::ProcessPeopleSearchResults(
162 const base::DictionaryValue* json) {
163 const base::ListValue* item_list = NULL;
164 if (!json ||
165 !json->GetList(kKeyItems, &item_list) ||
166 !item_list ||
167 item_list->empty()) {
168 return;
169 }
170
171 ClearResults();
172 for (ListValue::const_iterator it = item_list->begin();
173 it != item_list->end();
174 ++it) {
175 const base::DictionaryValue* dict;
176 if (!(*it)->GetAsDictionary(&dict))
177 continue;
178
179 scoped_ptr<ChromeSearchResult> result(CreateResult(*dict));
180 if (!result)
181 continue;
182
183 Add(result.Pass());
184 }
185 }
186
187 scoped_ptr<ChromeSearchResult> PeopleProvider::CreateResult(
188 const base::DictionaryValue& dict) {
189 scoped_ptr<ChromeSearchResult> result;
190
191 std::string id;
192 if (!dict.GetString(kKeyId, &id))
193 return result.Pass();
194
195 // Get the display name.
196 const base::ListValue* names;
197 if (!dict.GetList(kKeyNames, &names))
198 return result.Pass();
199 std::string display_name;
200 display_name = GetFirstValue(*names, kKeyDisplayName);
201
202 // Get the interaction rank.
203 const base::DictionaryValue* sort_keys;
204 if (!dict.GetDictionary(kKeySortKeys, &sort_keys))
205 return result.Pass();
206 std::string interaction_rank_string;
207 if (!sort_keys->GetString(kKeyInteractionRank, &interaction_rank_string))
208 return result.Pass();
209
210 double interaction_rank;
211 if (!base::StringToDouble(interaction_rank_string, &interaction_rank))
212 return result.Pass();
213
214 // If there has been no interaction with this user, the result
215 // is meaningless, hence discard it.
216 if (interaction_rank == 0.0)
217 return result.Pass();
218
219 // Get the image URL.
220 const base::ListValue* images;
221 if (!dict.GetList(kKeyImages, &images))
222 return result.Pass();
223 std::string image_url_string;
224 image_url_string = GetFirstValue(*images, kKeyUrl);
225
226 if (id.empty() ||
227 display_name.empty() ||
228 interaction_rank_string.empty() ||
229 image_url_string.empty()) {
230 return result.Pass();
231 }
232
233 GURL image_url(image_url_string);
234 if (!image_url.is_valid())
235 return result.Pass();
236
237 result.reset(new PeopleResult(
238 profile_, id, display_name, interaction_rank, image_url));
239 return result.Pass();
240 }
241
242 void PeopleProvider::SetupForTest(
243 const base::Closure& people_search_fetched_callback,
244 const GURL& people_search_url) {
245 people_search_fetched_callback_ = people_search_fetched_callback;
246 people_search_url_ = people_search_url;
247 skip_request_token_for_test_ = true;
248 }
249
250 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698