Add support for PRIVATE flag in import and export (#505)

* Add support for PRIVATE attribute in import

* Add support for PRIVATE attribute in export

* Update import sync tests
This commit is contained in:
Sascha Ißbrücker
2023-08-20 11:44:53 +02:00
committed by GitHub
parent 5d9e487ec1
commit 8206705876
10 changed files with 184 additions and 20 deletions

View File

@@ -33,9 +33,10 @@ def append_bookmark(doc: BookmarkDocument, bookmark: Bookmark):
desc = html.escape(bookmark.resolved_description or '')
tags = ','.join(bookmark.tag_names)
toread = '1' if bookmark.unread else '0'
private = '0' if bookmark.shared else '1'
added = int(bookmark.date_added.timestamp())
doc.append(f'<DT><A HREF="{url}" ADD_DATE="{added}" PRIVATE="0" TOREAD="{toread}" TAGS="{tags}">{title}</A>')
doc.append(f'<DT><A HREF="{url}" ADD_DATE="{added}" PRIVATE="{private}" TOREAD="{toread}" TAGS="{tags}">{title}</A>')
if desc:
doc.append(f'<DD>{desc}')

View File

@@ -20,6 +20,11 @@ class ImportResult:
failed: int = 0
@dataclass
class ImportOptions:
map_private_flag: bool = False
class TagCache:
def __init__(self, user: User):
self.user = user
@@ -50,7 +55,7 @@ class TagCache:
self.cache[tag.name.lower()] = tag
def import_netscape_html(html: str, user: User):
def import_netscape_html(html: str, user: User, options: ImportOptions = ImportOptions()) -> ImportResult:
result = ImportResult()
import_start = timezone.now()
@@ -70,7 +75,7 @@ def import_netscape_html(html: str, user: User):
# Split bookmarks to import into batches, to keep memory usage for bulk operations manageable
batches = _get_batches(netscape_bookmarks, 200)
for batch in batches:
_import_batch(batch, user, tag_cache, result)
_import_batch(batch, user, options, tag_cache, result)
# Create snapshots for newly imported bookmarks
tasks.schedule_bookmarks_without_snapshots(user)
@@ -114,7 +119,11 @@ def _get_batches(items: List, batch_size: int):
return batches
def _import_batch(netscape_bookmarks: List[NetscapeBookmark], user: User, tag_cache: TagCache, result: ImportResult):
def _import_batch(netscape_bookmarks: List[NetscapeBookmark],
user: User,
options: ImportOptions,
tag_cache: TagCache,
result: ImportResult):
# Query existing bookmarks
batch_urls = [bookmark.href for bookmark in netscape_bookmarks]
existing_bookmarks = Bookmark.objects.filter(owner=user, url__in=batch_urls)
@@ -135,7 +144,7 @@ def _import_batch(netscape_bookmarks: List[NetscapeBookmark], user: User, tag_ca
else:
is_update = True
# Copy data from parsed bookmark
_copy_bookmark_data(netscape_bookmark, bookmark)
_copy_bookmark_data(netscape_bookmark, bookmark, options)
# Validate bookmark fields, exclude owner to prevent n+1 database query,
# also there is no specific validation on owner
bookmark.clean_fields(exclude=['owner'])
@@ -152,8 +161,14 @@ def _import_batch(netscape_bookmarks: List[NetscapeBookmark], user: User, tag_ca
result.failed = result.failed + 1
# Bulk update bookmarks in DB
Bookmark.objects.bulk_update(bookmarks_to_update,
['url', 'date_added', 'date_modified', 'unread', 'title', 'description', 'owner'])
Bookmark.objects.bulk_update(bookmarks_to_update, ['url',
'date_added',
'date_modified',
'unread',
'shared',
'title',
'description',
'owner'])
# Bulk insert new bookmarks into DB
Bookmark.objects.bulk_create(bookmarks_to_create)
@@ -187,7 +202,7 @@ def _import_batch(netscape_bookmarks: List[NetscapeBookmark], user: User, tag_ca
BookmarkToTagRelationShip.objects.bulk_create(relationships, ignore_conflicts=True)
def _copy_bookmark_data(netscape_bookmark: NetscapeBookmark, bookmark: Bookmark):
def _copy_bookmark_data(netscape_bookmark: NetscapeBookmark, bookmark: Bookmark, options: ImportOptions):
bookmark.url = netscape_bookmark.href
if netscape_bookmark.date_added:
bookmark.date_added = parse_timestamp(netscape_bookmark.date_added)
@@ -199,3 +214,5 @@ def _copy_bookmark_data(netscape_bookmark: NetscapeBookmark, bookmark: Bookmark)
bookmark.title = netscape_bookmark.title
if netscape_bookmark.description:
bookmark.description = netscape_bookmark.description
if options.map_private_flag and not netscape_bookmark.private:
bookmark.shared = True

View File

@@ -11,6 +11,7 @@ class NetscapeBookmark:
date_added: str
tag_string: str
to_read: bool
private: bool
class BookmarkParser(HTMLParser):
@@ -26,6 +27,7 @@ class BookmarkParser(HTMLParser):
self.title = ''
self.description = ''
self.toread = ''
self.private = ''
def handle_starttag(self, tag: str, attrs: list):
name = 'handle_start_' + tag.lower()
@@ -58,7 +60,9 @@ class BookmarkParser(HTMLParser):
description='',
date_added=self.add_date,
tag_string=self.tags,
to_read=self.toread == '1'
to_read=self.toread == '1',
# Mark as private by default, also when attribute is not specified
private=self.private != '0',
)
def handle_a_data(self, data):
@@ -79,6 +83,7 @@ class BookmarkParser(HTMLParser):
self.title = ''
self.description = ''
self.toread = ''
self.private = ''
def parse(html: str) -> List[NetscapeBookmark]: