Source code for timApp.bookmark.bookmarks

from typing import Optional, TypedDict

from timApp.document.docsettings import DocSettings
from timApp.user.preferences import BookmarkCollection, BookmarkEntryList
from timApp.user.user import User


[docs]class BookmarkDictEntry(TypedDict): name: str link: str
[docs]class BookmarkDictGroup(TypedDict): name: str items: list[BookmarkDictEntry] editable: bool
MY_COURSES_GROUP = "My courses" HIDDEN_COURSES_GROUP = "Hidden courses" LAST_READ_GROUP = "Last read" LAST_EDITED_GROUP = "Last edited"
[docs]class Bookmarks: """ Class for managing bookmarks. .. note:: Bookmarks are stored as a JSON list in form [ { "Bookmark group" : [ { "Link 1": "https://example.com" }, { "Link 2": "https://example.com" } ] }, { "Bookmark group 2" : [ { "Link 1": "https://example.com" }, { "Link 2": "https://example.com" } ] } ] This class mainly allows to handle bookmars in a more convenient way. """ def __init__(self, user: User): """ Loads bookmarks from user preferences. :param user: User whose bookmarks to manage. """ self.user = user self.bookmark_data = self.get_bookmarks()
[docs] def add_bookmark( self, groupname: str, name: str, link: str, move_to_top: bool = False, limit: int | None = None, ) -> "Bookmarks": """ Adds a bookmark to the given bookmark group. :param groupname: Group name to add. :param name: Bookmark name. :param link: Bookmark link. :param move_to_top: If True, adds bookmark to the top of the group. :param limit: If not None, limits the number of bookmarks in the group. :return: This object. """ bookmark_data = self.bookmark_data added = False for g in bookmark_data: items = g.get(groupname) if items is not None: added = True self._add_item_to_group( items, name, link, move_to_top=move_to_top, limit=limit ) break if not added: empty: BookmarkEntryList = [] new_group = {groupname: empty} bookmark_data.append(new_group) self._add_item_to_group(empty, name, link) return self
[docs] def has_bookmark(self, groupname: str, name: str) -> bool: """ Checks if a bookmark with the given name exists in the given group. :param groupname: Group name. :param name: Bookmark name. :return: True if the bookmark exists, False otherwise. """ bookmark_data = self.bookmark_data for folder in bookmark_data: items = folder.get(groupname) if items is not None: for i in items: if i.get(name) is not None: return True return False
[docs] def delete_bookmark(self, groupname: str, name: str) -> "Bookmarks": """ Deletes a bookmark from the given group. :param groupname: Group name. :param name: Bookmark name. :return: This object. """ bookmark_data = self.bookmark_data items = next( (group[groupname] for group in bookmark_data if groupname in group), None, ) if not items: return self self._delete_item_from_group(items, name) return self
@staticmethod def _delete_item_from_group(groupitems: BookmarkEntryList, name: str) -> None: to_remove = [item for item in groupitems if item.get(name) is not None] if to_remove: groupitems.remove(to_remove[0])
[docs] def delete_group(self, groupname: str) -> "Bookmarks": """ Deletes a bookmark group. :param groupname: Group name to delete. :return: This object. """ bookmark_data = self.bookmark_data filtered = [group for group in bookmark_data if group.get(groupname) is None] self.bookmark_data = filtered return self
def _add_item_to_group( self, groupitems: BookmarkEntryList, name: str, link: str, move_to_top: bool = False, limit: int | None = None, ) -> None: item_found = False for i in groupitems: bookmark = i.get(name) if bookmark is not None: i[name] = link item_found = True if not item_found: groupitems.insert(0, {name: link}) elif move_to_top: self._delete_item_from_group(groupitems, name) groupitems.insert(0, {name: link}) if limit is not None: groupitems[:] = groupitems[:limit]
[docs] def add_group(self, groupname: str) -> "Bookmarks": """ Adds a bookmark group. :param groupname: Group name to add. :return: This object. """ bookmark_data = self.bookmark_data for g in bookmark_data: items = g.get(groupname) if items is not None: return self bookmark_data.append({groupname: []}) return self
[docs] def get_bookmarks(self) -> BookmarkCollection: """ Returns a collection of all bookmarks. :return: Collection of all bookmarks. """ p = self.user.get_prefs() if p.bookmarks: return p.bookmarks f = self.user.get_personal_folder() doc_info = f.get_document("Bookmarks", create_if_not_exist=False) if not doc_info: return [] bookmark_document = doc_info.document with bookmark_document.get_lock(): # Note: get_own_settings is intentional, so not get_settings. settings = bookmark_document.get_own_settings() return DocSettings(bookmark_document, settings).get_bookmarks()
[docs] def save_bookmarks(self) -> None: """ Saves edited bookmarks to the database. """ self._set_bookmarks(self.bookmark_data)
def _set_bookmarks(self, bookmark_data: BookmarkCollection) -> None: p = self.user.get_prefs() p.bookmarks = bookmark_data self.user.set_prefs(p)
[docs] def as_dict(self) -> list[BookmarkDictGroup]: """ Returns the bookmark data as a list of dicts. :return: A list of all bookmarks as dict objects. """ result: list[BookmarkDictGroup] = [] for group in self.get_bookmarks(): group_name = next(group.__iter__()) items = group[group_name] result_items: list[BookmarkDictEntry] = [] for i in items: item_name = next(i.__iter__()) result_items.append({"name": item_name, "link": i[item_name]}) result.append( { "name": group_name, "items": result_items, "editable": group_name != LAST_EDITED_GROUP, } ) return result