'OCA\\Files_Sharing\\Notification\\Listener' => $baseDir . '/../lib/Notification/Listener.php',
'OCA\\Files_Sharing\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
'OCA\\Files_Sharing\\OrphanHelper' => $baseDir . '/../lib/OrphanHelper.php',
+ 'OCA\\Files_Sharing\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php',
'OCA\\Files_Sharing\\Scanner' => $baseDir . '/../lib/Scanner.php',
'OCA\\Files_Sharing\\Settings\\Personal' => $baseDir . '/../lib/Settings/Personal.php',
'OCA\\Files_Sharing\\ShareBackend\\File' => $baseDir . '/../lib/ShareBackend/File.php',
'OCA\\Files_Sharing\\Notification\\Listener' => __DIR__ . '/..' . '/../lib/Notification/Listener.php',
'OCA\\Files_Sharing\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
'OCA\\Files_Sharing\\OrphanHelper' => __DIR__ . '/..' . '/../lib/OrphanHelper.php',
+ 'OCA\\Files_Sharing\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php',
'OCA\\Files_Sharing\\Scanner' => __DIR__ . '/..' . '/../lib/Scanner.php',
'OCA\\Files_Sharing\\Settings\\Personal' => __DIR__ . '/..' . '/../lib/Settings/Personal.php',
'OCA\\Files_Sharing\\ShareBackend\\File' => __DIR__ . '/..' . '/../lib/ShareBackend/File.php',
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Tobias Kaminsky <tobias@kaminsky.me>
* @author Vincent Petry <vincent@nextcloud.com>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
/**
* Return this classes capabilities
+ *
+ * @return array{
+ * files_sharing: array{
+ * api_enabled: bool,
+ * public: array{
+ * enabled: bool,
+ * password?: array{
+ * enforced: bool,
+ * askForOptionalPassword: bool
+ * },
+ * multiple_links?: bool,
+ * expire_date?: array{
+ * enabled: bool,
+ * days?: int,
+ * enforced?: bool,
+ * },
+ * expire_date_internal?: array{
+ * enabled: bool,
+ * days?: int,
+ * enforced?: bool,
+ * },
+ * expire_date_remote?: array{
+ * enabled: bool,
+ * days?: int,
+ * enforced?: bool,
+ * },
+ * send_mail?: bool,
+ * upload?: bool,
+ * upload_files_drop?: bool,
+ * },
+ * user: array{
+ * send_mail: bool,
+ * expire_date?: array{
+ * enabled: bool,
+ * },
+ * },
+ * resharing: bool,
+ * group_sharing?: bool,
+ * group?: array{
+ * enabled: bool,
+ * expire_date?: array{
+ * enabled: bool,
+ * },
+ * },
+ * default_permissions?: int,
+ * federation: array{
+ * outgoing: bool,
+ * incoming: bool,
+ * expire_date: array{
+ * enabled: bool,
+ * },
+ * expire_date_supported: array{
+ * enabled: bool,
+ * },
+ * },
+ * sharee: array{
+ * query_lookup_default: bool,
+ * always_show_unique: bool,
+ * },
+ * },
+ * }
*/
public function getCapabilities() {
$res = [];
* @copyright Copyright (c) 2020, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
use OCA\Files_Sharing\AppInfo\Application;
use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http\Attribute\IgnoreOpenAPI;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\AppFramework\Http\Response;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager as ShareManager;
+#[IgnoreOpenAPI]
class AcceptController extends Controller {
/** @var ShareManager */
* @author John Molakvoæ <skjnldsv@protonmail.com>
* @author Julius Härtl <jus@bitgrid.net>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
*/
namespace OCA\Files_Sharing\Controller;
+use OCA\Files_Sharing\ResponseDefinitions;
use OCP\App\IAppManager;
+use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\Share\IManager as ShareManager;
use OCP\Share\IShare;
+/**
+ * @psalm-import-type FilesSharingDeletedShare from ResponseDefinitions
+ */
class DeletedShareAPIController extends OCSController {
/** @var ShareManager */
/**
* @suppress PhanUndeclaredClassMethod
+ *
+ * @return FilesSharingDeletedShare
*/
private function formatShare(IShare $share): array {
$result = [
/**
* @NoAdminRequired
+ *
+ * Get a list of all deleted shares
+ *
+ * @return DataResponse<Http::STATUS_OK, FilesSharingDeletedShare[], array{}>
*/
public function index(): DataResponse {
$groupShares = $this->shareManager->getDeletedSharedWith($this->userId, IShare::TYPE_GROUP, null, -1, 0);
/**
* @NoAdminRequired
*
+ * Undelete a deleted share
+ *
+ * @param string $id ID of the share
+ * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
* @throws OCSException
+ * @throws OCSNotFoundException Share not found
+ *
+ * 200: Share undeleted successfully
*/
public function undelete(string $id): DataResponse {
try {
* @author Julius Härtl <jus@bitgrid.net>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
* @PublicPage
* @NoCSRFRequired
*
- * @param string $file
- * @param int $x
- * @param int $y
- * @param bool $a
- * @return DataResponse|FileDisplayResponse
+ * Get a preview for a shared file
+ *
+ * @param string $token Token of the share
+ * @param string $file File in the share
+ * @param int $x Width of the preview
+ * @param int $y Height of the preview
+ * @param bool $a Whether to not crop the preview
+ * @return FileDisplayResponse<Http::STATUS_OK, array{Content-Type: string}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>
+ *
+ * 200: Preview returned
+ * 400: Getting preview is not possible
+ * 403: Getting preview is not allowed
+ * 404: Share or preview not found
*/
public function getPreview(
string $token,
* @NoCSRFRequired
* @NoSameSiteCookieRequired
*
- * @param $token
- * @return DataResponse|FileDisplayResponse
+ * Get a direct link preview for a shared file
+ *
+ * @param string $token Token of the share
+ * @return FileDisplayResponse<Http::STATUS_OK, array{Content-Type: string}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>
+ *
+ * 200: Preview returned
+ * 400: Getting preview is not possible
+ * 403: Getting preview is not allowed
+ * 404: Share or preview not found
*/
public function directLink(string $token) {
// No token no image
* @author Bjoern Schiessle <bjoern@schiessle.org>
* @author Joas Schilling <coding@schilljs.com>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
namespace OCA\Files_Sharing\Controller;
use OCA\Files_Sharing\External\Manager;
+use OCA\Files_Sharing\ResponseDefinitions;
+use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSForbiddenException;
use OCP\AppFramework\OCS\OCSNotFoundException;
use OCP\IRequest;
use Psr\Log\LoggerInterface;
+/**
+ * @psalm-import-type FilesSharingRemoteShare from ResponseDefinitions
+ */
class RemoteController extends OCSController {
/**
* @NoAdminRequired
*
* Get list of pending remote shares
*
- * @return DataResponse
+ * @return DataResponse<Http::STATUS_OK, FilesSharingRemoteShare[], array{}>
*/
public function getOpenShares() {
return new DataResponse($this->externalManager->getOpenShares());
*
* Accept a remote share
*
- * @param int $id
- * @return DataResponse
- * @throws OCSNotFoundException
+ * @param int $id ID of the share
+ * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
+ * @throws OCSNotFoundException Share not found
+ *
+ * 200: Share accepted successfully
*/
public function acceptShare($id) {
if ($this->externalManager->acceptShare($id)) {
*
* Decline a remote share
*
- * @param int $id
- * @return DataResponse
- * @throws OCSNotFoundException
+ * @param int $id ID of the share
+ * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
+ * @throws OCSNotFoundException Share not found
+ *
+ * 200: Share declined successfully
*/
public function declineShare($id) {
if ($this->externalManager->declineShare($id)) {
/**
* @NoAdminRequired
*
- * List accepted remote shares
+ * Get a list of accepted remote shares
*
- * @return DataResponse
+ * @return DataResponse<Http::STATUS_OK, FilesSharingRemoteShare[], array{}>
*/
public function getShares() {
$shares = $this->externalManager->getAcceptedShares();
*
* Get info of a remote share
*
- * @param int $id
- * @return DataResponse
- * @throws OCSNotFoundException
+ * @param int $id ID of the share
+ * @return DataResponse<Http::STATUS_OK, FilesSharingRemoteShare, array{}>
+ * @throws OCSNotFoundException Share not found
+ *
+ * 200: Share returned
*/
public function getShare($id) {
$shareInfo = $this->externalManager->getShare($id);
*
* Unshare a remote share
*
- * @param int $id
- * @return DataResponse
- * @throws OCSNotFoundException
- * @throws OCSForbiddenException
+ * @param int $id ID of the share
+ * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
+ * @throws OCSNotFoundException Share not found
+ * @throws OCSForbiddenException Unsharing is not possible
+ *
+ * 200: Share unshared successfully
*/
public function unshare($id) {
$shareInfo = $this->externalManager->getShare($id);
* @author Valdnet <47037905+Valdnet@users.noreply.github.com>
* @author Vincent Petry <vincent@nextcloud.com>
* @author waleczny <michal@walczak.xyz>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
+
namespace OCA\Files_Sharing\Controller;
use Exception;
use OCA\Files\Helper;
use OCA\Files_Sharing\Exceptions\SharingRightsException;
use OCA\Files_Sharing\External\Storage;
+use OCA\Files_Sharing\ResponseDefinitions;
use OCA\Files_Sharing\SharedStorage;
use OCP\App\IAppManager;
+use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\AppFramework\OCS\OCSException;
use Psr\Log\LoggerInterface;
/**
- * Class Share20OCS
- *
* @package OCA\Files_Sharing\API
+ *
+ * @psalm-import-type FilesSharingShare from ResponseDefinitions
*/
class ShareAPIController extends OCSController {
*
* @param \OCP\Share\IShare $share
* @param Node|null $recipientNode
- * @return array
+ * @return FilesSharingShare
* @throws NotFoundException In case the node can't be resolved.
*
* @suppress PhanUndeclaredClassMethod
$result['share_with_displayname_unique'] = $sharedWith !== null ? (
!empty($sharedWith->getSystemEMailAddress()) ? $sharedWith->getSystemEMailAddress() : $sharedWith->getUID()
) : $share->getSharedWith();
- $result['status'] = [];
$userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
$userStatus = array_shift($userStatuses);
$result['share_with_displayname'] = '';
try {
- $result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
+ /** @var array{share_with_displayname: string, share_with_link: string, share_with?: string, token?: string} $roomShare */
+ $roomShare = $this->getRoomShareHelper()->formatShare($share);
+ $result = array_merge($result, $roomShare);
} catch (QueryException $e) {
}
} elseif ($share->getShareType() === IShare::TYPE_DECK) {
$result['share_with_displayname'] = '';
try {
- $result = array_merge($result, $this->getDeckShareHelper()->formatShare($share));
+ /** @var array{share_with: string, share_with_displayname: string, share_with_link: string} $deckShare */
+ $deckShare = $this->getDeckShareHelper()->formatShare($share);
+ $result = array_merge($result, $deckShare);
} catch (QueryException $e) {
}
} elseif ($share->getShareType() === IShare::TYPE_SCIENCEMESH) {
$result['share_with_displayname'] = '';
try {
- $result = array_merge($result, $this->getSciencemeshShareHelper()->formatShare($share));
+ /** @var array{share_with: string, share_with_displayname: string, token: string} $scienceMeshShare */
+ $scienceMeshShare = $this->getSciencemeshShareHelper()->formatShare($share);
+ $result = array_merge($result, $scienceMeshShare);
} catch (QueryException $e) {
}
}
$result['attributes'] = null;
if ($attributes = $share->getAttributes()) {
- $result['attributes'] = \json_encode($attributes->toArray());
+ $result['attributes'] = (string)\json_encode($attributes->toArray());
}
return $result;
/**
+ * @NoAdminRequired
+ *
* Get a specific share by id
*
- * @NoAdminRequired
+ * @param string $id ID of the share
+ * @param bool $include_tags Include tags in the share
+ * @return DataResponse<Http::STATUS_OK, FilesSharingShare, array{}>
+ * @throws OCSNotFoundException Share not found
*
- * @param string $id
- * @param bool $includeTags
- * @return DataResponse
- * @throws OCSNotFoundException
+ * 200: Share returned
*/
public function getShare(string $id, bool $include_tags = false): DataResponse {
try {
}
/**
+ * @NoAdminRequired
+ *
* Delete a share
*
- * @NoAdminRequired
+ * @param string $id ID of the share
+ * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
+ * @throws OCSNotFoundException Share not found
+ * @throws OCSForbiddenException Missing permissions to delete the share
*
- * @param string $id
- * @return DataResponse
- * @throws OCSNotFoundException
+ * 200: Share deleted successfully
*/
public function deleteShare(string $id): DataResponse {
try {
/**
* @NoAdminRequired
*
- * @param string $path
- * @param int $permissions
- * @param int $shareType
- * @param string $shareWith
- * @param string $publicUpload
- * @param string $password
- * @param string $sendPasswordByTalk
- * @param string $expireDate
- * @param string $label
- * @param string $attributes
+ * Create a share
*
- * @return DataResponse
- * @throws NotFoundException
- * @throws OCSBadRequestException
+ * @param string|null $path Path of the share
+ * @param int|null $permissions Permissions for the share
+ * @param int $shareType Type of the share
+ * @param string|null $shareWith The entity this should be shared with
+ * @param string $publicUpload If public uploading is allowed
+ * @param string $password Password for the share
+ * @param string|null $sendPasswordByTalk Send the password for the share over Talk
+ * @param string $expireDate Expiry date of the share
+ * @param string $note Note for the share
+ * @param string $label Label for the share (only used in link and email)
+ * @param string|null $attributes Additional attributes for the share
+ *
+ * @return DataResponse<Http::STATUS_OK, FilesSharingShare, array{}>
+ * @throws OCSBadRequestException Unknown share type
* @throws OCSException
- * @throws OCSForbiddenException
- * @throws OCSNotFoundException
- * @throws InvalidPathException
+ * @throws OCSForbiddenException Creating the share is not allowed
+ * @throws OCSNotFoundException Creating the share failed
* @suppress PhanUndeclaredClassMethod
+ *
+ * 200: Share created
*/
public function createShare(
string $path = null,
* @param null|Node $node
* @param boolean $includeTags
*
- * @return array
+ * @return FilesSharingShare[]
*/
private function getSharedWithMe($node, bool $includeTags): array {
$userShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_USER, $node, -1, 0);
/**
* @param \OCP\Files\Node $folder
*
- * @return array
+ * @return FilesSharingShare[]
* @throws OCSBadRequestException
* @throws NotFoundException
*/
}
/**
- * The getShares function.
- *
* @NoAdminRequired
*
- * @param string $shared_with_me
- * @param string $reshares
- * @param string $subfiles
- * @param string $path
+ * Get shares of the current user
*
- * - Get shares by the current user
- * - Get shares by the current user and reshares (?reshares=true)
- * - Get shares with the current user (?shared_with_me=true)
- * - Get shares for a specific path (?path=...)
- * - Get all shares in a folder (?subfiles=true&path=..)
+ * @param string $shared_with_me Only get shares with the current user
+ * @param string $reshares Only get shares by the current user and reshares
+ * @param string $subfiles Only get all shares in a folder
+ * @param string $path Get shares for a specific path
+ * @param string $include_tags Include tags in the share
*
- * @param string $include_tags
+ * @return DataResponse<Http::STATUS_OK, FilesSharingShare[], array{}>
+ * @throws OCSNotFoundException The folder was not found or is inaccessible
*
- * @return DataResponse
- * @throws NotFoundException
- * @throws OCSBadRequestException
- * @throws OCSNotFoundException
+ * 200: Shares returned
*/
public function getShares(
string $shared_with_me = 'false',
* @param bool $subFiles
* @param bool $includeTags
*
- * @return array
+ * @return FilesSharingShare[]
* @throws NotFoundException
* @throws OCSBadRequestException
*/
/**
- * The getInheritedShares function.
- * returns all shares relative to a file, including parent folders shares rights.
- *
* @NoAdminRequired
*
- * @param string $path
+ * Get all shares relative to a file, including parent folders shares rights
*
- * - Get shares by the current user
- * - Get shares by the current user and reshares (?reshares=true)
- * - Get shares with the current user (?shared_with_me=true)
- * - Get shares for a specific path (?path=...)
- * - Get all shares in a folder (?subfiles=true&path=..)
+ * @param string $path Path all shares will be relative to
*
- * @return DataResponse
+ * @return DataResponse<Http::STATUS_OK, FilesSharingShare[], array{}>
* @throws InvalidPathException
* @throws NotFoundException
- * @throws OCSNotFoundException
- * @throws OCSBadRequestException
+ * @throws OCSNotFoundException The given path is invalid
* @throws SharingRightsException
+ *
+ * 200: Shares returned
*/
public function getInheritedShares(string $path): DataResponse {
/**
* @NoAdminRequired
*
- * @param string $id
- * @param int $permissions
- * @param string $password
- * @param string $sendPasswordByTalk
- * @param string $publicUpload
- * @param string $expireDate
- * @param string $note
- * @param string $label
- * @param string $hideDownload
- * @param string $attributes
- * @return DataResponse
- * @throws LockedException
- * @throws NotFoundException
- * @throws OCSBadRequestException
- * @throws OCSForbiddenException
- * @throws OCSNotFoundException
+ * Update a share
+ *
+ * @param string $id ID of the share
+ * @param int|null $permissions New permissions
+ * @param string|null $password New password
+ * @param string|null $sendPasswordByTalk New condition if the password should be send over Talk
+ * @param string|null $publicUpload New condition if public uploading is allowed
+ * @param string|null $expireDate New expiry date
+ * @param string|null $note New note
+ * @param string|null $label New label
+ * @param string|null $hideDownload New condition if the download should be hidden
+ * @param string|null $attributes New additional attributes
+ * @return DataResponse<Http::STATUS_OK, FilesSharingShare, array{}>
+ * @throws OCSBadRequestException Share could not be updated because the requested changes are invalid
+ * @throws OCSForbiddenException Missing permissions to update the share
+ * @throws OCSNotFoundException Share not found
+ *
+ * 200: Share updated successfully
*/
public function updateShare(
string $id,
/**
* @NoAdminRequired
+ *
+ * Get all shares that are still pending
+ *
+ * @return DataResponse<Http::STATUS_OK, FilesSharingShare[], array{}>
*/
public function pendingShares(): DataResponse {
$pendingShares = [];
try {
$formattedShare = $this->formatShare($share, $node);
- $formattedShare['status'] = $share->getStatus();
$formattedShare['path'] = '/' . $share->getNode()->getName();
$formattedShare['permissions'] = 0;
return $formattedShare;
/**
* @NoAdminRequired
*
- * @param string $id
- * @return DataResponse
- * @throws OCSNotFoundException
+ * Accept a share
+ *
+ * @param string $id ID of the share
+ * @return DataResponse<Http::STATUS_OK, array<empty>, array{}>
+ * @throws OCSNotFoundException Share not found
* @throws OCSException
- * @throws OCSBadRequestException
+ * @throws OCSBadRequestException Share could not be accepted
+ *
+ * 200: Share accepted successfully
*/
public function acceptShare(string $id): DataResponse {
try {
* @author Sascha Sambale <mastixmc@gmail.com>
* @author Thomas Müller <thomas.mueller@tmit.eu>
* @author Vincent Petry <vincent@nextcloud.com>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license AGPL-3.0
*
use OCA\Files_Sharing\Event\ShareLinkAccessedEvent;
use OCP\Accounts\IAccountManager;
use OCP\AppFramework\AuthPublicShareController;
+use OCP\AppFramework\Http\Attribute\IgnoreOpenAPI;
use OCP\AppFramework\Http\NotFoundResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Defaults;
use OCP\Template;
/**
- * Class ShareController
- *
* @package OCA\Files_Sharing\Controllers
*/
+#[IgnoreOpenAPI]
class ShareController extends AuthPublicShareController {
protected ?Share\IShare $share = null;
*
* @author Morris Jobke <hey@morrisjobke.de>
* @author Roeland Jago Douma <roeland@famdouma.nl>
+ * @author Kate Döen <kate.doeen@nextcloud.com>
*
* @license GNU AGPL version 3 or any later version
*
namespace OCA\Files_Sharing\Controller;
use OCA\Files_External\NotFoundException;
+use OCA\Files_Sharing\ResponseDefinitions;
use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Share\Exceptions\ShareNotFound;
use OCP\Share\IManager;
+/**
+ * @psalm-import-type FilesSharingShareInfo from ResponseDefinitions
+ */
class ShareInfoController extends ApiController {
/** @var IManager */
* @NoCSRFRequired
* @BruteForceProtection(action=shareinfo)
*
- * @param string $t
- * @param ?string $password
- * @param ?string $dir
- * @return JSONResponse
+ * Get the info about a share
+ *
+ * @param string $t Token of the share
+ * @param string|null $password Password of the share
+ * @param string|null $dir Subdirectory to get info about
+ * @param int $depth Maximum depth to get info about
+ * @return JSONResponse<Http::STATUS_OK, FilesSharingShareInfo, array{}>|JSONResponse<Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>
+ *
+ * 200: Share info returned
+ * 403: Getting share info is not allowed
+ * 404: Share not found
*/
public function info(string $t, ?string $password = null, ?string $dir = null, int $depth = -1): JSONResponse {
try {
return new JSONResponse($this->parseNode($node, $permissionMask, $depth));
}
+ /**
+ * @return FilesSharingShareInfo
+ */
private function parseNode(Node $node, int $permissionMask, int $depth): array {
if ($node instanceof File) {
return $this->parseFile($node, $permissionMask);
return $this->parseFolder($node, $permissionMask, $depth);
}
+ /**
+ * @return FilesSharingShareInfo
+ */
private function parseFile(File $file, int $permissionMask): array {
return $this->format($file, $permissionMask);
}
+ /**
+ * @return FilesSharingShareInfo
+ */
private function parseFolder(Folder $folder, int $permissionMask, int $depth): array {
$data = $this->format($folder, $permissionMask);
return $data;
}
+ /**
+ * @return FilesSharingShareInfo
+ */
private function format(Node $node, int $permissionMask): array {
$entry = [];
use function array_values;
use Generator;
use OC\Collaboration\Collaborators\SearchResult;
+use OCA\Files_Sharing\ResponseDefinitions;
+use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\AppFramework\OCSController;
use OCP\Share\IManager;
use function usort;
+/**
+ * @psalm-import-type FilesSharingShareesSearchResult from ResponseDefinitions
+ * @psalm-import-type FilesSharingShareesRecommendedResult from ResponseDefinitions
+ */
class ShareesAPIController extends OCSController {
/** @var string */
/** @var int */
protected $limit = 10;
- /** @var array */
+ /** @var FilesSharingShareesSearchResult */
protected $result = [
'exact' => [
'users' => [],
/**
* @NoAdminRequired
*
- * @param string $search
- * @param string $itemType
- * @param int $page
- * @param int $perPage
- * @param int|int[] $shareType
- * @param bool $lookup
- * @return DataResponse
- * @throws OCSBadRequestException
+ * Search for sharees
+ *
+ * @param string $search Text to search for
+ * @param string|null $itemType Limit to specific item types
+ * @param int $page Page offset for searching
+ * @param int $perPage Limit amount of search results per page
+ * @param int|int[]|null $shareType Limit to specific share types
+ * @param bool $lookup If a global lookup should be performed too
+ * @return DataResponse<Http::STATUS_OK, FilesSharingShareesSearchResult, array{Link?: string}>
+ * @throws OCSBadRequestException Invalid search parameters
+ *
+ * 200: Sharees search result returned
*/
public function search(string $search = '', string $itemType = null, int $page = 1, int $perPage = 200, $shareType = null, bool $lookup = false): DataResponse {
$response = new DataResponse($this->result);
if ($hasMoreResults) {
- $response->addHeader('Link', $this->getPaginationLink($page, [
+ $response->setHeaders(['Link' => $this->getPaginationLink($page, [
'search' => $search,
'itemType' => $itemType,
'shareType' => $shareTypes,
'perPage' => $perPage,
- ]));
+ ])]);
}
return $response;
/**
* @NoAdminRequired
*
- * @param string $itemType
- * @return DataResponse
- * @throws OCSBadRequestException
+ * Find recommended sharees
+ *
+ * @param string $itemType Limit to specific item types
+ * @param int|int[]|null $shareType Limit to specific share types
+ * @return DataResponse<Http::STATUS_OK, FilesSharingShareesRecommendedResult, array{}>
*/
- public function findRecommended(string $itemType = null, $shareType = null): DataResponse {
+ public function findRecommended(string $itemType, $shareType = null): DataResponse {
$shareTypes = [
IShare::TYPE_USER,
];
- if ($itemType === null) {
- throw new OCSBadRequestException('Missing itemType');
- } elseif ($itemType === 'file' || $itemType === 'folder') {
+ if ($itemType === 'file' || $itemType === 'folder') {
if ($this->shareManager->allowGroupSharing()) {
$shareTypes[] = IShare::TYPE_GROUP;
}
--- /dev/null
+<?php
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @author Kate Döen <kate.doeen@nextcloud.com>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * 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/>.
+ *
+ */
+
+namespace OCA\Files_Sharing;
+
+/**
+ * @psalm-type FilesSharingShare = array{
+ * attributes: ?string,
+ * can_delete: bool,
+ * can_edit: bool,
+ * displayname_file_owner: string,
+ * displayname_owner: string,
+ * expiration: ?string,
+ * file_parent: int,
+ * file_source: int,
+ * file_target: string,
+ * has_preview: bool,
+ * hide_download: 0|1,
+ * id: string,
+ * item_mtime: int,
+ * item_permissions?: int,
+ * item_size: float|int,
+ * item_source: int,
+ * item_type: 'file'|'folder',
+ * label: string,
+ * mail_send: 0|1,
+ * mimetype: string,
+ * note: string,
+ * parent: null,
+ * password?: string,
+ * password_expiration_time?: ?string,
+ * path: ?string,
+ * permissions: int,
+ * send_password_by_talk?: bool,
+ * share_type: int,
+ * share_with?: string,
+ * share_with_avatar?: string,
+ * share_with_displayname?: string,
+ * share_with_displayname_unique?: ?string,
+ * share_with_link?: string,
+ * status?: array{clearAt?: int|null, icon?: ?string, message?: ?string, status?: string},
+ * stime: int,
+ * storage: int,
+ * storage_id: string,
+ * token: ?string,
+ * uid_file_owner: string,
+ * uid_owner: string,
+ * url?: string,
+ * }
+ *
+ * @psalm-type FilesSharingDeletedShare = array{
+ * id: string,
+ * share_type: int,
+ * uid_owner: string,
+ * displayname_owner: string,
+ * permissions: int,
+ * stime: int,
+ * uid_file_owner: string,
+ * displayname_file_owner: string,
+ * path: string,
+ * item_type: string,
+ * mimetype: string,
+ * storage: int,
+ * item_source: int,
+ * file_source: int,
+ * file_parent: int,
+ * file_target: int,
+ * expiration: string|null,
+ * share_with: string|null,
+ * share_with_displayname: string|null,
+ * share_with_link: string|null,
+ * }
+ *
+ * @psalm-type FilesSharingRemoteShare = array{
+ * accepted: bool,
+ * file_id: int|null,
+ * id: int,
+ * mimetype: string|null,
+ * mountpoint: string,
+ * mtime: int|null,
+ * name: string,
+ * owner: string,
+ * parent: int|null,
+ * permissions: int|null,
+ * remote: string,
+ * remote_id: string,
+ * share_token: string,
+ * share_type: int,
+ * type: string|null,
+ * user: string,
+ * }
+ *
+ * @psalm-type FilesSharingSharee = array{
+ * count: int|null,
+ * label: string,
+ * }
+ *
+ * @psalm-type FilesSharingShareeValue = array{
+ * shareType: int,
+ * shareWith: string,
+ * }
+ *
+ * @psalm-type FilesSharingShareeUser = FilesSharingSharee&array{
+ * subline: string,
+ * icon: string,
+ * shareWithDisplayNameUnique: string,
+ * status: array{
+ * status: string,
+ * message: string,
+ * icon: string,
+ * clearAt: int|null,
+ * },
+ * value: FilesSharingShareeValue,
+ * }
+ *
+ * @psalm-type FilesSharingShareeRemoteGroup = FilesSharingSharee&array{
+ * guid: string,
+ * name: string,
+ * value: FilesSharingShareeValue&array{
+ * server: string,
+ * }
+ * }
+ *
+ * @psalm-type FilesSharingLookup = array{
+ * value: string,
+ * verified: int,
+ * }
+ *
+ * @psalm-type FilesSharingShareeLookup = FilesSharingSharee&array{
+ * extra: array{
+ * federationId: string,
+ * name: FilesSharingLookup|null,
+ * email: FilesSharingLookup|null,
+ * address: FilesSharingLookup|null,
+ * website: FilesSharingLookup|null,
+ * twitter: FilesSharingLookup|null,
+ * phone: FilesSharingLookup|null,
+ * twitter_signature: FilesSharingLookup|null,
+ * website_signature: FilesSharingLookup|null,
+ * userid: FilesSharingLookup|null,
+ * },
+ * value: FilesSharingShareeValue&array{
+ * globalScale: bool,
+ * }
+ * }
+ *
+ * @psalm-type FilesSharingShareeEmail = FilesSharingSharee&array{
+ * uuid: string,
+ * name: string,
+ * type: string,
+ * shareWithDisplayNameUnique: string,
+ * value: FilesSharingShareeValue,
+ * }
+ *
+ * @psalm-type FilesSharingShareeRemote = FilesSharingSharee&array{
+ * uuid: string,
+ * name: string,
+ * type: string,
+ * value: FilesSharingShareeValue&array{
+ * server: string,
+ * }
+ * }
+ *
+ * @psalm-type FilesSharingShareeCircle = FilesSharingSharee&array{
+ * shareWithDescription: string,
+ * value: FilesSharingShareeValue&array{
+ * circle: string,
+ * }
+ * }
+ *
+ * @psalm-type FilesSharingShareesSearchResult = array{
+ * exact: array{
+ * circles: FilesSharingShareeCircle[],
+ * emails: FilesSharingShareeEmail[],
+ * groups: FilesSharingSharee[],
+ * remote_groups: FilesSharingShareeRemoteGroup[],
+ * remotes: FilesSharingShareeRemote[],
+ * rooms: FilesSharingSharee[],
+ * users: FilesSharingShareeUser[],
+ * },
+ * circles: FilesSharingShareeCircle[],
+ * emails: FilesSharingShareeEmail[],
+ * groups: FilesSharingSharee[],
+ * lookup: FilesSharingShareeLookup[],
+ * remote_groups: FilesSharingShareeRemoteGroup[],
+ * remotes: FilesSharingShareeRemote[],
+ * rooms: FilesSharingSharee[],
+ * users: FilesSharingShareeUser[],
+ * lookupEnabled: bool,
+ * }
+ *
+ * @psalm-type FilesSharingShareesRecommendedResult = array{
+ * exact: array{
+ * emails: FilesSharingShareeEmail[],
+ * groups: FilesSharingSharee[],
+ * remote_groups: FilesSharingShareeRemoteGroup[],
+ * remotes: FilesSharingShareeRemote[],
+ * users: FilesSharingShareeUser[],
+ * },
+ * emails: FilesSharingShareeEmail[],
+ * groups: FilesSharingSharee[],
+ * remote_groups: FilesSharingShareeRemoteGroup[],
+ * remotes: FilesSharingShareeRemote[],
+ * users: FilesSharingShareeUser[],
+ * }
+ *
+ * @psalm-type FilesSharingShareInfo = array{
+ * id: int,
+ * parentId: int,
+ * mtime: int,
+ * name: string,
+ * permissions: int,
+ * mimetype: string,
+ * size: int|float,
+ * type: string,
+ * etag: string,
+ * children?: array<string, mixed>[],
+ * }
+ */
+class ResponseDefinitions {
+}
"file_source",
"file_target",
"has_preview",
+ "hide_download",
"id",
+ "item_mtime",
+ "item_size",
"item_source",
"item_type",
"label",
"mail_send",
"mimetype",
"note",
- "password",
- "password_expiration_time",
+ "parent",
"path",
"permissions",
- "send_password_by_talk",
"share_type",
- "share_with",
- "share_with_avatar",
- "share_with_displayname",
- "share_with_link",
- "status",
"stime",
"storage",
"storage_id",
"token",
"uid_file_owner",
- "uid_owner",
- "url"
+ "uid_owner"
],
"properties": {
"attributes": {
"has_preview": {
"type": "boolean"
},
+ "hide_download": {
+ "type": "integer",
+ "format": "int64"
+ },
"id": {
"type": "string"
},
+ "item_mtime": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "item_permissions": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "item_size": {
+ "oneOf": [
+ {
+ "type": "number",
+ "format": "float"
+ },
+ {
+ "type": "integer",
+ "format": "int64"
+ }
+ ]
+ },
"item_source": {
"type": "integer",
"format": "int64"
},
"item_type": {
- "type": "string"
+ "type": "string",
+ "enum": [
+ "file",
+ "folder"
+ ]
},
"label": {
"type": "string"
"note": {
"type": "string"
},
- "password": {
- "type": "string",
+ "parent": {
"nullable": true
},
+ "password": {
+ "type": "string"
+ },
"password_expiration_time": {
"type": "string",
"nullable": true
},
"path": {
- "type": "string"
+ "type": "string",
+ "nullable": true
},
"permissions": {
"type": "integer",
"format": "int64"
},
"send_password_by_talk": {
- "type": "boolean",
- "nullable": true
+ "type": "boolean"
},
"share_type": {
"type": "integer",
"format": "int64"
},
"share_with": {
- "type": "string",
- "nullable": true
+ "type": "string"
},
"share_with_avatar": {
- "type": "string",
- "nullable": true
+ "type": "string"
},
"share_with_displayname": {
+ "type": "string"
+ },
+ "share_with_displayname_unique": {
"type": "string",
"nullable": true
},
"share_with_link": {
- "type": "string",
- "nullable": true
+ "type": "string"
},
"status": {
- "nullable": true,
- "oneOf": [
- {
- "type": "object",
- "required": [
- "status",
- "message",
- "icon",
- "clearAt"
- ],
- "properties": {
- "status": {
- "type": "string"
- },
- "message": {
- "type": "string",
- "nullable": true
- },
- "icon": {
- "type": "string",
- "nullable": true
- },
- "clearAt": {
- "type": "integer",
- "format": "int64",
- "nullable": true
- }
- }
- },
- {
+ "type": "object",
+ "properties": {
+ "clearAt": {
"type": "integer",
- "format": "int64"
+ "format": "int64",
+ "nullable": true
+ },
+ "icon": {
+ "type": "string",
+ "nullable": true
+ },
+ "message": {
+ "type": "string",
+ "nullable": true
+ },
+ "status": {
+ "type": "string"
}
- ]
+ }
},
"stime": {
"type": "integer",
"type": "string"
},
"url": {
- "type": "string",
- "nullable": true
+ "type": "string"
}
}
},
"mimetype",
"size",
"type",
- "etag",
- "children"
+ "etag"
],
"properties": {
"id": {
"type": "string"
},
"size": {
- "type": "integer",
- "format": "int64"
+ "oneOf": [
+ {
+ "type": "integer",
+ "format": "int64"
+ },
+ {
+ "type": "number",
+ "format": "float"
+ }
+ ]
},
"type": {
"type": "string"
},
"children": {
"type": "array",
- "nullable": true,
"items": {
"type": "object",
"additionalProperties": {
}
},
"paths": {
+ "/index.php/s/{token}/preview": {
+ "get": {
+ "operationId": "public_preview-direct-link",
+ "summary": "Get a direct link preview for a shared file",
+ "tags": [
+ "public_preview"
+ ],
+ "security": [
+ {},
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "token",
+ "in": "path",
+ "description": "Token of the share",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "default": "true"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Preview returned",
+ "content": {
+ "*/*": {
+ "schema": {
+ "type": "string",
+ "format": "binary"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Getting preview is not possible",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Getting preview is not allowed",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Share or preview not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/index.php/apps/files_sharing/publicpreview/{token}": {
+ "get": {
+ "operationId": "public_preview-get-preview",
+ "summary": "Get a preview for a shared file",
+ "tags": [
+ "public_preview"
+ ],
+ "security": [
+ {},
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "file",
+ "in": "query",
+ "description": "File in the share",
+ "schema": {
+ "type": "string",
+ "default": ""
+ }
+ },
+ {
+ "name": "x",
+ "in": "query",
+ "description": "Width of the preview",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 32
+ }
+ },
+ {
+ "name": "y",
+ "in": "query",
+ "description": "Height of the preview",
+ "schema": {
+ "type": "integer",
+ "format": "int64",
+ "default": 32
+ }
+ },
+ {
+ "name": "a",
+ "in": "query",
+ "description": "Whether to not crop the preview",
+ "schema": {
+ "type": "integer",
+ "default": 0
+ }
+ },
+ {
+ "name": "token",
+ "in": "path",
+ "description": "Token of the share",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "required": true,
+ "schema": {
+ "type": "string",
+ "default": "true"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Preview returned",
+ "content": {
+ "*/*": {
+ "schema": {
+ "type": "string",
+ "format": "binary"
+ }
+ }
+ }
+ },
+ "400": {
+ "description": "Getting preview is not possible",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "403": {
+ "description": "Getting preview is not allowed",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "Share or preview not found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/index.php/apps/files_sharing/shareinfo": {
"post": {
"operationId": "share_info-info",
"schema": {
"type": "integer",
"format": "int64",
- "default": 1
+ "default": -1
}
}
],
}
},
"403": {
- "description": "Getting share info not allowed",
+ "description": "Getting share info is not allowed",
"content": {
"application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": true
- }
+ "schema": {}
}
}
},
"description": "Share not found",
"content": {
"application/json": {
- "schema": {
- "type": "object",
- "additionalProperties": true
- }
+ "schema": {}
}
}
}
"schema": {
"type": "integer",
"format": "int64",
- "default": 1
+ "default": -1
}
},
{
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
- "data": {
- "type": "object",
- "additionalProperties": true
- }
+ "data": {}
}
}
}
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
- "data": {
- "type": "object",
- "additionalProperties": true
- }
+ "data": {}
}
}
}
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
- "data": {
- "type": "object",
- "additionalProperties": true
- }
+ "data": {}
}
}
}
"responses": {
"200": {
"description": "Sharees search result returned",
+ "headers": {
+ "Link": {
+ "schema": {
+ "type": "string"
+ }
+ }
+ },
"content": {
"application/json": {
"schema": {
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
- "data": {
- "type": "object",
- "additionalProperties": true
- }
+ "data": {}
}
}
}
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
- "data": {
- "type": "object",
- "additionalProperties": true
- }
+ "data": {}
}
}
}
"meta": {
"$ref": "#/components/schemas/OCSMeta"
},
- "data": {
- "type": "object",
- "additionalProperties": true
- }
+ "data": {}
}
}
}
}
},
"403": {
- "description": "Unsharing not possible",
+ "description": "Unsharing is not possible",
"content": {
"text/plain": {
"schema": {
}
},
"tags": [
- {
- "name": "share",
- "description": "Class ShareController"
- },
{
"name": "external_shares",
"description": "Class ExternalSharesController"
'hide_download' => 0,
'can_edit' => false,
'can_delete' => false,
- 'status' => [],
'item_size' => 123465,
'item_mtime' => 1234567890,
'attributes' => null,
'hide_download' => 0,
'can_edit' => false,
'can_delete' => false,
- 'status' => [],
'item_size' => 123456,
'item_mtime' => 1234567890,
'attributes' => '[{"scope":"permissions","key":"download","enabled":true}]',
'hide_download' => 0,
'can_edit' => false,
'can_delete' => false,
- 'status' => [],
'item_size' => 123456,
'item_mtime' => 1234567890,
'attributes' => '[{"scope":"permissions","key":"download","enabled":true}]',
'hide_download' => 0,
'can_edit' => false,
'can_delete' => false,
- 'status' => [],
'item_size' => 123456,
'item_mtime' => 1234567890,
'attributes' => null,
'hide_download' => 0,
'can_edit' => true,
'can_delete' => true,
- 'status' => [],
'item_size' => 123456,
'item_mtime' => 1234567890,
'attributes' => null,
'hide_download' => 0,
'can_edit' => true,
'can_delete' => true,
- 'status' => [],
'item_size' => 123456,
'item_mtime' => 1234567890,
'attributes' => null,