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

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 // OAuth2 scope for access to the Google+ People Search API.
45 const char kPeopleSearchOAuth2Scope[] =
46 "https://www.googleapis.com/auth/plus.peopleapi.readwrite";
47
48 // Get's the value associated with the key in the first dictionary in the list.
49 std::string GetFirstValue(const ListValue& list, const char key[]) {
50 ListValue::const_iterator it = list.begin();
51 if (it == list.end())
52 return std::string();
53
54 base::DictionaryValue* dict;
55 if (!(*it)->GetAsDictionary(&dict))
56 return std::string();
57
58 std::string value;
59 if (!dict || !dict->GetString(key, &value))
60 return std::string();
61
62 return value;
63 }
64
65 } // namespace
66
67 PeopleProvider::PeopleProvider(Profile* profile)
68 : WebserviceSearchProvider(profile),
69 people_search_url_(kPeopleSearchUrl),
70 skip_request_token_for_test_(false) {
71 oauth2_scope_.insert(kPeopleSearchOAuth2Scope);
72 }
73
74 PeopleProvider::~PeopleProvider() {}
75
76 void PeopleProvider::Start(const base::string16& query) {
77 ClearResults();
78 if (!IsValidQuery(query)) {
79 query_.clear();
80 return;
81 }
82
83 query_ = UTF16ToUTF8(query);
84 if (!people_search_) {
85 people_search_.reset(new JSONResponseFetcher(
86 base::Bind(&PeopleProvider::OnPeopleSearchFetched,
87 base::Unretained(this)),
88 profile_->GetRequestContext()));
89 }
90
91 if (!skip_request_token_for_test_) {
92 // We start with reqesting the access token. Once the token is fetched,
93 // we'll create the full query URL and fetch it.
94 StartThrottledQuery(base::Bind(&PeopleProvider::RequestAccessToken,
95 base::Unretained(this)));
96 } else {
97 // Running in a test, skip requesting the access token, straight away
98 // start our query.
99 StartThrottledQuery(base::Bind(&PeopleProvider::StartQuery,
100 base::Unretained(this)));
101 }
102 }
103
104 void PeopleProvider::Stop() {
105 if (people_search_)
106 people_search_->Stop();
107 }
108
109 void PeopleProvider::OnGetTokenSuccess(
110 const OAuth2TokenService::Request* request,
111 const std::string& access_token,
112 const base::Time& expiration_time) {
113 DCHECK_EQ(access_token_request_, request);
114 access_token_request_.reset();
115 access_token_ = access_token;
116 StartQuery();
117 }
118
119 void PeopleProvider::OnGetTokenFailure(
120 const OAuth2TokenService::Request* request,
121 const GoogleServiceAuthError& error) {
122 DCHECK_EQ(access_token_request_, request);
123 access_token_request_.reset();
124 }
125
126 void PeopleProvider::RequestAccessToken() {
127 // Only one active request at a time.
128 if (access_token_request_ != NULL)
129 return;
130
131 OAuth2TokenService* token_service =
132 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
133 access_token_request_ = token_service->StartRequest(oauth2_scope_, this);
134 }
135
136 GURL PeopleProvider::GetQueryUrl(const std::string& query) {
137 GURL people_search_url = people_search_url_;
138 people_search_url = net::AppendQueryParameter(people_search_url,
139 kAccessTokenField,
140 access_token_);
141 people_search_url = net::AppendQueryParameter(people_search_url,
142 kQueryField,
143 query);
144
145 return people_search_url;
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
175 ClearResults();
176 for (ListValue::const_iterator it = item_list->begin();
177 it != item_list->end();
178 ++it) {
179 const base::DictionaryValue* dict;
180 if (!(*it)->GetAsDictionary(&dict))
181 continue;
182
183 scoped_ptr<ChromeSearchResult> result(CreateResult(*dict));
184 if (!result)
185 continue;
186
187 Add(result.Pass());
188 }
189 }
190
191 scoped_ptr<ChromeSearchResult> PeopleProvider::CreateResult(
192 const base::DictionaryValue& dict) {
193 scoped_ptr<ChromeSearchResult> result;
194
195 std::string id;
196 if (!dict.GetString(kKeyId, &id))
197 return result.Pass();
198
199 // Get the display name.
200 const base::ListValue* names;
201 if (!dict.GetList(kKeyNames, &names))
202 return result.Pass();
203 std::string display_name;
204 display_name = GetFirstValue(*names, kKeyDisplayName);
205
206 // Get the interaction rank.
207 const base::DictionaryValue* sort_keys;
208 if (!dict.GetDictionary(kKeySortKeys, &sort_keys))
209 return result.Pass();
210 std::string interaction_rank_string;
211 if (!sort_keys->GetString(kKeyInteractionRank, &interaction_rank_string))
212 return result.Pass();
213
214 double interaction_rank;
215 if (!base::StringToDouble(interaction_rank_string, &interaction_rank))
216 return result.Pass();
217
218 // If there has been no interaction with this user, the result
219 // is meaningless, hence discard it.
220 if (interaction_rank == 0.0)
221 return result.Pass();
222
223 // Get the image URL.
224 const base::ListValue* images;
225 if (!dict.GetList(kKeyImages, &images))
226 return result.Pass();
227 std::string image_url_string;
228 image_url_string = GetFirstValue(*images, kKeyUrl);
229
230 if (id.empty() ||
231 display_name.empty() ||
232 interaction_rank_string.empty() ||
233 image_url_string.empty()) {
234 return result.Pass();
235 }
236
237 GURL image_url(image_url_string);
238 if (!image_url.is_valid())
239 return result.Pass();
240
241 result.reset(new PeopleResult(
242 profile_, id, display_name, interaction_rank, image_url));
243 return result.Pass();
244 }
245
246 void PeopleProvider::SetupForTest(
247 const base::Closure& people_search_fetched_callback,
248 const GURL& people_search_url) {
249 people_search_fetched_callback_ = people_search_fetched_callback;
250 people_search_url_ = people_search_url;
251 skip_request_token_for_test_ = true;
252 }
253
254 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698