瀏覽代碼

Add a transfer ownership background job

This job can be initiated by a user to transfer a file/folder to a
target user.

The target user will have to accept the job.
Once that is done the transfers is initiated in the background.

Both parties get notified when the job is done.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
tags/v18.0.0beta1
Roeland Jago Douma 4 年之前
父節點
當前提交
5274c54268
No account linked to committer's email address

+ 2
- 0
.gitattributes 查看文件

@@ -5,6 +5,8 @@
/apps/accessibility/js/accessibility.js.map binary
/apps/comments/js/*.js binary
/apps/comments/js/*.js.map binary
/apps/files/js/dist/*.js binary
/apps/files/js/dist/*.js.map binary
/apps/files_sharing/js/dist/*.js binary
/apps/files_sharing/js/dist/*.js.map binary
/apps/files_versions/js/files_versions.js binary

+ 4
- 0
apps/files/appinfo/info.xml 查看文件

@@ -65,4 +65,8 @@
</navigation>
</navigations>

<settings>
<personal>OCA\Files\Settings\PersonalSettings</personal>
</settings>

</info>

+ 16
- 1
apps/files/appinfo/routes.php 查看文件

@@ -119,7 +119,22 @@ $application->registerRoutes(
'url' => '/api/v1/directEditing/create',
'verb' => 'POST'
],
]
[
'name' => 'TransferOwnership#transfer',
'url' => '/api/v1/transferownership',
'verb' => 'POST',
],
[
'name' => 'TransferOwnership#accept',
'url' => '/api/v1/transferownership/{id}',
'verb' => 'POST',
],
[
'name' => 'TransferOwnership#reject',
'url' => '/api/v1/transferownership/{id}',
'verb' => 'DELETE',
],
],
]
);


+ 7
- 0
apps/files/composer/composer/autoload_classmap.php 查看文件

@@ -23,6 +23,7 @@ return array(
'OCA\\Files\\BackgroundJob\\CleanupFileLocks' => $baseDir . '/../lib/BackgroundJob/CleanupFileLocks.php',
'OCA\\Files\\BackgroundJob\\DeleteOrphanedItems' => $baseDir . '/../lib/BackgroundJob/DeleteOrphanedItems.php',
'OCA\\Files\\BackgroundJob\\ScanFiles' => $baseDir . '/../lib/BackgroundJob/ScanFiles.php',
'OCA\\Files\\BackgroundJob\\TransferOwnership' => $baseDir . '/../lib/BackgroundJob/TransferOwnership.php',
'OCA\\Files\\Capabilities' => $baseDir . '/../lib/Capabilities.php',
'OCA\\Files\\Collaboration\\Resources\\Listener' => $baseDir . '/../lib/Collaboration/Resources/Listener.php',
'OCA\\Files\\Collaboration\\Resources\\ResourceProvider' => $baseDir . '/../lib/Collaboration/Resources/ResourceProvider.php',
@@ -34,13 +35,19 @@ return array(
'OCA\\Files\\Controller\\ApiController' => $baseDir . '/../lib/Controller/ApiController.php',
'OCA\\Files\\Controller\\DirectEditingController' => $baseDir . '/../lib/Controller/DirectEditingController.php',
'OCA\\Files\\Controller\\DirectEditingViewController' => $baseDir . '/../lib/Controller/DirectEditingViewController.php',
'OCA\\Files\\Controller\\TransferOwnershipController' => $baseDir . '/../lib/Controller/TransferOwnershipController.php',
'OCA\\Files\\Controller\\ViewController' => $baseDir . '/../lib/Controller/ViewController.php',
'OCA\\Files\\Db\\TransferOwnership' => $baseDir . '/../lib/Db/TransferOwnership.php',
'OCA\\Files\\Db\\TransferOwnershipMapper' => $baseDir . '/../lib/Db/TransferOwnershipMapper.php',
'OCA\\Files\\Event\\LoadAdditionalScriptsEvent' => $baseDir . '/../lib/Event/LoadAdditionalScriptsEvent.php',
'OCA\\Files\\Event\\LoadSidebar' => $baseDir . '/../lib/Event/LoadSidebar.php',
'OCA\\Files\\Exception\\TransferOwnershipException' => $baseDir . '/../lib/Exception/TransferOwnershipException.php',
'OCA\\Files\\Helper' => $baseDir . '/../lib/Helper.php',
'OCA\\Files\\Listener\\LegacyLoadAdditionalScriptsAdapter' => $baseDir . '/../lib/Listener/LegacyLoadAdditionalScriptsAdapter.php',
'OCA\\Files\\Migration\\Version11301Date20191113195931' => $baseDir . '/../lib/Migration/Version11301Date20191113195931.php',
'OCA\\Files\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
'OCA\\Files\\Service\\DirectEditingService' => $baseDir . '/../lib/Service/DirectEditingService.php',
'OCA\\Files\\Service\\OwnershipTransferService' => $baseDir . '/../lib/Service/OwnershipTransferService.php',
'OCA\\Files\\Service\\TagService' => $baseDir . '/../lib/Service/TagService.php',
'OCA\\Files\\Settings\\PersonalSettings' => $baseDir . '/../lib/Settings/PersonalSettings.php',
);

+ 7
- 0
apps/files/composer/composer/autoload_static.php 查看文件

@@ -38,6 +38,7 @@ class ComposerStaticInitFiles
'OCA\\Files\\BackgroundJob\\CleanupFileLocks' => __DIR__ . '/..' . '/../lib/BackgroundJob/CleanupFileLocks.php',
'OCA\\Files\\BackgroundJob\\DeleteOrphanedItems' => __DIR__ . '/..' . '/../lib/BackgroundJob/DeleteOrphanedItems.php',
'OCA\\Files\\BackgroundJob\\ScanFiles' => __DIR__ . '/..' . '/../lib/BackgroundJob/ScanFiles.php',
'OCA\\Files\\BackgroundJob\\TransferOwnership' => __DIR__ . '/..' . '/../lib/BackgroundJob/TransferOwnership.php',
'OCA\\Files\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php',
'OCA\\Files\\Collaboration\\Resources\\Listener' => __DIR__ . '/..' . '/../lib/Collaboration/Resources/Listener.php',
'OCA\\Files\\Collaboration\\Resources\\ResourceProvider' => __DIR__ . '/..' . '/../lib/Collaboration/Resources/ResourceProvider.php',
@@ -49,15 +50,21 @@ class ComposerStaticInitFiles
'OCA\\Files\\Controller\\ApiController' => __DIR__ . '/..' . '/../lib/Controller/ApiController.php',
'OCA\\Files\\Controller\\DirectEditingController' => __DIR__ . '/..' . '/../lib/Controller/DirectEditingController.php',
'OCA\\Files\\Controller\\DirectEditingViewController' => __DIR__ . '/..' . '/../lib/Controller/DirectEditingViewController.php',
'OCA\\Files\\Controller\\TransferOwnershipController' => __DIR__ . '/..' . '/../lib/Controller/TransferOwnershipController.php',
'OCA\\Files\\Controller\\ViewController' => __DIR__ . '/..' . '/../lib/Controller/ViewController.php',
'OCA\\Files\\Db\\TransferOwnership' => __DIR__ . '/..' . '/../lib/Db/TransferOwnership.php',
'OCA\\Files\\Db\\TransferOwnershipMapper' => __DIR__ . '/..' . '/../lib/Db/TransferOwnershipMapper.php',
'OCA\\Files\\Event\\LoadAdditionalScriptsEvent' => __DIR__ . '/..' . '/../lib/Event/LoadAdditionalScriptsEvent.php',
'OCA\\Files\\Event\\LoadSidebar' => __DIR__ . '/..' . '/../lib/Event/LoadSidebar.php',
'OCA\\Files\\Exception\\TransferOwnershipException' => __DIR__ . '/..' . '/../lib/Exception/TransferOwnershipException.php',
'OCA\\Files\\Helper' => __DIR__ . '/..' . '/../lib/Helper.php',
'OCA\\Files\\Listener\\LegacyLoadAdditionalScriptsAdapter' => __DIR__ . '/..' . '/../lib/Listener/LegacyLoadAdditionalScriptsAdapter.php',
'OCA\\Files\\Migration\\Version11301Date20191113195931' => __DIR__ . '/..' . '/../lib/Migration/Version11301Date20191113195931.php',
'OCA\\Files\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
'OCA\\Files\\Service\\DirectEditingService' => __DIR__ . '/..' . '/../lib/Service/DirectEditingService.php',
'OCA\\Files\\Service\\OwnershipTransferService' => __DIR__ . '/..' . '/../lib/Service/OwnershipTransferService.php',
'OCA\\Files\\Service\\TagService' => __DIR__ . '/..' . '/../lib/Service/TagService.php',
'OCA\\Files\\Settings\\PersonalSettings' => __DIR__ . '/..' . '/../lib/Settings/PersonalSettings.php',
);

public static function getInitializer(ClassLoader $loader)

+ 36
- 0
apps/files/js/dist/personal-settings.js
文件差異過大導致無法顯示
查看文件


+ 1
- 0
apps/files/js/dist/personal-settings.js.map
文件差異過大導致無法顯示
查看文件


+ 16
- 16
apps/files/js/dist/sidebar.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
apps/files/js/dist/sidebar.js.map
文件差異過大導致無法顯示
查看文件


+ 10
- 2
apps/files/lib/AppInfo/Application.php 查看文件

@@ -35,6 +35,7 @@ use OCA\Files\Controller\ApiController;
use OCA\Files\Controller\ViewController;
use OCA\Files\Event\LoadAdditionalScriptsEvent;
use OCA\Files\Listener\LegacyLoadAdditionalScriptsAdapter;
use OCA\Files\Notification\Notifier;
use OCA\Files\Service\TagService;
use OCP\AppFramework\App;
use OCP\Collaboration\Resources\IManager;
@@ -42,8 +43,11 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\IContainer;

class Application extends App {

public const APP_ID = 'files';

public function __construct(array $urlParams=array()) {
parent::__construct('files', $urlParams);
parent::__construct(self::APP_ID, $urlParams);
$container = $this->getContainer();
$server = $container->getServer();

@@ -71,7 +75,7 @@ class Application extends App {
return new TagService(
$c->query('ServerContainer')->getUserSession(),
$c->query('ServerContainer')->getActivityManager(),
$c->query('ServerContainer')->getTagManager()->load('files'),
$c->query('ServerContainer')->getTagManager()->load(self::APP_ID),
$homeFolder,
$server->getEventDispatcher()
);
@@ -93,5 +97,9 @@ class Application extends App {
/** @var IEventDispatcher $dispatcher */
$dispatcher = $container->query(IEventDispatcher::class);
$dispatcher->addServiceListener(LoadAdditionalScriptsEvent::class, LegacyLoadAdditionalScriptsAdapter::class);

