Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/ntp_snippets/remote/remote_suggestion.h" | 5 #include "components/ntp_snippets/remote/remote_suggestion.h" |
| 6 | 6 |
| 7 #include "base/feature_list.h" | 7 #include "base/feature_list.h" |
| 8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
| 9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "base/time/time.h" | |
|
Marc Treib
2017/02/10 16:16:56
nit: not required, it's already included in the he
markusheintz_
2017/02/13 09:59:55
Done.
| |
| 12 #include "base/values.h" | 13 #include "base/values.h" |
| 13 #include "components/ntp_snippets/category.h" | 14 #include "components/ntp_snippets/category.h" |
| 14 #include "components/ntp_snippets/features.h" | 15 #include "components/ntp_snippets/features.h" |
| 15 #include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h" | 16 #include "components/ntp_snippets/remote/proto/ntp_snippets.pb.h" |
| 16 | 17 |
| 17 namespace { | 18 namespace { |
| 18 | 19 |
| 19 struct SnippetSource { | 20 struct SnippetSource { |
| 20 SnippetSource(const GURL& url, | 21 SnippetSource(const GURL& url, |
| 21 const std::string& publisher_name, | 22 const std::string& publisher_name, |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 score_(0), | 90 score_(0), |
| 90 is_dismissed_(false), | 91 is_dismissed_(false), |
| 91 remote_category_id_(remote_category_id), | 92 remote_category_id_(remote_category_id), |
| 92 should_notify_(false) {} | 93 should_notify_(false) {} |
| 93 | 94 |
| 94 RemoteSuggestion::~RemoteSuggestion() = default; | 95 RemoteSuggestion::~RemoteSuggestion() = default; |
| 95 | 96 |
| 96 // static | 97 // static |
| 97 std::unique_ptr<RemoteSuggestion> | 98 std::unique_ptr<RemoteSuggestion> |
| 98 RemoteSuggestion::CreateFromChromeReaderDictionary( | 99 RemoteSuggestion::CreateFromChromeReaderDictionary( |
| 99 const base::DictionaryValue& dict) { | 100 const base::DictionaryValue& dict, |
| 101 const base::Time& fetch_time) { | |
| 100 const base::DictionaryValue* content = nullptr; | 102 const base::DictionaryValue* content = nullptr; |
| 101 if (!dict.GetDictionary("contentInfo", &content)) { | 103 if (!dict.GetDictionary("contentInfo", &content)) { |
| 102 return nullptr; | 104 return nullptr; |
| 103 } | 105 } |
| 104 | 106 |
| 105 // Need at least a primary id. | 107 // Need at least a primary id. |
| 106 std::string primary_id; | 108 std::string primary_id; |
| 107 if (!content->GetString("url", &primary_id) || primary_id.empty()) { | 109 if (!content->GetString("url", &primary_id) || primary_id.empty()) { |
| 108 return nullptr; | 110 return nullptr; |
| 109 } | 111 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 160 // this for the primary ID). | 162 // this for the primary ID). |
| 161 ids.push_back(corpus_id_str); | 163 ids.push_back(corpus_id_str); |
| 162 } | 164 } |
| 163 if (sources.empty()) { | 165 if (sources.empty()) { |
| 164 DLOG(WARNING) << "No sources found for article " << primary_id; | 166 DLOG(WARNING) << "No sources found for article " << primary_id; |
| 165 return nullptr; | 167 return nullptr; |
| 166 } | 168 } |
| 167 | 169 |
| 168 std::unique_ptr<RemoteSuggestion> snippet( | 170 std::unique_ptr<RemoteSuggestion> snippet( |
| 169 new RemoteSuggestion(ids, kArticlesRemoteId)); | 171 new RemoteSuggestion(ids, kArticlesRemoteId)); |
| 172 snippet->fetch_time_ = fetch_time; | |
| 170 | 173 |
| 171 std::string title; | 174 std::string title; |
| 172 if (content->GetString("title", &title)) { | 175 if (content->GetString("title", &title)) { |
| 173 snippet->title_ = title; | 176 snippet->title_ = title; |
| 174 } | 177 } |
| 175 std::string salient_image_url; | 178 std::string salient_image_url; |
| 176 if (content->GetString("thumbnailUrl", &salient_image_url)) { | 179 if (content->GetString("thumbnailUrl", &salient_image_url)) { |
| 177 snippet->salient_image_url_ = GURL(salient_image_url); | 180 snippet->salient_image_url_ = GURL(salient_image_url); |
| 178 } | 181 } |
| 179 std::string snippet_str; | 182 std::string snippet_str; |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 210 snippet->score_ = score; | 213 snippet->score_ = score; |
| 211 } | 214 } |
| 212 | 215 |
| 213 return snippet; | 216 return snippet; |
| 214 } | 217 } |
| 215 | 218 |
| 216 // static | 219 // static |
| 217 std::unique_ptr<RemoteSuggestion> | 220 std::unique_ptr<RemoteSuggestion> |
| 218 RemoteSuggestion::CreateFromContentSuggestionsDictionary( | 221 RemoteSuggestion::CreateFromContentSuggestionsDictionary( |
| 219 const base::DictionaryValue& dict, | 222 const base::DictionaryValue& dict, |
| 220 int remote_category_id) { | 223 int remote_category_id, |
| 224 const base::Time& fetch_time) { | |
| 221 const base::ListValue* ids; | 225 const base::ListValue* ids; |
| 222 if (!dict.GetList("ids", &ids)) { | 226 if (!dict.GetList("ids", &ids)) { |
| 223 return nullptr; | 227 return nullptr; |
| 224 } | 228 } |
| 225 std::vector<std::string> parsed_ids; | 229 std::vector<std::string> parsed_ids; |
| 226 for (const auto& value : *ids) { | 230 for (const auto& value : *ids) { |
| 227 std::string id; | 231 std::string id; |
| 228 if (!value->GetAsString(&id)) { | 232 if (!value->GetAsString(&id)) { |
| 229 return nullptr; | 233 return nullptr; |
| 230 } | 234 } |
| 231 parsed_ids.push_back(id); | 235 parsed_ids.push_back(id); |
| 232 } | 236 } |
| 233 | 237 |
| 234 if (parsed_ids.empty()) { | 238 if (parsed_ids.empty()) { |
| 235 return nullptr; | 239 return nullptr; |
| 236 } | 240 } |
| 237 auto snippet = MakeUnique(parsed_ids, remote_category_id); | 241 auto snippet = MakeUnique(parsed_ids, remote_category_id); |
| 242 snippet->fetch_time_ = fetch_time; | |
| 238 | 243 |
| 239 if (!(dict.GetString("title", &snippet->title_) && | 244 if (!(dict.GetString("title", &snippet->title_) && |
| 240 dict.GetString("snippet", &snippet->snippet_) && | 245 dict.GetString("snippet", &snippet->snippet_) && |
| 241 GetTimeValue(dict, "creationTime", &snippet->publish_date_) && | 246 GetTimeValue(dict, "creationTime", &snippet->publish_date_) && |
| 242 GetTimeValue(dict, "expirationTime", &snippet->expiry_date_) && | 247 GetTimeValue(dict, "expirationTime", &snippet->expiry_date_) && |
| 243 GetURLValue(dict, "imageUrl", &snippet->salient_image_url_) && | 248 GetURLValue(dict, "imageUrl", &snippet->salient_image_url_) && |
| 244 dict.GetString("attribution", &snippet->publisher_name_) && | 249 dict.GetString("attribution", &snippet->publisher_name_) && |
| 245 GetURLValue(dict, "fullPageUrl", &snippet->url_))) { | 250 GetURLValue(dict, "fullPageUrl", &snippet->url_))) { |
| 246 return nullptr; | 251 return nullptr; |
| 247 } | 252 } |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 274 // Need at least the id. | 279 // Need at least the id. |
| 275 if (proto.ids_size() == 0 || proto.ids(0).empty()) { | 280 if (proto.ids_size() == 0 || proto.ids(0).empty()) { |
| 276 return nullptr; | 281 return nullptr; |
| 277 } | 282 } |
| 278 | 283 |
| 279 int remote_category_id = proto.has_remote_category_id() | 284 int remote_category_id = proto.has_remote_category_id() |
| 280 ? proto.remote_category_id() | 285 ? proto.remote_category_id() |
| 281 : kArticlesRemoteId; | 286 : kArticlesRemoteId; |
| 282 | 287 |
| 283 std::vector<std::string> ids(proto.ids().begin(), proto.ids().end()); | 288 std::vector<std::string> ids(proto.ids().begin(), proto.ids().end()); |
| 289 | |
| 284 auto snippet = MakeUnique(ids, remote_category_id); | 290 auto snippet = MakeUnique(ids, remote_category_id); |
| 285 | 291 |
| 286 snippet->title_ = proto.title(); | 292 snippet->title_ = proto.title(); |
| 287 snippet->snippet_ = proto.snippet(); | 293 snippet->snippet_ = proto.snippet(); |
| 288 snippet->salient_image_url_ = GURL(proto.salient_image_url()); | 294 snippet->salient_image_url_ = GURL(proto.salient_image_url()); |
| 289 snippet->publish_date_ = base::Time::FromInternalValue(proto.publish_date()); | 295 snippet->publish_date_ = base::Time::FromInternalValue(proto.publish_date()); |
| 290 snippet->expiry_date_ = base::Time::FromInternalValue(proto.expiry_date()); | 296 snippet->expiry_date_ = base::Time::FromInternalValue(proto.expiry_date()); |
| 291 snippet->score_ = proto.score(); | 297 snippet->score_ = proto.score(); |
| 292 snippet->is_dismissed_ = proto.dismissed(); | 298 snippet->is_dismissed_ = proto.dismissed(); |
| 293 | 299 |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 312 | 318 |
| 313 if (sources.empty()) { | 319 if (sources.empty()) { |
| 314 DLOG(WARNING) << "No sources found for article " << snippet->id(); | 320 DLOG(WARNING) << "No sources found for article " << snippet->id(); |
| 315 return nullptr; | 321 return nullptr; |
| 316 } | 322 } |
| 317 const SnippetSource& source = FindBestSource(sources); | 323 const SnippetSource& source = FindBestSource(sources); |
| 318 snippet->url_ = source.url; | 324 snippet->url_ = source.url; |
| 319 snippet->publisher_name_ = source.publisher_name; | 325 snippet->publisher_name_ = source.publisher_name; |
| 320 snippet->amp_url_ = source.amp_url; | 326 snippet->amp_url_ = source.amp_url; |
| 321 | 327 |
| 328 if (proto.has_fetch_time()) { | |
| 329 snippet->fetch_time_ = base::Time::FromInternalValue(proto.fetch_time()); | |
| 330 } | |
| 331 | |
| 322 return snippet; | 332 return snippet; |
| 323 } | 333 } |
| 324 | 334 |
| 325 // static | 335 // static |
| 326 std::unique_ptr<RemoteSuggestion> RemoteSuggestion::CreateForTesting( | 336 std::unique_ptr<RemoteSuggestion> RemoteSuggestion::CreateForTesting( |
| 327 const std::string& id, | 337 const std::string& id, |
| 328 int remote_category_id, | 338 int remote_category_id, |
| 329 const GURL& url, | 339 const GURL& url, |
| 330 const std::string& publisher_name, | 340 const std::string& publisher_name, |
| 331 const GURL& amp_url) { | 341 const GURL& amp_url) { |
| 342 // TODO(markusheintz): | |
|
jkrcal
2017/02/10 16:14:42
can you please fill in the todo?
Marc Treib
2017/02/10 16:16:56
?
markusheintz_
2017/02/13 09:59:55
sorry forgot to remove :-(
Removed now.
| |
| 332 auto snippet = | 343 auto snippet = |
| 333 MakeUnique(std::vector<std::string>(1, id), remote_category_id); | 344 MakeUnique(std::vector<std::string>(1, id), remote_category_id); |
| 334 snippet->url_ = url; | 345 snippet->url_ = url; |
| 335 snippet->publisher_name_ = publisher_name; | 346 snippet->publisher_name_ = publisher_name; |
| 336 snippet->amp_url_ = amp_url; | 347 snippet->amp_url_ = amp_url; |
| 337 | 348 |
| 338 return snippet; | 349 return snippet; |
| 339 } | 350 } |
| 340 | 351 |
| 341 SnippetProto RemoteSuggestion::ToProto() const { | 352 SnippetProto RemoteSuggestion::ToProto() const { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 364 | 375 |
| 365 SnippetSourceProto* source_proto = result.add_sources(); | 376 SnippetSourceProto* source_proto = result.add_sources(); |
| 366 source_proto->set_url(url_.spec()); | 377 source_proto->set_url(url_.spec()); |
| 367 if (!publisher_name_.empty()) { | 378 if (!publisher_name_.empty()) { |
| 368 source_proto->set_publisher_name(publisher_name_); | 379 source_proto->set_publisher_name(publisher_name_); |
| 369 } | 380 } |
| 370 if (amp_url_.is_valid()) { | 381 if (amp_url_.is_valid()) { |
| 371 source_proto->set_amp_url(amp_url_.spec()); | 382 source_proto->set_amp_url(amp_url_.spec()); |
| 372 } | 383 } |
| 373 | 384 |
| 385 if (!fetch_time_.is_null()) { | |
| 386 result.set_fetch_time(fetch_time_.ToInternalValue()); | |
| 387 } | |
| 374 return result; | 388 return result; |
| 375 } | 389 } |
| 376 | 390 |
| 377 ContentSuggestion RemoteSuggestion::ToContentSuggestion( | 391 ContentSuggestion RemoteSuggestion::ToContentSuggestion( |
| 378 Category category) const { | 392 Category category) const { |
| 379 GURL url = url_; | 393 GURL url = url_; |
| 380 if (base::FeatureList::IsEnabled(kPreferAmpUrlsFeature) && | 394 if (base::FeatureList::IsEnabled(kPreferAmpUrlsFeature) && |
| 381 !amp_url_.is_empty()) { | 395 !amp_url_.is_empty()) { |
| 382 url = amp_url_; | 396 url = amp_url_; |
| 383 } | 397 } |
| 384 ContentSuggestion suggestion(category, id(), url); | 398 ContentSuggestion suggestion(category, id(), url); |
| 385 suggestion.set_title(base::UTF8ToUTF16(title_)); | 399 suggestion.set_title(base::UTF8ToUTF16(title_)); |
| 386 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet_)); | 400 suggestion.set_snippet_text(base::UTF8ToUTF16(snippet_)); |
| 387 suggestion.set_publish_date(publish_date_); | 401 suggestion.set_publish_date(publish_date_); |
| 388 suggestion.set_publisher_name(base::UTF8ToUTF16(publisher_name_)); | 402 suggestion.set_publisher_name(base::UTF8ToUTF16(publisher_name_)); |
| 389 suggestion.set_score(score_); | 403 suggestion.set_score(score_); |
| 390 if (should_notify_) { | 404 if (should_notify_) { |
| 391 NotificationExtra extra; | 405 NotificationExtra extra; |
| 392 extra.deadline = notification_deadline_; | 406 extra.deadline = notification_deadline_; |
| 393 suggestion.set_notification_extra( | 407 suggestion.set_notification_extra( |
| 394 base::MakeUnique<NotificationExtra>(extra)); | 408 base::MakeUnique<NotificationExtra>(extra)); |
| 395 } | 409 } |
| 410 suggestion.set_fetch_time(fetch_time_); | |
| 396 return suggestion; | 411 return suggestion; |
| 397 } | 412 } |
| 398 | 413 |
| 399 // static | 414 // static |
| 400 base::Time RemoteSuggestion::TimeFromJsonString( | 415 base::Time RemoteSuggestion::TimeFromJsonString( |
| 401 const std::string& timestamp_str) { | 416 const std::string& timestamp_str) { |
| 402 int64_t timestamp; | 417 int64_t timestamp; |
| 403 if (!base::StringToInt64(timestamp_str, ×tamp)) { | 418 if (!base::StringToInt64(timestamp_str, ×tamp)) { |
| 404 // Even if there's an error in the conversion, some garbage data may still | 419 // Even if there's an error in the conversion, some garbage data may still |
| 405 // be written to the output var, so reset it. | 420 // be written to the output var, so reset it. |
| 406 DLOG(WARNING) << "Invalid json timestamp: " << timestamp_str; | 421 DLOG(WARNING) << "Invalid json timestamp: " << timestamp_str; |
| 407 timestamp = 0; | 422 timestamp = 0; |
| 408 } | 423 } |
| 409 return base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(timestamp); | 424 return base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(timestamp); |
| 410 } | 425 } |
| 411 | 426 |
| 412 // static | 427 // static |
| 413 std::string RemoteSuggestion::TimeToJsonString(const base::Time& time) { | 428 std::string RemoteSuggestion::TimeToJsonString(const base::Time& time) { |
| 414 return base::Int64ToString((time - base::Time::UnixEpoch()).InSeconds()); | 429 return base::Int64ToString((time - base::Time::UnixEpoch()).InSeconds()); |
| 415 } | 430 } |
| 416 | 431 |
| 417 // static | 432 // static |
| 418 std::unique_ptr<RemoteSuggestion> RemoteSuggestion::MakeUnique( | 433 std::unique_ptr<RemoteSuggestion> RemoteSuggestion::MakeUnique( |
| 419 const std::vector<std::string>& ids, | 434 const std::vector<std::string>& ids, |
| 420 int remote_category_id) { | 435 int remote_category_id) { |
| 421 return base::WrapUnique(new RemoteSuggestion(ids, remote_category_id)); | 436 return base::WrapUnique(new RemoteSuggestion(ids, remote_category_id)); |
| 422 } | 437 } |
| 423 | 438 |
| 424 } // namespace ntp_snippets | 439 } // namespace ntp_snippets |
| OLD | NEW |