Signed-off-by: Christopher Ng <chrng8@gmail.com>pull/44643/head
@@ -60,7 +60,7 @@ class Helper { | |||
$absoluteDir = $view->getAbsolutePath($dir); | |||
$internalPath = $mount->getInternalPath($absoluteDir); | |||
$originalLocations = \OCA\Files_Trashbin\Trashbin::getLocations($user); | |||
$extraData = \OCA\Files_Trashbin\Trashbin::getExtraData($user); | |||
$dirContent = $storage->getCache()->getFolderContents($mount->getInternalPath($view->getAbsolutePath($dir))); | |||
foreach ($dirContent as $entry) { | |||
$entryName = $entry->getName(); | |||
@@ -76,8 +76,8 @@ class Helper { | |||
} | |||
$originalPath = ''; | |||
$originalName = substr($entryName, 0, -strlen($timestamp) - 2); | |||
if (isset($originalLocations[$originalName][$timestamp])) { | |||
$originalPath = $originalLocations[$originalName][$timestamp]; | |||
if (isset($extraData[$originalName][$timestamp]['location'])) { | |||
$originalPath = $extraData[$originalName][$timestamp]['location']; | |||
if (substr($originalPath, -1) === '/') { | |||
$originalPath = substr($originalPath, 0, -1); | |||
} | |||
@@ -101,6 +101,7 @@ class Helper { | |||
$i['extraData'] = $originalName; | |||
} | |||
} | |||
$i['deletedBy'] = $extraData[$originalName][$timestamp]['deletedBy'] ?? null; | |||
$result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i, $mount); | |||
} | |||
@@ -28,6 +28,7 @@ namespace OCA\Files_Trashbin\Sabre; | |||
use OCA\Files_Trashbin\Trash\ITrashItem; | |||
use OCA\Files_Trashbin\Trash\ITrashManager; | |||
use OCP\Files\FileInfo; | |||
use OCP\IUser; | |||
abstract class AbstractTrash implements ITrash { | |||
/** @var ITrashItem */ | |||
@@ -89,6 +90,10 @@ abstract class AbstractTrash implements ITrash { | |||
return $this->data->getTitle(); | |||
} | |||
public function getDeletedBy(): ?IUser { | |||
return $this->data->getDeletedBy(); | |||
} | |||
public function delete() { | |||
$this->trashManager->removeItem($this->data); | |||
} |
@@ -27,6 +27,7 @@ declare(strict_types=1); | |||
namespace OCA\Files_Trashbin\Sabre; | |||
use OCP\Files\FileInfo; | |||
use OCP\IUser; | |||
interface ITrash { | |||
public function restore(): bool; | |||
@@ -39,6 +40,8 @@ interface ITrash { | |||
public function getDeletionTime(): int; | |||
public function getDeletedBy(): ?IUser; | |||
public function getSize(): int|float; | |||
public function getFileId(): int; |
@@ -77,5 +77,10 @@ interface ITrashItem extends FileInfo { | |||
*/ | |||
public function getUser(): IUser; | |||
/** | |||
* @since 30.0.0 | |||
*/ | |||
public function getDeletedBy(): ?IUser; | |||
public function getTitle(): string; | |||
} |
@@ -33,16 +33,16 @@ use OCP\Files\IRootFolder; | |||
use OCP\Files\NotFoundException; | |||
use OCP\Files\Storage\IStorage; | |||
use OCP\IUser; | |||
use OCP\IUserManager; | |||
class LegacyTrashBackend implements ITrashBackend { | |||
/** @var array */ | |||
private $deletedFiles = []; | |||
/** @var IRootFolder */ | |||
private $rootFolder; | |||
public function __construct(IRootFolder $rootFolder) { | |||
$this->rootFolder = $rootFolder; | |||
public function __construct( | |||
private IRootFolder $rootFolder, | |||
private IUserManager $userManager, | |||
) { | |||
} | |||
/** | |||
@@ -59,6 +59,8 @@ class LegacyTrashBackend implements ITrashBackend { | |||
if (!$originalLocation) { | |||
$originalLocation = $file->getName(); | |||
} | |||
/** @psalm-suppress UndefinedInterfaceMethod */ | |||
$deletedBy = $this->userManager->get($file['deletedBy']) ?? $parent?->getDeletedBy(); | |||
$trashFilename = Trashbin::getTrashFilename($file->getName(), $file->getMtime()); | |||
return new TrashItem( | |||
$this, | |||
@@ -66,7 +68,8 @@ class LegacyTrashBackend implements ITrashBackend { | |||
$file->getMTime(), | |||
$parentTrashPath . '/' . ($isRoot ? $trashFilename : $file->getName()), | |||
$file, | |||
$user | |||
$user, | |||
$deletedBy, | |||
); | |||
}, $items); | |||
} |
@@ -27,33 +27,16 @@ use OCP\Files\FileInfo; | |||
use OCP\IUser; | |||
class TrashItem implements ITrashItem { | |||
/** @var ITrashBackend */ | |||
private $backend; | |||
/** @var string */ | |||
private $orignalLocation; | |||
/** @var int */ | |||
private $deletedTime; | |||
/** @var string */ | |||
private $trashPath; | |||
/** @var FileInfo */ | |||
private $fileInfo; | |||
/** @var IUser */ | |||
private $user; | |||
public function __construct( | |||
ITrashBackend $backend, | |||
string $originalLocation, | |||
int $deletedTime, | |||
string $trashPath, | |||
FileInfo $fileInfo, | |||
IUser $user | |||
private ITrashBackend $backend, | |||
private string $originalLocation, | |||
private int $deletedTime, | |||
private string $trashPath, | |||
private FileInfo $fileInfo, | |||
private IUser $user, | |||
private ?IUser $deletedBy, | |||
) { | |||
$this->backend = $backend; | |||
$this->orignalLocation = $originalLocation; | |||
$this->deletedTime = $deletedTime; | |||
$this->trashPath = $trashPath; | |||
$this->fileInfo = $fileInfo; | |||
$this->user = $user; | |||
} | |||
public function getTrashBackend(): ITrashBackend { | |||
@@ -61,7 +44,7 @@ class TrashItem implements ITrashItem { | |||
} | |||
public function getOriginalLocation(): string { | |||
return $this->orignalLocation; | |||
return $this->originalLocation; | |||
} | |||
public function getDeletedTime(): int { | |||
@@ -192,6 +175,10 @@ class TrashItem implements ITrashItem { | |||
return $this->fileInfo->getParentId(); | |||
} | |||
public function getDeletedBy(): ?IUser { | |||
return $this->deletedBy; | |||
} | |||
/** | |||
* @inheritDoc | |||
* @return array<string, int|string|bool|float|string[]|int[]> |
@@ -126,24 +126,23 @@ class Trashbin { | |||
} | |||
/** | |||
* get original location of files for user | |||
* get original location and deleted by of files for user | |||
* | |||
* @param string $user | |||
* @return array (filename => array (timestamp => original location)) | |||
* @return array<string, array<string, array{location: string, deletedBy: string}>> | |||
*/ | |||
public static function getLocations($user) { | |||
public static function getExtraData($user) { | |||
$query = \OC::$server->getDatabaseConnection()->getQueryBuilder(); | |||
$query->select('id', 'timestamp', 'location') | |||
$query->select('id', 'timestamp', 'location', 'deleted_by') | |||
->from('files_trash') | |||
->where($query->expr()->eq('user', $query->createNamedParameter($user))); | |||
$result = $query->executeQuery(); | |||
$array = []; | |||
while ($row = $result->fetch()) { | |||
if (isset($array[$row['id']])) { | |||
$array[$row['id']][$row['timestamp']] = $row['location']; | |||
} else { | |||
$array[$row['id']] = [$row['timestamp'] => $row['location']]; | |||
} | |||
$array[$row['id']][$row['timestamp']] = [ | |||
'location' => (string)$row['location'], | |||
'deletedBy' => (string)$row['deleted_by'], | |||
]; | |||
} | |||
$result->closeCursor(); | |||
return $array; |
@@ -96,7 +96,15 @@ class TrashbinMigrator implements IMigrator, ISizeEstimationMigrator { | |||
} | |||
$output->writeln("Exporting trashbin files…"); | |||
$exportDestination->copyFolder($trashbinFolder, static::PATH_FILES_FOLDER); | |||
$originalLocations = \OCA\Files_Trashbin\Trashbin::getLocations($uid); | |||
$originalLocations = []; | |||
// TODO Export all extra data and bump migrator to v2 | |||
foreach (\OCA\Files_Trashbin\Trashbin::getExtraData($uid) as $filename => $extraData) { | |||
$locationData = []; | |||
foreach ($extraData as $timestamp => ['location' => $location]) { | |||
$locationData[$timestamp] = $location; | |||
} | |||
$originalLocations[$filename] = $locationData; | |||
} | |||
$exportDestination->addFileContents(static::PATH_LOCATIONS_FILE, json_encode($originalLocations)); | |||
} catch (NotFoundException $e) { | |||
$output->writeln("No trashbin to export…"); |