/** @var \OCP\Notification\IManager $notifications */
$notifications = $container->query(\OCP\Notification\IManager::class);
$notifications->registerNotifierService(Notifier::class);
}
}

+ 183
- 0
apps/files/lib/BackgroundJob/TransferOwnership.php 查看文件

@@ -0,0 +1,183 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @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\BackgroundJob;

use OCA\Files\AppInfo\Application;
use OCA\Files\Db\TransferOwnership as Transfer;
use OCA\Files\Db\TransferOwnershipMapper;
use OCA\Files\Exception\TransferOwnershipException;
use OCA\Files\Service\OwnershipTransferService;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\QueuedJob;
use OCP\Files\IRootFolder;
use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Notification\IManager as NotificationManager;
use function ltrim;

class TransferOwnership extends QueuedJob {

/** @var IUserManager $userManager */
private $userManager;

/** @var OwnershipTransferService */
private $transferService;

/** @var ILogger */
private $logger;

/** @var NotificationManager */
private $notificationManager;

/** @var TransferOwnershipMapper */
private $mapper;
/** @var IRootFolder */
private $rootFolder;

public function __construct(ITimeFactory $timeFactory,
IUserManager $userManager,
OwnershipTransferService $transferService,
ILogger $logger,
NotificationManager $notificationManager,
TransferOwnershipMapper $mapper,
IRootFolder $rootFolder) {
parent::__construct($timeFactory);

$this->userManager = $userManager;
$this->transferService = $transferService;
$this->logger = $logger;
$this->notificationManager = $notificationManager;
$this->mapper = $mapper;
$this->rootFolder = $rootFolder;
}

protected function run($argument) {
$id = $argument['id'];

$transfer = $this->mapper->getById($id);
$sourceUser = $transfer->getSourceUser();
$destinationUser = $transfer->getTargetUser();
$fileId = $transfer->getFileId();

$userFolder = $this->rootFolder->getUserFolder($sourceUser);
$nodes = $userFolder->getById($fileId);

if (empty($nodes)) {
$this->logger->alert('Could not transfer ownership: Node not found');
$this->failedNotication($transfer);
return;
}
$path = $userFolder->getRelativePath($nodes[0]->getPath());

$sourceUserObject = $this->userManager->get($sourceUser);
$destinationUserObject = $this->userManager->get($destinationUser);

if (!$sourceUserObject instanceof IUser) {
$this->logger->alert('Could not transfer ownership: Unknown source user ' . $sourceUser);
$this->failedNotication($transfer);
return;
}

if (!$destinationUserObject instanceof IUser) {
$this->logger->alert("Unknown destination user $destinationUser");
$this->failedNotication($transfer);
return;
}

try {
$this->transferService->transfer(
$sourceUserObject,
$destinationUserObject,
ltrim($path, '/')
);
$this->successNotification($transfer);
} catch (TransferOwnershipException $e) {
$this->logger->logException($e);
$this->failedNotication($transfer);
}

$this->mapper->delete($transfer);

}

private function failedNotication(Transfer $transfer): void {
// Send notification to source user
$notification = $this->notificationManager->createNotification();
$notification->setUser($transfer->getSourceUser())
->setApp(Application::APP_ID)
->setDateTime($this->time->getDateTime())
->setSubject('transferOwnershipFailedSource', [
'sourceUser' => $transfer->getSourceUser(),
'targetUser' => $transfer->getTargetUser(),
'nodeName' => $transfer->getNodeName(),
])
->setObject('transfer', (string)$transfer->getId());
$this->notificationManager->notify($notification);

// Send notification to source user
$notification = $this->notificationManager->createNotification();
$notification->setUser($transfer->getTargetUser())
->setApp(Application::APP_ID)
->setDateTime($this->time->getDateTime())
->setSubject('transferOwnershipFailedTarget', [
'sourceUser' => $transfer->getSourceUser(),
'targetUser' => $transfer->getTargetUser(),
'nodeName' => $transfer->getNodeName(),
])
->setObject('transfer', (string)$transfer->getId());
$this->notificationManager->notify($notification);
}

private function successNotification(Transfer $transfer): void {
// Send notification to source user
$notification = $this->notificationManager->createNotification();
$notification->setUser($transfer->getSourceUser())
->setApp(Application::APP_ID)
->setDateTime($this->time->getDateTime())
->setSubject('transferOwnershipDoneSource', [
'sourceUser' => $transfer->getSourceUser(),
'targetUser' => $transfer->getTargetUser(),
'nodeName' => $transfer->getNodeName(),
])
->setObject('transfer', (string)$transfer->getId());
$this->notificationManager->notify($notification);

// Send notification to source user
$notification = $this->notificationManager->createNotification();
$notification->setUser($transfer->getTargetUser())
->setApp(Application::APP_ID)
->setDateTime($this->time->getDateTime())
->setSubject('transferOwnershipDoneTarget', [
'sourceUser' => $transfer->getSourceUser(),
'targetUser' => $transfer->getTargetUser(),
'nodeName' => $transfer->getNodeName(),
])
->setObject('transfer', (string)$transfer->getId());
$this->notificationManager->notify($notification);
}
}

