Add active profile local data export
This commit is contained in:
@@ -313,6 +313,16 @@ impl BrowserCore {
|
||||
self.open_tab(space_settings_url()?);
|
||||
Ok(true)
|
||||
}
|
||||
"export-local-data"
|
||||
| "export local data"
|
||||
| "export-privacy-data"
|
||||
| "export privacy data" => {
|
||||
let Some(url) = settings_page_url("privacy")? else {
|
||||
return Ok(false);
|
||||
};
|
||||
self.open_tab(url);
|
||||
Ok(true)
|
||||
}
|
||||
"site-settings" | "open-site-settings" | "open site settings" => {
|
||||
let Some(url) = self.active_tab_site_settings_url()? else {
|
||||
return Ok(false);
|
||||
|
||||
@@ -0,0 +1,482 @@
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
use ely_domain::{
|
||||
ArchiveSource, ArchivedTab, BookmarkEntry, BrowserTab, DownloadChecksum, DownloadDestination,
|
||||
DownloadEntry, DownloadSecurity, DownloadState, HistoryEntry, NoteEntry, NoteTarget, Profile,
|
||||
ProfileKind, ReadingListEntry, ReadingProgress, SitePermissionAuditAction,
|
||||
SitePermissionAuditEvent, SitePermissionEntry, TabFlags, TabState,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::LocalDataInventory;
|
||||
use crate::CoreError;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ElyLocalDataPackage {
|
||||
pub(super) version: u16,
|
||||
pub(super) exported_at_unix_seconds: u64,
|
||||
pub(super) profile: ElyLocalProfileRecord,
|
||||
pub(super) inventory: LocalDataInventory,
|
||||
pub(super) open_tabs: Vec<ElyLocalTabRecord>,
|
||||
pub(super) archived_tabs: Vec<ElyLocalArchivedTabRecord>,
|
||||
pub(super) bookmarks: Vec<ElyLocalBookmarkRecord>,
|
||||
pub(super) notes: Vec<ElyLocalNoteRecord>,
|
||||
pub(super) reading_list: Vec<ElyLocalReadingListRecord>,
|
||||
pub(super) history: Vec<ElyLocalHistoryRecord>,
|
||||
pub(super) downloads: Vec<ElyLocalDownloadRecord>,
|
||||
pub(super) site_permissions: Vec<ElyLocalSitePermissionRecord>,
|
||||
pub(super) site_permission_audit_events: Vec<ElyLocalSitePermissionAuditRecord>,
|
||||
}
|
||||
|
||||
impl ElyLocalDataPackage {
|
||||
#[must_use]
|
||||
pub fn version(&self) -> u16 {
|
||||
self.version
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn profile_id(&self) -> &str {
|
||||
&self.profile.id
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn profile_name(&self) -> &str {
|
||||
&self.profile.name
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn inventory(&self) -> LocalDataInventory {
|
||||
self.inventory
|
||||
}
|
||||
|
||||
pub(super) fn unix_seconds(time: SystemTime) -> Result<u64, CoreError> {
|
||||
time.duration_since(UNIX_EPOCH)
|
||||
.map(|duration| duration.as_secs())
|
||||
.map_err(|error| CoreError::InvalidLocalDataPackage { reason: error.to_string() })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub(super) struct ElyLocalProfileRecord {
|
||||
id: String,
|
||||
name: String,
|
||||
kind: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub(super) struct ElyLocalTabRecord {
|
||||
id: String,
|
||||
space_id: String,
|
||||
space_name: String,
|
||||
title: String,
|
||||
url: String,
|
||||
favicon_key: Option<String>,
|
||||
parent_tab_id: Option<String>,
|
||||
state: String,
|
||||
flags: ElyLocalTabFlagsRecord,
|
||||
group_id: Option<String>,
|
||||
split_id: Option<String>,
|
||||
sort_key: u64,
|
||||
sync_enabled: bool,
|
||||
created_at_unix_seconds: u64,
|
||||
last_active_at_unix_seconds: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct ElyLocalTabFlagsRecord {
|
||||
pinned: bool,
|
||||
favorite: bool,
|
||||
muted: bool,
|
||||
unread: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub(super) struct ElyLocalArchivedTabRecord {
|
||||
tab: ElyLocalTabRecord,
|
||||
archived_at_unix_seconds: u64,
|
||||
source: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub(super) struct ElyLocalBookmarkRecord {
|
||||
id: String,
|
||||
space_id: String,
|
||||
space_name: String,
|
||||
collection_name: String,
|
||||
title: String,
|
||||
url: String,
|
||||
tags: Vec<String>,
|
||||
note: Option<String>,
|
||||
thumbnail_key: Option<String>,
|
||||
added_at_unix_seconds: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub(super) struct ElyLocalNoteRecord {
|
||||
id: String,
|
||||
space_id: String,
|
||||
space_name: String,
|
||||
target: ElyLocalNoteTargetRecord,
|
||||
title: String,
|
||||
source_url: String,
|
||||
body: String,
|
||||
created_at_unix_seconds: u64,
|
||||
updated_at_unix_seconds: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
enum ElyLocalNoteTargetRecord {
|
||||
Url { url: String },
|
||||
Tab { tab_id: String },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub(super) struct ElyLocalReadingListRecord {
|
||||
id: String,
|
||||
space_id: String,
|
||||
space_name: String,
|
||||
title: String,
|
||||
source_url: String,
|
||||
progress: ElyLocalReadingProgressRecord,
|
||||
added_at_unix_seconds: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(tag = "state", rename_all = "snake_case")]
|
||||
enum ElyLocalReadingProgressRecord {
|
||||
Unread,
|
||||
InProgress { percent: u8 },
|
||||
Finished,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub(super) struct ElyLocalHistoryRecord {
|
||||
space_id: String,
|
||||
space_name: String,
|
||||
source_tab_id: String,
|
||||
title: String,
|
||||
url: String,
|
||||
favicon_key: Option<String>,
|
||||
visited_at_unix_seconds: u64,
|
||||
visit_count: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub(super) struct ElyLocalDownloadRecord {
|
||||
id: String,
|
||||
source_url: String,
|
||||
file_name: String,
|
||||
destination: ElyLocalDownloadDestinationRecord,
|
||||
target_file_path: Option<String>,
|
||||
security: String,
|
||||
state: String,
|
||||
received_bytes: u64,
|
||||
total_bytes: Option<u64>,
|
||||
checksum: Option<ElyLocalDownloadChecksumRecord>,
|
||||
security_prompt_confirmed: bool,
|
||||
started_at_unix_seconds: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
enum ElyLocalDownloadDestinationRecord {
|
||||
AskEveryTime,
|
||||
FixedDirectory { path: String },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct ElyLocalDownloadChecksumRecord {
|
||||
algorithm: String,
|
||||
value: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub(super) struct ElyLocalSitePermissionRecord {
|
||||
origin: String,
|
||||
feature: String,
|
||||
decision: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub(super) struct ElyLocalSitePermissionAuditRecord {
|
||||
origin: String,
|
||||
feature: String,
|
||||
action: ElyLocalSitePermissionAuditActionRecord,
|
||||
created_at_unix_seconds: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(tag = "kind", rename_all = "snake_case")]
|
||||
enum ElyLocalSitePermissionAuditActionRecord {
|
||||
Set { decision: String },
|
||||
Revoked,
|
||||
}
|
||||
|
||||
impl ElyLocalProfileRecord {
|
||||
pub(super) fn from_profile(profile: &Profile) -> Self {
|
||||
Self {
|
||||
id: profile.id().as_str().to_string(),
|
||||
name: profile.name().to_string(),
|
||||
kind: profile_kind(profile.kind()).to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalTabRecord {
|
||||
pub(super) fn from_tab(tab: &BrowserTab, space_name: String) -> Result<Self, CoreError> {
|
||||
Ok(Self {
|
||||
id: tab.id().as_str().to_string(),
|
||||
space_id: tab.space_id().as_str().to_string(),
|
||||
space_name,
|
||||
title: tab.title().to_string(),
|
||||
url: tab.url().as_str().to_string(),
|
||||
favicon_key: tab.favicon_key().map(str::to_string),
|
||||
parent_tab_id: tab.parent_tab_id().map(|id| id.as_str().to_string()),
|
||||
state: tab_state(tab.state()).to_string(),
|
||||
flags: ElyLocalTabFlagsRecord::from_flags(tab.flags()),
|
||||
group_id: tab.group_id().map(|id| id.as_str().to_string()),
|
||||
split_id: tab.split_id().map(|id| id.as_str().to_string()),
|
||||
sort_key: tab.sort_key(),
|
||||
sync_enabled: tab.sync_enabled(),
|
||||
created_at_unix_seconds: ElyLocalDataPackage::unix_seconds(tab.created_at())?,
|
||||
last_active_at_unix_seconds: ElyLocalDataPackage::unix_seconds(tab.last_active_at())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalTabFlagsRecord {
|
||||
fn from_flags(flags: &TabFlags) -> Self {
|
||||
Self {
|
||||
pinned: flags.pinned,
|
||||
favorite: flags.favorite,
|
||||
muted: flags.muted,
|
||||
unread: flags.unread,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalArchivedTabRecord {
|
||||
pub(super) fn from_archived_tab(
|
||||
archived: &ArchivedTab,
|
||||
tab: ElyLocalTabRecord,
|
||||
) -> Result<Self, CoreError> {
|
||||
Ok(Self {
|
||||
tab,
|
||||
archived_at_unix_seconds: ElyLocalDataPackage::unix_seconds(archived.archived_at())?,
|
||||
source: archive_source(archived.source()).to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalBookmarkRecord {
|
||||
pub(super) fn from_bookmark(
|
||||
bookmark: &BookmarkEntry,
|
||||
space_name: String,
|
||||
) -> Result<Self, CoreError> {
|
||||
Ok(Self {
|
||||
id: bookmark.id().as_str().to_string(),
|
||||
space_id: bookmark.space_id().as_str().to_string(),
|
||||
space_name,
|
||||
collection_name: bookmark.collection_name().to_string(),
|
||||
title: bookmark.title().to_string(),
|
||||
url: bookmark.url().as_str().to_string(),
|
||||
tags: bookmark.tags().to_vec(),
|
||||
note: bookmark.note().map(str::to_string),
|
||||
thumbnail_key: bookmark.thumbnail_key().map(str::to_string),
|
||||
added_at_unix_seconds: ElyLocalDataPackage::unix_seconds(bookmark.added_at())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalNoteRecord {
|
||||
pub(super) fn from_note(note: &NoteEntry, space_name: String) -> Result<Self, CoreError> {
|
||||
Ok(Self {
|
||||
id: note.id().as_str().to_string(),
|
||||
space_id: note.space_id().as_str().to_string(),
|
||||
space_name,
|
||||
target: ElyLocalNoteTargetRecord::from_note_target(note.target()),
|
||||
title: note.title().to_string(),
|
||||
source_url: note.source_url().as_str().to_string(),
|
||||
body: note.body().to_string(),
|
||||
created_at_unix_seconds: ElyLocalDataPackage::unix_seconds(note.created_at())?,
|
||||
updated_at_unix_seconds: ElyLocalDataPackage::unix_seconds(note.updated_at())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalReadingListRecord {
|
||||
pub(super) fn from_entry(
|
||||
entry: &ReadingListEntry,
|
||||
space_name: String,
|
||||
) -> Result<Self, CoreError> {
|
||||
Ok(Self {
|
||||
id: entry.id().as_str().to_string(),
|
||||
space_id: entry.space_id().as_str().to_string(),
|
||||
space_name,
|
||||
title: entry.title().to_string(),
|
||||
source_url: entry.source_url().as_str().to_string(),
|
||||
progress: ElyLocalReadingProgressRecord::from_progress(*entry.progress()),
|
||||
added_at_unix_seconds: ElyLocalDataPackage::unix_seconds(entry.added_at())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalHistoryRecord {
|
||||
pub(super) fn from_entry(entry: &HistoryEntry, space_name: String) -> Result<Self, CoreError> {
|
||||
Ok(Self {
|
||||
space_id: entry.space_id().as_str().to_string(),
|
||||
space_name,
|
||||
source_tab_id: entry.source_tab_id().as_str().to_string(),
|
||||
title: entry.title().to_string(),
|
||||
url: entry.url().as_str().to_string(),
|
||||
favicon_key: entry.favicon_key().map(str::to_string),
|
||||
visited_at_unix_seconds: ElyLocalDataPackage::unix_seconds(entry.visited_at())?,
|
||||
visit_count: entry.visit_count(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalDownloadRecord {
|
||||
pub(super) fn from_download(entry: &DownloadEntry) -> Result<Self, CoreError> {
|
||||
Ok(Self {
|
||||
id: entry.id().as_str().to_string(),
|
||||
source_url: entry.source_url().as_str().to_string(),
|
||||
file_name: entry.file_name().to_string(),
|
||||
destination: ElyLocalDownloadDestinationRecord::from_destination(entry.destination()),
|
||||
target_file_path: entry.target_file_path().map(|path| path.display().to_string()),
|
||||
security: download_security(entry.security()).to_string(),
|
||||
state: download_state(entry.state()).to_string(),
|
||||
received_bytes: entry.received_bytes(),
|
||||
total_bytes: entry.total_bytes(),
|
||||
checksum: entry.checksum().map(ElyLocalDownloadChecksumRecord::from_checksum),
|
||||
security_prompt_confirmed: entry.security_prompt_confirmed(),
|
||||
started_at_unix_seconds: ElyLocalDataPackage::unix_seconds(entry.started_at())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalDownloadDestinationRecord {
|
||||
fn from_destination(destination: &DownloadDestination) -> Self {
|
||||
match destination {
|
||||
DownloadDestination::AskEveryTime => Self::AskEveryTime,
|
||||
DownloadDestination::FixedDirectory(path) => {
|
||||
Self::FixedDirectory { path: path.display().to_string() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalDownloadChecksumRecord {
|
||||
fn from_checksum(checksum: &DownloadChecksum) -> Self {
|
||||
Self {
|
||||
algorithm: checksum.algorithm().as_str().to_string(),
|
||||
value: checksum.value().to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalSitePermissionRecord {
|
||||
pub(super) fn from_site_permission(entry: &SitePermissionEntry) -> Self {
|
||||
Self {
|
||||
origin: entry.origin().as_str().to_string(),
|
||||
feature: entry.feature().as_str().to_string(),
|
||||
decision: entry.decision().as_str().to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalSitePermissionAuditRecord {
|
||||
pub(super) fn from_audit_event(event: &SitePermissionAuditEvent) -> Result<Self, CoreError> {
|
||||
Ok(Self {
|
||||
origin: event.origin().as_str().to_string(),
|
||||
feature: event.feature().as_str().to_string(),
|
||||
action: ElyLocalSitePermissionAuditActionRecord::from_action(event.action()),
|
||||
created_at_unix_seconds: ElyLocalDataPackage::unix_seconds(event.created_at())?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalNoteTargetRecord {
|
||||
fn from_note_target(target: &NoteTarget) -> Self {
|
||||
match target {
|
||||
NoteTarget::Url(url) => Self::Url { url: url.as_str().to_string() },
|
||||
NoteTarget::Tab(tab_id) => Self::Tab { tab_id: tab_id.as_str().to_string() },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalReadingProgressRecord {
|
||||
fn from_progress(progress: ReadingProgress) -> Self {
|
||||
match progress {
|
||||
ReadingProgress::Unread => Self::Unread,
|
||||
ReadingProgress::InProgress(percent) => Self::InProgress { percent: percent.value() },
|
||||
ReadingProgress::Finished => Self::Finished,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyLocalSitePermissionAuditActionRecord {
|
||||
fn from_action(action: &SitePermissionAuditAction) -> Self {
|
||||
match action {
|
||||
SitePermissionAuditAction::Set(decision) => {
|
||||
Self::Set { decision: decision.as_str().to_string() }
|
||||
}
|
||||
SitePermissionAuditAction::Revoked => Self::Revoked,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn profile_kind(kind: &ProfileKind) -> &'static str {
|
||||
match kind {
|
||||
ProfileKind::Standard => "standard",
|
||||
ProfileKind::Private => "private",
|
||||
}
|
||||
}
|
||||
|
||||
fn tab_state(state: &TabState) -> &'static str {
|
||||
match state {
|
||||
TabState::Loading => "loading",
|
||||
TabState::Ready => "ready",
|
||||
TabState::Crashed => "crashed",
|
||||
TabState::Discarded => "discarded",
|
||||
TabState::Archived => "archived",
|
||||
}
|
||||
}
|
||||
|
||||
fn archive_source(source: &ArchiveSource) -> &'static str {
|
||||
match source {
|
||||
ArchiveSource::ManualClose => "manual_close",
|
||||
ArchiveSource::AutoArchive => "auto_archive",
|
||||
}
|
||||
}
|
||||
|
||||
fn download_security(security: &DownloadSecurity) -> &'static str {
|
||||
match security {
|
||||
DownloadSecurity::Standard => "standard",
|
||||
DownloadSecurity::DangerousExtension => "dangerous_extension",
|
||||
}
|
||||
}
|
||||
|
||||
fn download_state(state: &DownloadState) -> &'static str {
|
||||
match state {
|
||||
DownloadState::InProgress => "in_progress",
|
||||
DownloadState::Paused => "paused",
|
||||
DownloadState::Completed => "completed",
|
||||
DownloadState::Cancelled => "cancelled",
|
||||
DownloadState::Failed => "failed",
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
use std::time::SystemTime;
|
||||
|
||||
use ely_domain::{ArchivedTab, BookmarkEntry, BrowserTab, HistoryEntry, NoteEntry, SpaceId};
|
||||
|
||||
use super::BrowserCore;
|
||||
pub use super::local_data_export_records::ElyLocalDataPackage;
|
||||
use super::local_data_export_records::{
|
||||
ElyLocalArchivedTabRecord, ElyLocalBookmarkRecord, ElyLocalDownloadRecord,
|
||||
ElyLocalHistoryRecord, ElyLocalNoteRecord, ElyLocalProfileRecord, ElyLocalReadingListRecord,
|
||||
ElyLocalSitePermissionAuditRecord, ElyLocalSitePermissionRecord, ElyLocalTabRecord,
|
||||
};
|
||||
use crate::CoreError;
|
||||
|
||||
pub const ELYDATA_SCHEMA_VERSION: u16 = 1;
|
||||
pub const ELYDATA_FILE_EXTENSION: &str = "elydata";
|
||||
|
||||
impl BrowserCore {
|
||||
pub fn export_local_data_package_json(&self) -> Result<String, CoreError> {
|
||||
serde_json::to_string_pretty(&self.export_local_data_package()?)
|
||||
.map_err(invalid_local_data_package)
|
||||
}
|
||||
|
||||
pub fn export_local_data_package(&self) -> Result<ElyLocalDataPackage, CoreError> {
|
||||
let profile = self.active_profile()?;
|
||||
let profile_id = profile.id();
|
||||
|
||||
Ok(ElyLocalDataPackage {
|
||||
version: ELYDATA_SCHEMA_VERSION,
|
||||
exported_at_unix_seconds: ElyLocalDataPackage::unix_seconds(SystemTime::now())?,
|
||||
profile: ElyLocalProfileRecord::from_profile(profile),
|
||||
inventory: self.active_profile_local_data_inventory(),
|
||||
open_tabs: self
|
||||
.tabs
|
||||
.iter()
|
||||
.filter(|tab| tab.profile_id() == profile_id)
|
||||
.map(|tab| self.local_tab_record(tab))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
archived_tabs: self
|
||||
.archived_tabs
|
||||
.iter()
|
||||
.filter(|archived| archived.tab().profile_id() == profile_id)
|
||||
.map(|archived| self.local_archived_tab_record(archived))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
bookmarks: self
|
||||
.bookmarks
|
||||
.iter()
|
||||
.filter(|bookmark| bookmark.profile_id() == profile_id)
|
||||
.map(|bookmark| self.local_bookmark_record(bookmark))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
notes: self
|
||||
.notes
|
||||
.iter()
|
||||
.filter(|note| note.profile_id() == profile_id)
|
||||
.map(|note| self.local_note_record(note))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
reading_list: self
|
||||
.reading_list
|
||||
.iter()
|
||||
.filter(|entry| entry.profile_id() == profile_id)
|
||||
.map(|entry| {
|
||||
self.space_name(entry.space_id()).and_then(|space_name| {
|
||||
ElyLocalReadingListRecord::from_entry(entry, space_name)
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
history: self
|
||||
.history_entries
|
||||
.iter()
|
||||
.filter(|entry| entry.profile_id() == profile_id)
|
||||
.map(|entry| self.local_history_record(entry))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
downloads: self
|
||||
.download_entries
|
||||
.iter()
|
||||
.filter(|entry| entry.profile_id() == profile_id)
|
||||
.map(ElyLocalDownloadRecord::from_download)
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
site_permissions: self
|
||||
.site_permissions
|
||||
.iter()
|
||||
.filter(|entry| entry.profile_id() == profile_id)
|
||||
.map(ElyLocalSitePermissionRecord::from_site_permission)
|
||||
.collect(),
|
||||
site_permission_audit_events: self
|
||||
.site_permission_audit_events
|
||||
.iter()
|
||||
.filter(|event| event.profile_id() == profile_id)
|
||||
.map(ElyLocalSitePermissionAuditRecord::from_audit_event)
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
})
|
||||
}
|
||||
|
||||
fn local_tab_record(&self, tab: &BrowserTab) -> Result<ElyLocalTabRecord, CoreError> {
|
||||
ElyLocalTabRecord::from_tab(tab, self.space_name(tab.space_id())?)
|
||||
}
|
||||
|
||||
fn local_archived_tab_record(
|
||||
&self,
|
||||
archived: &ArchivedTab,
|
||||
) -> Result<ElyLocalArchivedTabRecord, CoreError> {
|
||||
ElyLocalArchivedTabRecord::from_archived_tab(
|
||||
archived,
|
||||
self.local_tab_record(archived.tab())?,
|
||||
)
|
||||
}
|
||||
|
||||
fn local_bookmark_record(
|
||||
&self,
|
||||
bookmark: &BookmarkEntry,
|
||||
) -> Result<ElyLocalBookmarkRecord, CoreError> {
|
||||
ElyLocalBookmarkRecord::from_bookmark(bookmark, self.space_name(bookmark.space_id())?)
|
||||
}
|
||||
|
||||
fn local_note_record(&self, note: &NoteEntry) -> Result<ElyLocalNoteRecord, CoreError> {
|
||||
ElyLocalNoteRecord::from_note(note, self.space_name(note.space_id())?)
|
||||
}
|
||||
|
||||
fn local_history_record(
|
||||
&self,
|
||||
entry: &HistoryEntry,
|
||||
) -> Result<ElyLocalHistoryRecord, CoreError> {
|
||||
ElyLocalHistoryRecord::from_entry(entry, self.space_name(entry.space_id())?)
|
||||
}
|
||||
|
||||
fn space_name(&self, space_id: &SpaceId) -> Result<String, CoreError> {
|
||||
self.spaces
|
||||
.iter()
|
||||
.find(|space| space.id() == space_id)
|
||||
.map(|space| space.name().to_string())
|
||||
.ok_or_else(|| CoreError::SpaceNotFound { id: space_id.clone() })
|
||||
}
|
||||
}
|
||||
|
||||
fn invalid_local_data_package(error: serde_json::Error) -> CoreError {
|
||||
CoreError::InvalidLocalDataPackage { reason: error.to_string() }
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
use ely_domain::{DiagnosticsReportingPolicy, HistoryRecordingPolicy};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::BrowserCore;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct LocalDataInventory {
|
||||
open_tabs: usize,
|
||||
archived_tabs: usize,
|
||||
|
||||
Reference in New Issue
Block a user