Skip to content

Commit c8affee

Browse files
committed
Notes support for email aliases.
1 parent 543ee41 commit c8affee

File tree

10 files changed

+412
-45
lines changed

10 files changed

+412
-45
lines changed

components/email_aliases/BUILD.gn

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ static_library("service") {
4141
"email_aliases_auth.cc",
4242
"email_aliases_auth.h",
4343
"email_aliases_endpoints.h",
44+
"email_aliases_notes.cc",
45+
"email_aliases_notes.h",
4446
"email_aliases_service.cc",
4547
"email_aliases_service.h",
4648
]
@@ -82,7 +84,10 @@ source_set("test_utils") {
8284

8385
source_set("unit_tests") {
8486
testonly = true
85-
sources = [ "email_aliases_service_unittest.cc" ]
87+
sources = [
88+
"email_aliases_notes_unittest.cc",
89+
"email_aliases_service_unittest.cc",
90+
]
8691
deps = [
8792
":features",
8893
":service",

components/email_aliases/email_aliases.mojom

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ struct Alias {
3030
array<string>? domains;
3131
};
3232

33+
struct AliasUpdateData {
34+
// Change the alias's status: active/inactive
35+
bool? active;
36+
// Change the alias's note
37+
string? note;
38+
// Change domains list where aliase is used
39+
array<string>? domains;
40+
};
41+
3342
// Observer for change in email aliases state
3443
interface EmailAliasesServiceObserver {
3544

@@ -47,7 +56,7 @@ interface EmailAliasesService {
4756
GenerateAlias() => result<string, string>;
4857

4958
// Create or Update an existing email alias.
50-
UpdateAlias(string alias_email, string? note) =>
59+
UpdateAlias(string alias_email, AliasUpdateData update_data) =>
5160
result<mojo_base.mojom.Empty, string>;
5261

5362
// Delete an email alias.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/* Copyright (c) 2025 The Brave Authors. All rights reserved.
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
* You can obtain one at https://mozilla.org/MPL/2.0/. */
5+
6+
#include "brave/components/email_aliases/email_aliases_notes.h"
7+
8+
#include "base/check.h"
9+
#include "components/prefs/pref_registry_simple.h"
10+
#include "components/prefs/pref_service.h"
11+
#include "components/prefs/scoped_user_pref_update.h"
12+
13+
namespace email_aliases {
14+
15+
EmailAliasesNotes::EmailAliasesNotes(PrefService* pref_service,
16+
const std::string& primary_email)
17+
: pref_service_(pref_service), primary_email_(primary_email) {
18+
CHECK(pref_service_);
19+
}
20+
21+
EmailAliasesNotes::~EmailAliasesNotes() = default;
22+
23+
// static
24+
void EmailAliasesNotes::RegisterProfilePrefs(PrefRegistrySimple* registry) {
25+
registry->RegisterDictionaryPref(prefs::kEmailAliasesNotes);
26+
}
27+
28+
std::optional<std::string> EmailAliasesNotes::GetNote(
29+
const std::string& alias) {
30+
const auto& pref = pref_service_->GetDict(prefs::kEmailAliasesNotes);
31+
const auto* aliases = pref.FindDict(primary_email_);
32+
if (!aliases) {
33+
return std::nullopt;
34+
}
35+
36+
if (const auto* note = aliases->FindString(alias)) {
37+
return *note;
38+
}
39+
return std::nullopt;
40+
}
41+
42+
void EmailAliasesNotes::UpdateNote(const std::string& alias,
43+
const std::string& note) {
44+
ScopedDictPrefUpdate update(pref_service_.get(), prefs::kEmailAliasesNotes);
45+
auto& aliases = update.Get();
46+
if (note.empty()) {
47+
if (auto* notes = aliases.FindDict(primary_email_)) {
48+
notes->Remove(alias);
49+
}
50+
} else {
51+
auto* notes = aliases.EnsureDict(primary_email_);
52+
notes->Set(alias, note);
53+
}
54+
}
55+
56+
void EmailAliasesNotes::RemoveNote(const std::string& alias) {
57+
UpdateNote(alias, {});
58+
}
59+
60+
void EmailAliasesNotes::RemoveInactiveNotes(
61+
const std::vector<AliasListEntry>& active_aliases) {
62+
base::Value::Dict notes;
63+
for (const auto& alias : active_aliases) {
64+
if (alias.status != "active") {
65+
continue;
66+
}
67+
if (auto note = GetNote(alias.alias)) {
68+
notes.Set(alias.alias, std::move(note).value());
69+
}
70+
}
71+
// Set only notes for active aliases.
72+
ScopedDictPrefUpdate update(pref_service_.get(), prefs::kEmailAliasesNotes);
73+
if (notes.empty()) {
74+
update->Remove(primary_email_);
75+
} else {
76+
update->Set(primary_email_, std::move(notes));
77+
}
78+
}
79+
80+
} // namespace email_aliases
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* Copyright (c) 2025 The Brave Authors. All rights reserved.
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
* You can obtain one at https://mozilla.org/MPL/2.0/. */
5+
6+
#ifndef BRAVE_COMPONENTS_EMAIL_ALIASES_EMAIL_ALIASES_NOTES_H_
7+
#define BRAVE_COMPONENTS_EMAIL_ALIASES_EMAIL_ALIASES_NOTES_H_
8+
9+
#include <optional>
10+
#include <string>
11+
#include <vector>
12+
13+
#include "base/memory/raw_ptr.h"
14+
#include "brave/components/email_aliases/email_aliases_api.h"
15+
16+
class PrefRegistrySimple;
17+
class PrefService;
18+
19+
namespace email_aliases {
20+
21+
namespace prefs {
22+
23+
inline constexpr char kEmailAliasesNotes[] = "brave.email_alises_notes";
24+
25+
}
26+
27+
class EmailAliasesNotes {
28+
public:
29+
EmailAliasesNotes(PrefService* pref_service,
30+
const std::string& primary_email);
31+
~EmailAliasesNotes();
32+
33+
static void RegisterProfilePrefs(PrefRegistrySimple* registry);
34+
35+
std::optional<std::string> GetNote(const std::string& alias);
36+
void UpdateNote(const std::string& alias, const std::string& notes);
37+
void RemoveNote(const std::string& alias);
38+
void RemoveInactiveNotes(const std::vector<AliasListEntry>& active_aliases);
39+
40+
private:
41+
const raw_ptr<PrefService> pref_service_ = nullptr;
42+
const std::string primary_email_;
43+
};
44+
45+
} // namespace email_aliases
46+
47+
#endif // BRAVE_COMPONENTS_EMAIL_ALIASES_EMAIL_ALIASES_NOTES_H_
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/* Copyright (c) 2025 The Brave Authors. All rights reserved.
2+
* This Source Code Form is subject to the terms of the Mozilla Public
3+
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
* You can obtain one at https://mozilla.org/MPL/2.0/. */
5+
6+
#include "brave/components/email_aliases/email_aliases_notes.h"
7+
8+
#include "base/values.h"
9+
#include "components/prefs/testing_pref_service.h"
10+
#include "testing/gtest/include/gtest/gtest.h"
11+
12+
namespace email_aliases {
13+
14+
namespace {
15+
struct AliasNote {
16+
std::string alias;
17+
std::string note;
18+
};
19+
20+
} // namespace
21+
22+
class EmailAliasesNotesTest : public ::testing::Test {
23+
public:
24+
EmailAliasesNotesTest() {
25+
EmailAliasesNotes::RegisterProfilePrefs(prefs_.registry());
26+
}
27+
~EmailAliasesNotesTest() override = default;
28+
29+
PrefService* GetPrefs() { return &prefs_; }
30+
31+
base::DictValue CreateNotes(const std::vector<AliasNote>& notes) {
32+
base::DictValue v;
33+
for (const auto& note : notes) {
34+
v.Set(note.alias, note.note);
35+
}
36+
return v;
37+
}
38+
39+
std::vector<AliasListEntry> CreateAliases(
40+
const std::vector<std::string>& aliases) {
41+
std::vector<AliasListEntry> r;
42+
for (const auto& a : aliases) {
43+
AliasListEntry e;
44+
e.alias = a;
45+
e.status = "active";
46+
r.push_back(std::move(e));
47+
}
48+
return r;
49+
}
50+
51+
private:
52+
TestingPrefServiceSimple prefs_;
53+
};
54+
55+
TEST_F(EmailAliasesNotesTest, InitAndRemoveInactive) {
56+
base::DictValue notes;
57+
notes.Set("a@prima.ry", CreateNotes({{"alias1", "note1"},
58+
{"alias2", "note2"},
59+
{"alias3", "note3"}}));
60+
notes.Set("b@prima.ry", CreateNotes({{"alias1", "note1"},
61+
{"alias2", "note2"},
62+
{"alias3", "note3"}}));
63+
notes.Set("c@prima.ry", CreateNotes({{"alias1", "note1"},
64+
{"alias2", "note2"},
65+
{"alias3", "note3"}}));
66+
GetPrefs()->SetDict(prefs::kEmailAliasesNotes, std::move(notes));
67+
68+
{
69+
EmailAliasesNotes email_aliases_notes(GetPrefs(), "a@prima.ry");
70+
// No active aliases for `a@primay.ry`
71+
email_aliases_notes.RemoveInactiveNotes({});
72+
EXPECT_EQ(2u, GetPrefs()->GetDict(prefs::kEmailAliasesNotes).size());
73+
EXPECT_EQ(std::nullopt, email_aliases_notes.GetNote("alias1"));
74+
}
75+
76+
{
77+
EmailAliasesNotes email_aliases_notes(GetPrefs(), "b@prima.ry");
78+
email_aliases_notes.RemoveInactiveNotes(
79+
CreateAliases({"alias1", "alias3"}));
80+
EXPECT_EQ(2u, GetPrefs()->GetDict(prefs::kEmailAliasesNotes).size());
81+
EXPECT_EQ(2u, GetPrefs()
82+
->GetDict(prefs::kEmailAliasesNotes)
83+
.FindDict("b@prima.ry")
84+
->size());
85+
EXPECT_EQ("note1", email_aliases_notes.GetNote("alias1"));
86+
EXPECT_EQ(std::nullopt, email_aliases_notes.GetNote("alias2"));
87+
EXPECT_EQ("note3", email_aliases_notes.GetNote("alias3"));
88+
}
89+
{
90+
EmailAliasesNotes email_aliases_notes(GetPrefs(), "c@prima.ry");
91+
email_aliases_notes.RemoveInactiveNotes(
92+
CreateAliases({"alias1", "alias2", "alias3"}));
93+
EXPECT_EQ(2u, GetPrefs()->GetDict(prefs::kEmailAliasesNotes).size());
94+
EXPECT_EQ(3u, GetPrefs()
95+
->GetDict(prefs::kEmailAliasesNotes)
96+
.FindDict("c@prima.ry")
97+
->size());
98+
EXPECT_EQ("note1", email_aliases_notes.GetNote("alias1"));
99+
EXPECT_EQ("note2", email_aliases_notes.GetNote("alias2"));
100+
EXPECT_EQ("note3", email_aliases_notes.GetNote("alias3"));
101+
}
102+
}
103+
104+
TEST_F(EmailAliasesNotesTest, Update) {
105+
base::DictValue notes;
106+
notes.Set("a@prima.ry", CreateNotes({{"alias1", "note1"},
107+
{"alias2", "note2"},
108+
{"alias3", "note3"}}));
109+
GetPrefs()->SetDict(prefs::kEmailAliasesNotes, std::move(notes));
110+
111+
EmailAliasesNotes email_aliases_notes(GetPrefs(), "a@prima.ry");
112+
113+
email_aliases_notes.UpdateNote("alias1", "updated1");
114+
email_aliases_notes.UpdateNote("alias2", "updated2");
115+
email_aliases_notes.UpdateNote("alias3", "updated3");
116+
email_aliases_notes.UpdateNote("alias4", "updated4");
117+
118+
EXPECT_EQ("updated1", email_aliases_notes.GetNote("alias1"));
119+
EXPECT_EQ("updated2", email_aliases_notes.GetNote("alias2"));
120+
EXPECT_EQ("updated3", email_aliases_notes.GetNote("alias3"));
121+
EXPECT_EQ("updated4", email_aliases_notes.GetNote("alias4"));
122+
}
123+
124+
TEST_F(EmailAliasesNotesTest, Remove) {
125+
base::DictValue notes;
126+
notes.Set("a@prima.ry", CreateNotes({{"alias1", "note1"},
127+
{"alias2", "note2"},
128+
{"alias3", "note3"}}));
129+
GetPrefs()->SetDict(prefs::kEmailAliasesNotes, std::move(notes));
130+
131+
EmailAliasesNotes email_aliases_notes(GetPrefs(), "a@prima.ry");
132+
133+
email_aliases_notes.RemoveNote("alias1");
134+
EXPECT_EQ(std::nullopt, email_aliases_notes.GetNote("alias1"));
135+
email_aliases_notes.RemoveNote("alias2");
136+
EXPECT_EQ(std::nullopt, email_aliases_notes.GetNote("alias2"));
137+
email_aliases_notes.RemoveNote("alias3");
138+
EXPECT_EQ(std::nullopt, email_aliases_notes.GetNote("alias3"));
139+
}
140+
141+
} // namespace email_aliases

0 commit comments

Comments
 (0)