+ 181
- 0
apps/files/lib/Controller/TransferOwnershipController.php 查看文件

@@ -0,0 +1,181 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @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\Controller;

use OCA\Files\BackgroundJob\TransferOwnership;
use OCA\Files\Db\TransferOwnershipMapper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\IJobList;
use OCP\Files\IRootFolder;
use OCP\IRequest;
use OCP\IUserManager;
use OCP\Notification\IManager as NotificationManager;

class TransferOwnershipController extends OCSController {

/** @var string */
private $userId;
/** @var NotificationManager */
private $notificationManager;
/** @var ITimeFactory */
private $timeFactory;
/** @var IJobList */
private $jobList;
/** @var TransferOwnershipMapper */
private $mapper;
/** @var IUserManager */
private $userManager;
/** @var IRootFolder */
private $rootFolder;

public function __construct(string $appName,
IRequest $request,
string $userId,
NotificationManager $notificationManager,
ITimeFactory $timeFactory,
IJobList $jobList,
TransferOwnershipMapper $mapper,
IUserManager $userManager,
IRootFolder $rootFolder) {
parent::__construct($appName, $request);

$this->userId = $userId;
$this->notificationManager = $notificationManager;
$this->timeFactory = $timeFactory;
$this->jobList = $jobList;
$this->mapper = $mapper;
$this->userManager = $userManager;
$this->rootFolder = $rootFolder;
}


/**
* @NoAdminRequired
*/
public function transfer(string $recipient, string $path): DataResponse {
$recipientUser = $this->userManager->get($recipient);

if ($recipientUser === null) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

$userRoot = $this->rootFolder->getUserFolder($this->userId);

try {
$node = $userRoot->get($path);
} catch (\Exception $e) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

$transferOwnership = new \OCA\Files\Db\TransferOwnership();
$transferOwnership->setSourceUser($this->userId);
$transferOwnership->setTargetUser($recipient);
$transferOwnership->setFileId($node->getId());
$transferOwnership->setNodeName($node->getName());
$transferOwnership = $this->mapper->insert($transferOwnership);

$notification = $this->notificationManager->createNotification();
$notification->setUser($recipient)
->setApp($this->appName)
->setDateTime($this->timeFactory->getDateTime())
->setSubject('transferownershipRequest', [
'sourceUser' => $this->userId,
'targetUser' => $recipient,
'nodeName' => $node->getName(),
])
->setObject('transfer', (string)$transferOwnership->getId());

$this->notificationManager->notify($notification);

return new DataResponse([]);
}

/**
* @NoAdminRequired
*/
public function accept(int $id): DataResponse {
try {
$transferOwnership = $this->mapper->getById($id);
} catch (DoesNotExistException $e) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}

if ($transferOwnership->getTargetUser() !== $this->userId) {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}

$this->jobList->add(TransferOwnership::class, [
'id' => $transferOwnership->getId(),
]);

$notification = $this->notificationManager->createNotification();
$notification->setApp('files')
->setObject('transfer', (string)$id);
$this->notificationManager->markProcessed($notification);

return new DataResponse([], Http::STATUS_OK);
}

/**
* @NoAdminRequired
*/
public function reject(int $id): DataResponse {
try {
$transferOwnership = $this->mapper->getById($id);
} catch (DoesNotExistException $e) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}

if ($transferOwnership->getTargetUser() !== $this->userId) {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}

$notification = $this->notificationManager->createNotification();
$notification->setApp('files')
->setObject('transfer', (string)$id);
$this->notificationManager->markProcessed($notification);

$notification = $this->notificationManager->createNotification();
$notification->setUser($transferOwnership->getSourceUser())
->setApp($this->appName)
->setDateTime($this->timeFactory->getDateTime())
->setSubject('transferownershipRequestDenied', [
'sourceUser' => $transferOwnership->getSourceUser(),
'targetUser' => $transferOwnership->getTargetUser(),
'nodeName' => $transferOwnership->getNodeName()
])
->setObject('transfer', (string)$transferOwnership->getId());
$this->notificationManager->notify($notification);

$this->mapper->delete($transferOwnership);

return new DataResponse([], Http::STATUS_OK);
}

}

+ 60
- 0
apps/files/lib/Db/TransferOwnership.php 查看文件

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @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\Db;

use OCP\AppFramework\Db\Entity;

/**
* @method void setSourceUser(string $uid)
* @method string getSourceUser()
* @method void setTargetUser(string $uid)
* @method string getTargetUser()
* @method void setFileId(int $fileId)
* @method int getFileId()
* @method void setNodeName(string $name)
* @method string getNodeName()
*/
class TransferOwnership extends Entity {
/** @var string */
protected $sourceUser;

/** @var string */
protected $targetUser;

/** @var integer */
protected $fileId;

/** @var string */
protected $nodeName;

public function __construct() {
$this->addType('sourceUser', 'string');
$this->addType('targetUser', 'string');
$this->addType('fileId', 'integer');
$this->addType('nodeName', 'string');
}


}

+ 47
- 0
apps/files/lib/Db/TransferOwnershipMapper.php 查看文件

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @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\Db;

use OCP\AppFramework\Db\QBMapper;
use OCP\IDBConnection;

class TransferOwnershipMapper extends QBMapper {
public function __construct(IDBConnection $db) {
parent::__construct($db, 'user_transfer_ownership', TransferOwnership::class);
}

public function getById(int $id): TransferOwnership {
$qb = $this->db->getQueryBuilder();

$qb->select('*')
->from($this->getTableName())
->where(
$qb->expr()->eq('id', $qb->createNamedParameter($id))
);

return $this->findEntity($qb);
}

}

+ 72
- 0
apps/files/lib/Migration/Version11301Date20191113195931.php 查看文件

@@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @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\Migration;

use Closure;
use OCP\DB\ISchemaWrapper;
use OCP\Migration\SimpleMigrationStep;
use OCP\Migration\IOutput;

class Version11301Date20191113195931 extends SimpleMigrationStep {

/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
* @param array $options
* @return null|ISchemaWrapper
*/
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();

$table = $schema->createTable('user_transfer_ownership');
$table->addColumn('id', 'integer', [
'autoincrement' => true,
'notnull' => true,
'length' => 4,
]);
$table->addColumn('source_user', 'string', [
'notnull' => true,
'length' => 64,
]);
$table->addColumn('target_user', 'string', [
'notnull' => true,
'length' => 64,
]);
$table->addColumn('file_id', 'bigint', [
'notnull' => true,
'length' => 20,
]);
$table->addColumn('node_name', 'string', [
'notnull' => true,
'length' => 255,
]);
$table->setPrimaryKey(['id']);

return $schema;
}

}

+ 243
- 0
apps/files/lib/Notification/Notifier.php 查看文件

@@ -0,0 +1,243 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @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\Notification;

use OCP\IURLGenerator;
use OCP\L10N\IFactory;
use OCP\Notification\IAction;
use OCP\Notification\INotification;
use OCP\Notification\INotifier;

class Notifier implements INotifier {

/** @var IFactory */
protected $l10nFactory;

/** @var IURLGenerator */
protected $urlGenerator;

/**
* @param IFactory $l10nFactory
* @param IURLGenerator $urlGenerator
*/
public function __construct(IFactory $l10nFactory, IURLGenerator $urlGenerator) {
$this->l10nFactory = $l10nFactory;
$this->urlGenerator = $urlGenerator;
}

public function getID(): string {
return 'files';
}

public function getName(): string {
return $this->l10nFactory->get('files')->t('Files');
}

/**
* @param INotification $notification
* @param string $languageCode The code of the language that should be used to prepare the notification
* @return INotification
* @throws \InvalidArgumentException When the notification was not prepared by a notifier
*/
public function prepare(INotification $notification, string $languageCode): INotification {
if ($notification->getApp() !== 'files') {
throw new \InvalidArgumentException('Unhandled app');
}

if ($notification->getSubject() === 'transferownershipRequest') {
return $this->handleTransferownershipRequest($notification, $languageCode);
}
if ($notification->getSubject() === 'transferOwnershipFailedSource') {
return $this->handleTransferOwnershipFailedSource($notification, $languageCode);
}
if ($notification->getSubject() === 'transferOwnershipFailedTarget') {
return $this->handleTransferOwnershipFailedTarget($notification, $languageCode);
}
if ($notification->getSubject() === 'transferOwnershipDoneSource') {
return $this->handleTransferOwnershipDoneSource($notification, $languageCode);
}
if ($notification->getSubject() === 'transferOwnershipDoneTarget') {
return $this->handleTransferOwnershipDoneTarget($notification, $languageCode);
}

throw new \InvalidArgumentException('Unhandled subject');
}

public function handleTransferownershipRequest(INotification $notification, string $languageCode): INotification {
$l = $this->l10nFactory->get('files', $languageCode);
$id = $notification->getObjectId();
$param = $notification->getSubjectParameters();

$approveAction = $notification->createAction()
->setParsedLabel($l->t('Accept'))
->setPrimary(true)
->setLink(
$this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->linkTo(
'',
'ocs/v2.php/apps/files/api/v1/transferownership/' . $id
)
),
IAction::TYPE_POST
);

$disapproveAction = $notification->createAction()
->setParsedLabel($l->t('Decline'))
->setPrimary(false)
->setLink(
$this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->linkTo(
'',
'ocs/v2.php/apps/files/api/v1/transferownership/' . $id
)
),
IAction::TYPE_DELETE
);

$notification->addParsedAction($approveAction)
->addParsedAction($disapproveAction)
->setRichSubject(
$l->t('Incomming file transfer from {user}'),
[
'user' => [
'type' => 'user',
'id' => $param['sourceUser'],
'name' => $param['sourceUser'],
],
])
->setParsedSubject(str_replace('{user}', $param['sourceUser'], $l->t('Incomming file transfer from {user}')))
->setRichMessage(
$l->t('Do you want to accept {path}?'),
[
'path' => [
'type' => 'highlight',
'id' => $param['targetUser'] . '::' . $param['nodeName'],
'name' => $param['nodeName'],
]
])
->setParsedMessage(str_replace('{path}', $param['nodeName'], $l->t('Do you want to accept {path}?')));

return $notification;
}

public function handleTransferOwnershipFailedSource(INotification $notification, string $languageCode): INotification {
$l = $this->l10nFactory->get('files', $languageCode);
$param = $notification->getSubjectParameters();

$notification->setRichSubject($l->t('File transfer failed'))
->setParsedSubject(str_replace(['{path}', '{user}'], [$param['nodeName'], $param['targetUser']], $l->t('Your transfer of {path} to {user} failed.')))
->setRichMessage(
$l->t('Your transfer of {path} to {user} failed.'),
[
'path' => [
'type' => 'highlight',
'id' => $param['targetUser'] . '::' . $param['nodeName'],
'name' => $param['nodeName'],
],
'user' => [
'type' => 'user',
'id' => $param['targetUser'],
'name' => $param['targetUser'],
],
])
->setParsedMessage($l->t('File transfer failed'));
return $notification;
}

public function handleTransferOwnershipFailedTarget(INotification $notification, string $languageCode): INotification {
$l = $this->l10nFactory->get('files', $languageCode);
$param = $notification->getSubjectParameters();

$notification->setRichSubject($l->t('File transfer failed'))
->setParsedSubject(str_replace(['{path}', '{user}'], [$param['nodeName'], $param['sourceUser']], $l->t('The transfer of {path} from {user} failed.')))
->setRichMessage(
$l->t('The transfer of {path} from {user} failed.'),
[
'path' => [
'type' => 'highlight',
'id' => $param['sourceUser'] . '::' . $param['nodeName'],
'name' => $param['nodeName'],
],
'user' => [
'type' => 'user',
'id' => $param['sourceUser'],
'name' => $param['sourceUser'],
],
])
->setParsedMessage($l->t('File transfer failed'));

return $notification;
}

public function handleTransferOwnershipDoneSource(INotification $notification, string $languageCode): INotification {
$l = $this->l10nFactory->get('files', $languageCode);
$param = $notification->getSubjectParameters();

$notification->setRichSubject($l->t('File transfer done'))
->setParsedSubject(str_replace(['{path}', '{user}'], [$param['nodeName'], $param['targetUser']], $l->t('Your transfer of {path} to {user} has completed.')))
->setRichMessage(
$l->t('Your transfer of {path} to {user} has completed.'),
[
'path' => [
'type' => 'highlight',
'id' => $param['targetUser'] . '::' . $param['nodeName'],
'name' => $param['nodeName'],
],
'user' => [
'type' => 'user',
'id' => $param['targetUser'],
'name' => $param['targetUser'],
],
])
->setParsedMessage($l->t('File transfer done'));

return $notification;
}

public function handleTransferOwnershipDoneTarget(INotification $notification, string $languageCode): INotification {
$l = $this->l10nFactory->get('files', $languageCode);
$param = $notification->getSubjectParameters();

$notification->setRichSubject($l->t('File transfer done'))
->setParsedSubject(str_replace(['{path}', '{user}'], [$param['nodeName'], $param['sourceUser']], $l->t('The transfer of {path} from {user} has completed.')))
->setRichMessage(
$l->t('The transfer of {path} from {user} has completed.'),
[
'path' => [
'type' => 'highlight',
'id' => $param['sourceUser'] . '::' . $param['nodeName'],
'name' => $param['nodeName'],
],
'user' => [
'type' => 'user',
'id' => $param['sourceUser'],
'name' => $param['sourceUser'],
],
])
->setParsedMessage($l->t('File transfer done'));

return $notification;
}
}

+ 46
- 0
apps/files/lib/Settings/PersonalSettings.php 查看文件

@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

/**
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @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\Settings;

use OCA\Files\AppInfo\Application;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\Settings\ISettings;

class PersonalSettings implements ISettings {

public function getForm(): TemplateResponse {
return new TemplateResponse(Application::APP_ID, 'settings-personal');
}

public function getSection(): string {
return 'sharing';
}

public function getPriority(): int {
return 90;
}

}

+ 38
- 0
apps/files/src/components/PersonalSettings.vue 查看文件

@@ -0,0 +1,38 @@
<!--
- @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
-
- @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
-
- @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/>.
-->

<template>
<div id="files-personal-settings" class="section">
<h2>{{ t('files', 'Files') }}</h2>
<TransferOwnershipDialogue />
</div>
</template>

<script>
import TransferOwnershipDialogue from './TransferOwnershipDialogue'

export default {
name: 'PersonalSettings',
components: {
TransferOwnershipDialogue
}
}
</script>

+ 143
- 0
apps/files/src/components/TransferOwnershipDialogue.vue 查看文件

@@ -0,0 +1,143 @@
<!--
- @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
-
- @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
-
- @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/>.
-->

<template>
<div>
<h3>{{ t('files', 'Transfer ownership') }} </h3>
<p>
{{ t('files', 'Here you can select a directory that is transferred to another user. It may take some time until the process is done.') }}
</p>
<form @submit.prevent="submit">
<ol>
<li>
<div class="step-header">
{{ t('files', 'Directory to move') }}
</div>
<span v-if="directory === undefined">{{ t('files', 'No directory selected') }}</span>
<span v-else>{{ directory }}</span>
<button class="primary" @click.prevent="start">
{{ t('files', 'Select') }}
</button>
<span class="error">{{ directoryPickerError }}</span>
</li>
<li>
<div class="step-header">
{{ t('files', 'Target user') }}
</div>
<input id="files-transfer-user" v-model="uid" type="text">
</li>
<li>
<input type="submit"
class="primary"
:value="t('files', 'Submit')"
:disabled="!canSubmit">
<span class="error">{{ submitError }}</span>
</li>
</ol>
</form>
</div>
</template>

<script>
import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import { getFilePickerBuilder } from '@nextcloud/dialogs'

import logger from '../logger'

const picker = getFilePickerBuilder(t('files', 'Select directory to transfer'))
.setMultiSelect(false)
.setModal(true)
.setType(1)
.allowDirectories()
.build()

export default {
name: 'TransferOwnershipDialogue',
data() {
return {
directory: undefined,
directoryPickerError: undefined,
submitError: undefined,
uid: ''
}
},
computed: {
canSubmit() {
return !!this.directory && !!this.uid
}
},
methods: {
start() {
this.directoryPickerError = undefined

picker.pick()
.then(dir => dir === '' ? '/' : dir)
.then(dir => {
logger.debug(`path ${dir} selected for transfer ownership`)
if (!dir.startsWith('/')) {
throw new Error(t('files', 'Invalid path selected'))
}
// /ocs/v2.php/apps/files/api/v1/transferownership
// /ocs/v2.php/apps/files/api/v1/transferownership
this.directory = dir
}).catch(error => {
logger.error(`Selecting dir for transfer aborted: ${error.message || 'Unknown error'}`, { error })

this.directoryPickerError = error.message || t('files', 'Unknown error')
})
},
submit() {
if (!this.canSubmit) {
logger.warn('ignoring form submit')
}

this.submitError = undefined
const data = {
path: this.directory,
recipient: this.uid
}
logger.debug('submit transfer ownership form', data)

const url = generateOcsUrl('apps/files/api/v1/', 2) + 'transferownership'

axios.post(url, data)
.then(resp => resp.data)
.then(data => {
logger.info('Transfer ownership request sent', { data })

this.directory = undefined
this.recipient = undefined
OCP.Toast.success(t('files', 'Ownership transfer request sent'))
})
.catch(error => {
logger.error('Could not send ownership transfer request', { error })

this.submitError = error.message || t('files', 'Unknown error')
})
}
}
}
</script>

<style scoped>

</style>

+ 28
- 0
apps/files/src/logger.js 查看文件

@@ -0,0 +1,28 @@
/*
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @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/>.
*/

