changeset 3325:7ebda4b54170

jp (file/share): added commands to manage affiliations and configuration + documentation
author Goffi <goffi@goffi.org>
date Sat, 01 Aug 2020 16:25:50 +0200
parents b57b5e42e894
children 9e1ba1e1179f
files doc/jp/file_share.rst doc/jp/file_share_affiliations.rst doc/jp/file_share_configuration.rst sat_frontends/jp/cmd_file.py sat_frontends/jp/cmd_pubsub.py
diffstat 5 files changed, 322 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/doc/jp/file_share.rst	Sat Aug 01 16:24:03 2020 +0200
+++ b/doc/jp/file_share.rst	Sat Aug 01 16:25:50 2020 +0200
@@ -96,3 +96,13 @@
 
   $ jp file share invite -P "photos/summer holidays" -t photos pierre@files.example.net
   louise@example.org
+
+affiliations
+============
+
+subcommands for file sharing affiliations management. please check :ref:`jp-file_share_affiliations`.
+
+configuration
+=============
+
+subcommands for retrieving/modifying file sharing node configuration. please check :ref:`jp-file_share_configuration`.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/jp/file_share_affiliations.rst	Sat Aug 01 16:25:50 2020 +0200
@@ -0,0 +1,56 @@
+.. _jp-file_share_affiliations:
+
+=============================================================
+file/share/affiliations: file sharing affiliations management
+=============================================================
+
+``affiliations`` let you manage access permission to your shared files repository, in a
+way similar as for pubsub.
+
+Affiliations with file sharing are not standard and will only work with the SàT file
+sharing component.
+
+Affiliations are similar to pubsub ones:
+
+``owner``
+  Has full permissions on the node, including changing affiliations. Owner can't be
+  changed at the moment.
+
+``publisher``
+  Can read, upload and delete files
+
+``member``
+  Can access file but can't modify them or add new ones
+
+``none``
+  Is not a member of this node, use it to remove an existing affiliation.
+
+
+get
+===
+
+Retrieve entities affiliated to this file sharing node, and their role
+
+example
+-------
+
+Get affiliations of a file sharing node::
+
+  $ jp file share affiliations get -P "/some/path" louise@files.example.org
+
+set
+===
+
+Set affiliations of an entity to a file sharing node.
+
+examples
+--------
+
+Allow read access to a photo album to Louise::
+
+  $ jp file share affiliations set -c files.example.net -P "/albums/holidays" -a louise@tazar2.int member
+
+Remove access to a directory from an old address of Pierre, and give it to the new one::
+
+  $ jp file share affiliations set -c files.example.net -N "some_namespace" -P
+  "/interesting/directory" -a pierre@example.com none -a pierre@example.org member
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/jp/file_share_configuration.rst	Sat Aug 01 16:25:50 2020 +0200
@@ -0,0 +1,38 @@
+.. _jp-file_share_configuration:
+
+=========================================================
+file/share/configuration: file sharing node configuration
+=========================================================
+
+``configuration`` commands are use to check or modify settings of a file sharing node.
+This is not standard and specific to SàT file sharing component.
+
+The configuration is similar as pubsub one.
+
+Only ``access_model`` can be used so far, with the ``open`` or ``whitelist`` values.
+
+
+get
+===
+
+Retrieve file sharing node configuration.
+
+example
+-------
+
+Get configuration of a file sharing node::
+
+  $ jp file share configuration get -P "/some/path" louise@files.example.org
+
+set
+===
+
+Set configuration of a file sharing node.
+
+example
+-------
+
+Make a repository public::
+
+  $ jp file share configuration set -c files.example.net -P "/public_files" -f
+  access_model open
--- a/sat_frontends/jp/cmd_file.py	Sat Aug 01 16:24:03 2020 +0200
+++ b/sat_frontends/jp/cmd_file.py	Sat Aug 01 16:25:50 2020 +0200
@@ -582,6 +582,221 @@
             await self.gotId(upload_data, file_)
 
 
