1// Copyright 2014 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 "components/suggestions/suggestions_store.h"
6
7#include <string>
8
9#include "base/base64.h"
10#include "base/prefs/pref_service.h"
11#include "base/time/time.h"
12#include "components/pref_registry/pref_registry_syncable.h"
13#include "components/suggestions/suggestions_pref_names.h"
14
15namespace suggestions {
16
17SuggestionsStore::SuggestionsStore(PrefService* profile_prefs)
18    : pref_service_(profile_prefs) {
19  DCHECK(profile_prefs);
20}
21
22SuggestionsStore::~SuggestionsStore() {}
23
24bool SuggestionsStore::LoadSuggestions(SuggestionsProfile* suggestions) {
25  DCHECK(suggestions);
26
27  const std::string base64_suggestions_data =
28      pref_service_->GetString(prefs::kSuggestionsData);
29  if (base64_suggestions_data.empty()) {
30    suggestions->Clear();
31    return false;
32  }
33
34  // If the decode process fails, assume the pref value is corrupt and clear it.
35  std::string suggestions_data;
36  if (!base::Base64Decode(base64_suggestions_data, &suggestions_data) ||
37      !suggestions->ParseFromString(suggestions_data)) {
38    VLOG(1) << "Suggestions data in profile pref is corrupt, clearing it.";
39    suggestions->Clear();
40    ClearSuggestions();
41    return false;
42  }
43
44  // Filter expired suggestions and update the stored suggestions if at least
45  // one was filtered. Return false if all suggestions are filtered.
46  int unfiltered_size = suggestions->suggestions_size();
47  FilterExpiredSuggestions(suggestions);
48  if (suggestions->suggestions_size() != unfiltered_size) {
49    if (!suggestions->suggestions_size()) {
50      suggestions->Clear();
51      ClearSuggestions();
52      return false;
53    } else {
54      StoreSuggestions(*suggestions);
55    }
56  }
57
58  return true;
59}
60
61void SuggestionsStore::FilterExpiredSuggestions(
62    SuggestionsProfile* suggestions) {
63  SuggestionsProfile filtered_suggestions;
64  int64 now_usec = (base::Time::NowFromSystemTime() - base::Time::UnixEpoch())
65      .ToInternalValue();
66
67  for (int i = 0; i < suggestions->suggestions_size(); ++i) {
68    ChromeSuggestion* suggestion = suggestions->mutable_suggestions(i);
69    if (!suggestion->has_expiry_ts() || suggestion->expiry_ts() > now_usec) {
70      filtered_suggestions.add_suggestions()->Swap(suggestion);
71    }
72  }
73  suggestions->Swap(&filtered_suggestions);
74}
75
76bool SuggestionsStore::StoreSuggestions(const SuggestionsProfile& suggestions) {
77  std::string suggestions_data;
78  if (!suggestions.SerializeToString(&suggestions_data)) return false;
79
80  std::string base64_suggestions_data;
81  base::Base64Encode(suggestions_data, &base64_suggestions_data);
82
83  pref_service_->SetString(prefs::kSuggestionsData, base64_suggestions_data);
84  return true;
85}
86
87void SuggestionsStore::ClearSuggestions() {
88  pref_service_->ClearPref(prefs::kSuggestionsData);
89}
90
91// static
92void SuggestionsStore::RegisterProfilePrefs(
93    user_prefs::PrefRegistrySyncable* registry) {
94  registry->RegisterStringPref(
95      prefs::kSuggestionsData, std::string(),
96      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
97}
98
99}  // namespace suggestions
100