import { getCurrentUser } from '@nextcloud/auth'
import { getLoggerBuilder } from '@nextcloud/logger'

export default getLoggerBuilder()
.setApp('files')
.setUid(getCurrentUser().uid)
.build()

+ 38
- 0
apps/files/src/main-personal-settings.js 查看文件

@@ -0,0 +1,38 @@
// global t

/*
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @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/>.
*/

import Vue from 'vue'
import { getRequestToken } from '@nextcloud/auth'
import { generateFilePath } from '@nextcloud/router'

import PersonalSettings from './components/PersonalSettings'

// eslint-disable-next-line camelcase
__webpack_nonce__ = btoa(getRequestToken())
// eslint-disable-next-line camelcase
__webpack_public_path__ = generateFilePath('files', '', 'js/')

Vue.prototype.t = t

const View = Vue.extend(PersonalSettings)
new View().$mount('#files-personal-settings')

+ 29
- 0
apps/files/templates/settings-personal.php 查看文件

@@ -0,0 +1,29 @@
<?php

/**
* @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
*
* @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/>.
*/


script(\OCA\Files\AppInfo\Application::APP_ID, 'dist/personal-settings');

?>
<div id="files-personal-settings" class="section">
</div>

+ 1
- 0
apps/files/webpack.js 查看文件