+class ShareAffiliationsSet(base.CommandBase):
+
+    def __init__(self, host):
+        super(ShareAffiliationsSet, self).__init__(
+            host,
+            "set",
+            use_output=C.OUTPUT_DICT,
+            help=_("set affiliations for a shared file/directory"),
+        )
+
+    def add_parser_options(self):
+        self.parser.add_argument(
+            "-N",
+            "--namespace",
+            default="",
+            help=_("namespace of the repository"),
+        )
+        self.parser.add_argument(
+            "-P",
+            "--path",
+            default="",
+            help=_("path to the repository"),
+        )
+        self.parser.add_argument(
+            "-a",
+            "--affiliation",
+            dest="affiliations",
+            metavar=("JID", "AFFILIATION"),
+            required=True,
+            action="append",
+            nargs=2,
+            help=_("entity/affiliation couple(s)"),
+        )
+        self.parser.add_argument(
+            "jid",
+            help=_("jid of file sharing entity"),
+        )
+
+    async def start(self):
+        affiliations = dict(self.args.affiliations)
+        try:
+            affiliations = await self.host.bridge.FISAffiliationsSet(
+                self.args.jid,
+                self.args.namespace,
+                self.args.path,
+                affiliations,
+                self.profile,
+            )
+        except Exception as e:
+            self.disp(f"can't set affiliations: {e}", error=True)
+            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
+        else:
+            self.host.quit()
+
+
+class ShareAffiliationsGet(base.CommandBase):
+    def __init__(self, host):
+        super(ShareAffiliationsGet, self).__init__(
+            host,
+            "get",
+            use_output=C.OUTPUT_DICT,
+            help=_("retrieve affiliations of a shared file/directory"),
+        )
+
+    def add_parser_options(self):
+        self.parser.add_argument(
+            "-N",
+            "--namespace",
+            default="",
+            help=_("namespace of the repository"),
+        )
+        self.parser.add_argument(
+            "-P",
+            "--path",
+            default="",
+            help=_("path to the repository"),
+        )
+        self.parser.add_argument(
+            "jid",
+            help=_("jid of sharing entity"),
+        )
+
+    async def start(self):
+        try:
+            affiliations = await self.host.bridge.FISAffiliationsGet(
+                self.args.jid,
+                self.args.namespace,
+                self.args.path,
+                self.profile,
+            )
+        except Exception as e:
+            self.disp(f"can't get affiliations: {e}", error=True)
+            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
+        else:
+            await self.output(affiliations)
+            self.host.quit()
+
+
+class ShareAffiliations(base.CommandBase):
+    subcommands = (ShareAffiliationsGet, ShareAffiliationsSet)
+
+    def __init__(self, host):
+        super(ShareAffiliations, self).__init__(
+            host, "affiliations", use_profile=False, help=_("affiliations management")
+        )
+
+
+class ShareConfigurationSet(base.CommandBase):
+
+    def __init__(self, host):
+        super(ShareConfigurationSet, self).__init__(
+            host,
+            "set",
+            use_output=C.OUTPUT_DICT,
+            help=_("set configuration for a shared file/directory"),
+        )
+
+    def add_parser_options(self):
+        self.parser.add_argument(
+            "-N",
+            "--namespace",
+            default="",
+            help=_("namespace of the repository"),
+        )
+        self.parser.add_argument(
+            "-P",
+            "--path",
+            default="",
+            help=_("path to the repository"),
+        )
+        self.parser.add_argument(
+            "-f",
+            "--field",
+            action="append",
+            nargs=2,
+            dest="fields",
+            required=True,
+            metavar=("KEY", "VALUE"),
+            help=_("configuration field to set (required)"),
+        )
+        self.parser.add_argument(
+            "jid",
+            help=_("jid of file sharing entity"),
+        )
+
+    async def start(self):
+        configuration = dict(self.args.fields)
+        try:
+            configuration = await self.host.bridge.FISConfigurationSet(
+                self.args.jid,
+                self.args.namespace,
+                self.args.path,
+                configuration,
+                self.profile,
+            )
+        except Exception as e:
+            self.disp(f"can't set configuration: {e}", error=True)
+            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
+        else:
+            self.host.quit()
+
+
+class ShareConfigurationGet(base.CommandBase):
+    def __init__(self, host):
+        super(ShareConfigurationGet, self).__init__(
+            host,
+            "get",
+            use_output=C.OUTPUT_DICT,
+            help=_("retrieve configuration of a shared file/directory"),
+        )
+
+    def add_parser_options(self):
+        self.parser.add_argument(
+            "-N",
+            "--namespace",
+            default="",
+            help=_("namespace of the repository"),
+        )
+        self.parser.add_argument(
+            "-P",
+            "--path",
+            default="",
+            help=_("path to the repository"),
+        )
+        self.parser.add_argument(
+            "jid",
+            help=_("jid of sharing entity"),
+        )
+
+    async def start(self):
+        try:
+            configuration = await self.host.bridge.FISConfigurationGet(
+                self.args.jid,
+                self.args.namespace,
+                self.args.path,
+                self.profile,
+            )
+        except Exception as e:
+            self.disp(f"can't get configuration: {e}", error=True)
+            self.host.quit(C.EXIT_BRIDGE_ERRBACK)
+        else:
+            await self.output(configuration)
+            self.host.quit()
+
+
+class ShareConfiguration(base.CommandBase):
+    subcommands = (ShareConfigurationGet, ShareConfigurationSet)
+
+    def __init__(self, host):
+        super(ShareConfiguration, self).__init__(
+            host, "configuration", use_profile=False,
+            help=_("file sharing node configuration")
+        )
+
+
 class ShareList(base.CommandBase):
     def __init__(self, host):
         extra_outputs = {"default": self.default_output}
@@ -804,7 +1019,8 @@
 
 
 class Share(base.CommandBase):
-    subcommands = (ShareList, SharePath, ShareInvite)
+    subcommands = (
+        ShareList, SharePath, ShareInvite, ShareAffiliations, ShareConfiguration)
 
     def __init__(self, host):
         super(Share, self).__init__(
--- a/sat_frontends/jp/cmd_pubsub.py	Sat Aug 01 16:24:03 2020 +0200
+++ b/sat_frontends/jp/cmd_pubsub.py	Sat Aug 01 16:25:50 2020 +0200
@@ -415,7 +415,7 @@
 
     def add_parser_options(self):
         # XXX: we use optional argument syntax for a required one because list of list of 2 elements
-        #      (uses to construct dicts) don't work with positional arguments
+        #      (used to construct dicts) don't work with positional arguments
         self.parser.add_argument(
             "-a",
             "--affiliation",