Skip to content

Commit

Permalink
partial description(3)
Browse files Browse the repository at this point in the history
Signed-off-by: Alexander Piskun <bigcat88@icloud.com>
  • Loading branch information
bigcat88 committed Jul 24, 2023
1 parent d522ec7 commit b8b371e
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Project cloud-py-api was **abandoned** and divided into two parts:
* User status manipulation
* Weather status
* ~~Nextcloud notifications support~~
* ~~Shares operations support~~
* Shares support
* ~~Talk support~~

### Extended Features with installed App_ecosystem_v2:
Expand Down
13 changes: 13 additions & 0 deletions docs/reference/Shares.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.. py:currentmodule:: nc_py_api.files_sharing
File Sharing
============

The Shares API is universal for both modes and provides all the necessary methods for working with the Nextcloud Shares system.
Refer to the **share examples** to see how to use them nicely.

.. autoclass:: Share
:members:

.. autoclass:: FilesSharingAPI
:members:
1 change: 1 addition & 0 deletions docs/reference/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ Reference
:maxdepth: 2

Files
Shares
Session
constants
1 change: 1 addition & 0 deletions nc_py_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .constants import ApiScope, LogLvl, SharePermissions, ShareStatus, ShareType
from .exceptions import NextcloudException, NextcloudExceptionNotFound, check_error
from .files import FsNode, FsNodeInfo
from .files_sharing import Share
from .integration_fastapi import (
enable_heartbeat,
nc_app,
Expand Down
10 changes: 3 additions & 7 deletions nc_py_api/constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Common constants. Do not use them directly, all public ones are imported to __init__.py"""

from enum import IntEnum
from enum import IntEnum, IntFlag
from typing import TypedDict


Expand Down Expand Up @@ -36,10 +36,8 @@ class OCSRespond(IntEnum):
RESPOND_UNKNOWN_ERROR = 999


class SharePermissions(IntEnum):
"""The share permissions to be set.
All permissions can be combined with each other, except ``PERMISSION_ALL``"""
class SharePermissions(IntFlag):
"""The share permissions to be set"""

PERMISSION_READ = 1
"""Access to read"""
Expand All @@ -51,8 +49,6 @@ class SharePermissions(IntEnum):
"""Access to remove objects in the share"""
PERMISSION_SHARE = 16
"""Access to re-share objects in the share"""
PERMISSION_ALL = 31
"""Full access to the shared object"""


class ShareType(IntEnum):
Expand Down
4 changes: 3 additions & 1 deletion nc_py_api/files.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Nextcloud API for working with file system.
Nextcloud API for working with the file system.
"""

import builtins
Expand Down Expand Up @@ -168,6 +168,8 @@ def is_creatable(self) -> bool:


class FilesAPI:
"""This class provides all WebDAV functionality related to the files."""

def __init__(self, session: NcSessionBasic):
self._session = session

Expand Down
114 changes: 100 additions & 14 deletions nc_py_api/files_sharing.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,146 @@
"""
Nextcloud API for working with files shares.
Nextcloud API for working with the files shares.
"""

from typing import Union

from ._session import NcSessionBasic
from .constants import SharePermissions, ShareType
from .files import FsNode
from .misc import check_capabilities, require_capabilities

ENDPOINT_BASE_SHARES = "/ocs/v1.php/shares"
ENDPOINT_BASE_SHAREES = "/ocs/v1.php/sharees"
ENDPOINT_BASE_DELETED = "/ocs/v1.php/deletedshares"
ENDPOINT_BASE_REMOTE = "/ocs/v1.php/remote_shares"
ENDPOINT_BASE = "/ocs/v1.php/apps/files_sharing/api/v1/"


class Share:
"""Class represents one Nextcloud Share."""

def __init__(self, raw_data: dict):
self.raw_data = raw_data

@property
def share_id(self) -> int:
return int(self.raw_data["id"])

@property
def type(self) -> ShareType:
return ShareType(int(self.raw_data["share_type"]))

@property
def permissions(self) -> SharePermissions:
"""Recipient permissions"""

return SharePermissions(int(self.raw_data["permissions"]))

@property
def url(self) -> str:
return self.raw_data.get("url", "")

@property
def path(self) -> str:
return self.raw_data.get("path", "")

@property
def label(self) -> str:
return self.raw_data.get("label", "")

@property
def note(self) -> str:
return self.raw_data.get("note", "")

@property
def mimetype(self) -> str:
return self.raw_data.get("mimetype", "")


class FilesSharingAPI:
"""This class provides all File Sharing functionality."""

def __init__(self, session: NcSessionBasic):
self._session = session

def get_list(self, shared_with_me=False, reshares=False, subfiles=False, path: Union[str, FsNode] = ""):
@property
def available(self) -> bool:
"""Returns True if the Nextcloud instance supports this feature, False otherwise."""

return not check_capabilities("files_sharing", self._session.capabilities)

def get_list(
self, shared_with_me=False, reshares=False, subfiles=False, path: Union[str, FsNode] = ""
) -> list[Share]:
"""Returns lists of shares."""

require_capabilities("files_sharing", self._session.capabilities)
path = path.path if isinstance(path, FsNode) else path
params = {
"shared_with_me": "true" if shared_with_me else "false",
"reshares": "true" if reshares else "false",
"subfiles": "true" if subfiles else "false",
"path": path,
}
return self._session.ocs(method="GET", path=f"{ENDPOINT_BASE_SHARES}", params=params)
if path:
params["path"] = path
result = self._session.ocs(method="GET", path=f"{ENDPOINT_BASE}/shares", params=params)
return [Share(i) for i in result]

def create(
self,
path: Union[str, FsNode],
permissions: SharePermissions,
share_type: ShareType,
share_with: str,
share_with: str = "",
**kwargs,
):
) -> Share:
"""Creates a new share.
:param path: The path of an existing file/directory.
:param permissions: combination of the :py:class:`~nc_py_api.SharePermissions` object values.
:param share_type: :py:class:`~nc_py_api.ShareType` value.
:param share_with: string representing object name to where send share.
:param share_with: the recipient of the shared object.
:param kwargs: *Additionally supported arguments*
Additionally supported arguments:
``public`` - boolean indicating should share be available for non-registered users.
default = ``False``
``password`` - string with password to protect share.
default = ``""``
``sendPasswordByTalk`` - boolean indicating should password be automatically delivered using Talk.
``send_password_by_talk`` - boolean indicating should password be automatically delivered using Talk.
default = ``False``
``expireDate`` - to-do, choose format.
``expire_date`` - py:class:`datetime` time when share should expire. `hours, minutes, seconds` are ignored.
default = None
``note`` - string with note, if any.
default = ``""``
``label`` - string with label, if any.
default = ``""``
"""

