view libervia/cli/cmd_bookmarks.py @ 4327:554a87ae17a6

plugin XEP-0048, XEP-0402; CLI (bookmarks): implement XEP-0402 (PEP Native Bookmarks): - Former bookmarks implementation is now labeled as "legacy". - XEP-0402 is now used for bookmarks when relevant namespaces are found, and it fallbacks to legacy XEP-0048/XEP-0049 bookmarks otherwise. - CLI legacy bookmark commands have been moved to `bookmarks legacy` - CLI bookmarks commands now use the new XEP-0402 (with fallback to legacy one automatically used if necessary).
author Goffi <goffi@goffi.org>
date Wed, 20 Nov 2024 11:43:27 +0100
parents 47401850dec6
children
line wrap: on
line source

#!/usr/bin/env python3


# Libervia CLI
# Copyright (C) 2009-2021 JΓ©rΓ΄me Poisson (goffi@goffi.org)

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from rich.table import Table

from libervia.backend.core.i18n import _
from libervia.backend.tools.common import data_format
from libervia.cli.constants import Const as C

from . import base
from .bookmarks_legacy import BookmarksLegacy

__commands__ = ["Bookmarks"]


class BookmarksList(base.CommandBase):
    def __init__(self, host):
        extra_outputs = {"default": self.default_output}
        super().__init__(
            host, "list", help=_("list bookmarks"),
            use_output=C.OUTPUT_COMPLEX,
            extra_outputs=extra_outputs
        )

    def add_parser_options(self):
        pass

    def default_output(self, data: dict) -> None:
        table = Table(title="πŸ“š " + _("Group Chat Bookmarks"))
        table.add_column("🌐 JID")
        table.add_column("πŸ“ " + _("Name"))
        table.add_column("πŸ‘€ " + _("Nick"))
        table.add_column("πŸ”’ " + _("Password"))
        table.add_column("πŸšͺ " + _("Joined"))

        for jid, conference_data in data.items():
            table.add_row(
                str(jid),
                conference_data.get("name", ""),
                conference_data.get("nick", ""),
                conference_data.get("password", ""),
                "βœ…" if conference_data.get("autojoin", False) else "❌"
            )

        self.console.print(table)

    async def start(self):
        try:
            data = data_format.deserialise(await self.host.bridge.bookmarks_list(
                "", self.host.profile
            ))
        except Exception as e:
            self.disp(f"can't get bookmarks list: {e}", error=True)
            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
            return

        await self.output(data)
        self.host.quit()


class BookmarksRemove(base.CommandBase):
    def __init__(self, host):
        super().__init__(host, "remove", help=_("remove a bookmark"))

    def add_parser_options(self):
        self.parser.add_argument(
            "bookmark", help=_("jid of the bookmark to remove")
        )
        self.parser.add_argument(
            "-f",
            "--force",
            action="store_true",
            help=_("delete bookmark without confirmation"),
        )

    async def start(self):
        if not self.args.force:
            await self.host.confirm_or_quit(
                _("Are you sure to delete the bookmark {bookmark_id!r}?")
                .format(bookmark_id=self.args.bookmark)
            )

        try:
            await self.host.bridge.bookmark_remove(
                self.args.bookmark, self.host.profile
            )
        except Exception as e:
            self.disp(_("can't delete bookmark: {e}").format(e=e), error=True)
            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
        else:
            self.disp(_("bookmark deleted"))
            self.host.quit()


class BookmarksSet(base.CommandBase):
    def __init__(self, host):
        super().__init__(
            host, "set", help=_("add or update a bookmark")
        )

    def add_parser_options(self):
        self.parser.add_argument("bookmark", help=_("jid of the chat room"))
        self.parser.add_argument("-n", "--name", help=_("bookmark name"), dest="name")
        self.parser.add_argument(
            "-j",
            "--join",
            nargs="?",
            # Value use when option is missing.
            default=None,
            # Value use when option is used, but value is not specified.
            const=True,
            type=base.optional_bool_decoder,
            # The bookmark attribute is called "autojoin" for historical reason, but it's
            # now used a "join" flag, so we use ``join`` here for the option.
            dest="autojoin",
            metavar="BOOL",
            help=_("join the conference room"),
        )
        self.parser.add_argument(
            "-N",
            "--nick", help=_("preferred roomnick for the chatroom")
        )
        self.parser.add_argument(
            "-P",
            "--password", help=_("password used to access the chatroom")
        )
        self.parser.add_argument(
            "-u",
            "--update",
            action="store_true",
            help=_("update bookmark data instead of replacing")
        )

    async def start(self):
        conference_data = {
            "autojoin": self.args.autojoin,
            "name": self.args.name,
            "nick": self.args.nick,
            "password": self.args.password,
        }

        conference_data = {k: v for k, v in conference_data.items() if v is not None}
        if self.args.update:
            try:
                old_conference_data = data_format.deserialise(
                    await self.host.bridge.bookmark_get(
                        self.args.bookmark, self.host.profile
                    )
                )
            except Exception as e:
                self.disp(
                    f"Can't find existing bookmark {self.args.bookmark!r}: {e}. We "
                    "create it.",
                    error=True
                )
            else:
                old_conference_data.update(conference_data)
                conference_data = old_conference_data

        try:
            await self.host.bridge.bookmarks_set(
                data_format.serialise({self.args.bookmark: conference_data}),
                self.host.profile,
            )
        except Exception as e:
            self.disp(f"can't add bookmark: {e}", error=True)
            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
        else:
            self.disp(_("bookmark successfully set"))
            self.host.quit()


class Bookmarks(base.CommandBase):
    subcommands = (BookmarksList, BookmarksSet, BookmarksRemove, BookmarksLegacy)

    def __init__(self, host):
        super().__init__(
            host, "bookmarks", use_profile=False, help=_("manage bookmarks")
        )