@@ -3,6 +3,7 @@ const path = require('path');
module.exports = {
entry: {
'sidebar': path.join(__dirname, 'src', 'sidebar.js'),
'personal-settings': path.join(__dirname, 'src', 'main-personal-settings.js'),
},
output: {
path: path.resolve(__dirname, './js/dist/'),

+ 1
- 1
core/js/dist/login.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
core/js/dist/login.js.map
文件差異過大導致無法顯示
查看文件


+ 1
- 1
core/js/dist/main.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
core/js/dist/main.js.map
文件差異過大導致無法顯示
查看文件


+ 1
- 1
core/js/dist/maintenance.js
文件差異過大導致無法顯示
查看文件


+ 1
- 1
core/js/dist/maintenance.js.map
文件差異過大導致無法顯示
查看文件


+ 2
- 2
core/src/OC/dialogs.js 查看文件

@@ -486,7 +486,7 @@ const Dialogs = {
// Hence this is one of the approach to get the choose button.
var getOcDialog = self.$filePicker.closest('.oc-dialog')
var buttonEnableDisable = getOcDialog.find('.primary')
if (self.$filePicker.data('mimetype').indexOf('httpd/unix-directory') !== -1 && !self.$filePicker.data('.allowDirectoryChooser')) {
if (self.$filePicker.data('mimetype').indexOf('httpd/unix-directory') !== -1 || self.$filePicker.data('allowDirectoryChooser')) {
buttonEnableDisable.prop('disabled', false)
} else {
buttonEnableDisable.prop('disabled', true)
@@ -1213,7 +1213,7 @@ const Dialogs = {
var getOcDialog = (event.target).closest('.oc-dialog')
var buttonEnableDisable = $('.primary', getOcDialog)
this._changeButtonsText(type, dir.split(/[/]+/).pop())
if (this.$filePicker.data('mimetype').indexOf('httpd/unix-directory') !== -1) {
if (this.$filePicker.data('mimetype').indexOf('httpd/unix-directory') !== -1 || this.$filePicker.data('allowDirectoryChooser')) {
buttonEnableDisable.prop('disabled', false)
} else {
buttonEnableDisable.prop('disabled', true)

+ 188
- 7
package-lock.json 查看文件

@@ -2142,6 +2142,21 @@
"integrity": "sha512-f+sKpdLZXkODV+OY39K1M+Spmd4RgxmtEXmNn4Bviv4R7uBFHXuw+JX9ZdfDeOryfHjJ/TRQxQEp0GMpBwZFUw==",
"dev": true
},
"@nextcloud/dialogs": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-0.1.1.tgz",
"integrity": "sha512-eO3qfMdxg+ZRrP3lYX5B6R/DyEEuBieOwI6N42yaGmsniBmPnAGt7uxWKMBBCeOQLDJT2ni805GUkU2hMA3xNw==",
"requires": {
"core-js": "3.4.2"
},
"dependencies": {
"core-js": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.4.2.tgz",
"integrity": "sha512-bUTfqFWtNKWp73oNIfRkqwYZJeNT3lstzZcAkhhiuvDraRSgOH1/+F9ZklbpR4zpdKuo4cpXN8tKP7s61yjX+g=="
}
}
},
"@nextcloud/event-bus": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/@nextcloud/event-bus/-/event-bus-0.2.1.tgz",
@@ -2172,6 +2187,22 @@
}
}
},
"@nextcloud/logger": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@nextcloud/logger/-/logger-0.1.0.tgz",
"integrity": "sha512-8ZI9SkuY3vRe7IoQV9J83zUf6s8UpXHsG9vH8cTLiCyQihiJ6xpdvmbBk509v6MitG7H7Nx83vygSLM1gkMnNQ==",
"requires": {
"babel-plugin-transform-class-properties": "6.24.1",
"core-js": "3.1.4"
},
"dependencies": {
"core-js": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz",
"integrity": "sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ=="
}
}
},
"@nextcloud/paths": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@nextcloud/paths/-/paths-0.2.0.tgz",
@@ -2688,6 +2719,58 @@
}
}
},
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
"requires": {
"chalk": "^1.1.3",
"esutils": "^2.0.2",
"js-tokens": "^3.0.2"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
}
}
},
"babel-eslint": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.3.tgz",
@@ -2713,6 +2796,27 @@
}
}
},
"babel-helper-function-name": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
"integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
"requires": {
"babel-helper-get-function-arity": "^6.24.1",
"babel-runtime": "^6.22.0",
"babel-template": "^6.24.1",
"babel-traverse": "^6.24.1",
"babel-types": "^6.24.1"
}
},
"babel-helper-get-function-arity": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
"integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
"requires": {
"babel-runtime": "^6.22.0",
"babel-types": "^6.24.1"
}
},
"babel-loader": {
"version": "8.0.6",
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.0.6.tgz",
@@ -2725,6 +2829,14 @@
"pify": "^4.0.1"
}
},
"babel-messages": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
"integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
"requires": {
"babel-runtime": "^6.22.0"
}
},
"babel-plugin-dynamic-import-node": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz",
@@ -2733,6 +2845,22 @@
"object.assign": "^4.1.0"
}
},
"babel-plugin-syntax-class-properties": {
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
"integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94="
},
"babel-plugin-transform-class-properties": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
"integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
"requires": {
"babel-helper-function-name": "^6.24.1",
"babel-plugin-syntax-class-properties": "^6.8.0",
"babel-runtime": "^6.22.0",
"babel-template": "^6.24.1"
}
},
"babel-plugin-transform-es2015-arrow-functions": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
@@ -2746,7 +2874,6 @@
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"dev": true,
"requires": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
@@ -2755,11 +2882,68 @@
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
"dev": true
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
}
}
},
"babel-template": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
"integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
"requires": {
"babel-runtime": "^6.26.0",
"babel-traverse": "^6.26.0",
"babel-types": "^6.26.0",
"babylon": "^6.18.0",
"lodash": "^4.17.4"
}
},
"babel-traverse": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
"integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
"requires": {
"babel-code-frame": "^6.26.0",
"babel-messages": "^6.23.0",
"babel-runtime": "^6.26.0",
"babel-types": "^6.26.0",
"babylon": "^6.18.0",
"debug": "^2.6.8",
"globals": "^9.18.0",
"invariant": "^2.2.2",
"lodash": "^4.17.4"
},
"dependencies": {
"globals": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
"integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
}
}
},
"babel-types": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
"integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
"requires": {
"babel-runtime": "^6.26.0",
"esutils": "^2.0.2",
"lodash": "^4.17.4",
"to-fast-properties": "^1.0.3"
},
"dependencies": {
"to-fast-properties": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
"integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc="
}
}
},
"babylon": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
},
"backbone": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/backbone/-/backbone-1.4.0.tgz",
@@ -3588,7 +3772,6 @@
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -5515,7 +5698,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
},
@@ -5523,8 +5705,7 @@
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
}
}
},

+ 2
- 0
package.json 查看文件

@@ -27,8 +27,10 @@
"@chenfengyuan/vue-qrcode": "^1.0.1",
"@nextcloud/auth": "^0.3.1",
"@nextcloud/axios": "^0.5.0",
"@nextcloud/dialogs": "^0.1.1",
"@nextcloud/event-bus": "^0.2.1",
"@nextcloud/initial-state": "^0.2.0",
"@nextcloud/logger": "^0.1.0",
"@nextcloud/paths": "^0.2.0",
"@nextcloud/router": "^0.1.0",
"autosize": "^4.0.2",

Loading…
取消
儲存