pass # noqa # pylint: disable=unnecessary-pass
require_capabilities("files_sharing", self._session.capabilities)
path = path.path if isinstance(path, FsNode) else path
params = {
"path": path,
"permissions": int(permissions),
"shareType": int(share_type),
}
if share_with:
kwargs["shareWith"] = share_with
if kwargs.get("public", False):
params["publicUpload"] = "true"
if "password" in kwargs:
params["publicUpload"] = kwargs["password"]
if kwargs.get("send_password_by_talk", False):
params["sendPasswordByTalk"] = "true"
if "expire_date" in kwargs:
params["expireDate"] = kwargs["expire_date"].isoformat()
if "note" in kwargs:
params["note"] = kwargs["note"]
if "label" in kwargs:
params["label"] = kwargs["label"]
return Share(self._session.ocs(method="POST", path=f"{ENDPOINT_BASE}/shares", params=params))

def delete(self, share_id: Union[int, Share]) -> None:
"""Removes the given share.
:param share_id: The Share object or an ID of the share.
"""

share_id = share_id.share_id if isinstance(share_id, Share) else share_id
self._session.ocs(method="DELETE", path=f"{ENDPOINT_BASE}/shares/{share_id}")
2 changes: 2 additions & 0 deletions nc_py_api/users_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ def __init__(self, session: NcSessionBasic):

@property
def available(self) -> bool:
"""Returns True if the Nextcloud instance supports this feature, False otherwise."""

return not check_capabilities("user_status", self._session.capabilities)

def get_list(self, limit: Optional[int] = None, offset: Optional[int] = None) -> list[UserStatus]:
Expand Down
2 changes: 2 additions & 0 deletions nc_py_api/weather_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ def __init__(self, session: NcSessionBasic):

@property
def available(self) -> bool:
"""Returns True if the Nextcloud instance supports this feature, False otherwise."""

return not check_capabilities("weather_status", self._session.capabilities)

def get_location(self) -> WeatherLocation:
Expand Down
20 changes: 20 additions & 0 deletions tests/files_sharing_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import pytest
from gfixture import NC_TO_TEST

from nc_py_api import Share, SharePermissions, ShareType


@pytest.mark.parametrize("nc", NC_TO_TEST)
def test_create_list_delete_shares(nc):
nc.files.upload("share_test", content="")
try:
result = nc.files_sharing.get_list()
assert isinstance(result, list)
n_shares = len(result)
new_share = nc.files_sharing.create("share_test", SharePermissions.PERMISSION_READ, ShareType.TYPE_LINK)
assert isinstance(new_share, Share)
assert n_shares + 1 == len(nc.files_sharing.get_list())
nc.files_sharing.delete(new_share)
assert n_shares == len(nc.files_sharing.get_list())
finally:
nc.files.delete("share_test")

0 comments on commit b8b371e

Please sign in to comment.