2424
2525namespace OCA \Files \Listener ;
2626
27- use OCA \Files_Trashbin \Events \BeforeNodeRestoredEvent ;
28- use OCA \Files_Trashbin \Trash \ITrashItem ;
29- use OCA \Files_Trashbin \Trash \ITrashManager ;
27+ use OCA \Files \Service \LivePhotosService ;
3028use OCP \EventDispatcher \Event ;
3129use OCP \EventDispatcher \IEventListener ;
3230use OCP \Files \Cache \CacheEntryRemovedEvent ;
3533use OCP \Files \Folder ;
3634use OCP \Files \Node ;
3735use OCP \Files \NotFoundException ;
38- use OCP \Files \NotPermittedException ;
39- use OCP \FilesMetadata \Exceptions \FilesMetadataNotFoundException ;
4036use OCP \FilesMetadata \IFilesMetadataManager ;
41- use OCP \IUserSession ;
4237
4338/**
4439 * @template-implements IEventListener<Event>
@@ -48,36 +43,38 @@ class SyncLivePhotosListener implements IEventListener {
4843 private array $ pendingRenames = [];
4944 /** @var Array<int, bool> */
5045 private array $ pendingDeletion = [];
51- /** @var Array<int, bool> */
52- private array $ pendingRestores = [];
5346
5447 public function __construct (
5548 private ?Folder $ userFolder ,
56- private ?IUserSession $ userSession ,
57- private ITrashManager $ trashManager ,
5849 private IFilesMetadataManager $ filesMetadataManager ,
50+ private LivePhotosService $ livePhotosService ,
5951 ) {
6052 }
6153
6254 public function handle (Event $ event ): void {
63- if ($ this ->userFolder === null || $ this -> userSession === null ) {
55+ if ($ this ->userFolder === null ) {
6456 return ;
6557 }
6658
67- $ peerFile = null ;
59+ $ peerFileId = null ;
6860
6961 if ($ event instanceof BeforeNodeRenamedEvent) {
70- $ peerFile = $ this ->getLivePhotoPeer ($ event ->getSource ()->getId ());
71- } elseif ($ event instanceof BeforeNodeRestoredEvent) {
72- $ peerFile = $ this ->getLivePhotoPeer ($ event ->getSource ()->getId ());
62+ $ peerFileId = $ this ->livePhotosService ->getLivePhotoPeerId ($ event ->getSource ()->getId ());
7363 } elseif ($ event instanceof BeforeNodeDeletedEvent) {
74- $ peerFile = $ this ->getLivePhotoPeer ($ event ->getNode ()->getId ());
64+ $ peerFileId = $ this ->livePhotosService -> getLivePhotoPeerId ($ event ->getNode ()->getId ());
7565 } elseif ($ event instanceof CacheEntryRemovedEvent) {
76- $ peerFile = $ this ->getLivePhotoPeer ($ event ->getFileId ());
66+ $ peerFileId = $ this ->livePhotosService ->getLivePhotoPeerId ($ event ->getFileId ());
67+ }
68+
69+ if ($ peerFileId === null ) {
70+ return ; // Not a live photo.
7771 }
7872
73+ // Check the user's folder.
74+ $ peerFile = $ this ->userFolder ->getFirstNodeById ($ peerFileId );
75+
7976 if ($ peerFile === null ) {
80- return ; // not a Live Photo
77+ return ; // Peer file not found.
8178 }
8279
8380 if ($ event instanceof BeforeNodeRenamedEvent) {
@@ -164,114 +161,4 @@ private function handleDeletion(BeforeNodeDeletedEvent $event, Node $peerFile):
164161 }
165162 return ;
166163 }
167-
168- /**
169- * During restore event, we trigger another recursive restore on the peer file.
170- * Restore operations on the .mov file directly are currently blocked.
171- * The event listener being singleton, we can store the current state
172- * of pending restores inside the 'pendingRestores' property,
173- * to prevent infinite recursivity.
174- */
175- private function handleRestore (BeforeNodeRestoredEvent $ event , Node $ peerFile ): void {
176- $ sourceFile = $ event ->getSource ();
177-
178- if ($ sourceFile ->getMimetype () === 'video/quicktime ' ) {
179- if (isset ($ this ->pendingRestores [$ peerFile ->getId ()])) {
180- unset($ this ->pendingRestores [$ peerFile ->getId ()]);
181- return ;
182- } else {
183- $ event ->abortOperation (new NotPermittedException ("Cannot restore the video part of a live photo " ));
184- }
185- } else {
186- $ user = $ this ->userSession ->getUser ();
187- if ($ user === null ) {
188- return ;
189- }
190-
191- $ peerTrashItem = $ this ->trashManager ->getTrashNodeById ($ user , $ peerFile ->getId ());
192- // Peer file is not in the bin, no need to restore it.
193- if ($ peerTrashItem === null ) {
194- return ;
195- }
196-
197- $ trashRoot = $ this ->trashManager ->listTrashRoot ($ user );
198- $ trashItem = $ this ->getTrashItem ($ trashRoot , $ peerFile ->getInternalPath ());
199-
200- if ($ trashItem === null ) {
201- $ event ->abortOperation (new NotFoundException ("Couldn't find peer file in trashbin " ));
202- }
203-
204- $ this ->pendingRestores [$ sourceFile ->getId ()] = true ;
205- try {
206- $ this ->trashManager ->restoreItem ($ trashItem );
207- } catch (\Throwable $ ex ) {
208- $ event ->abortOperation ($ ex );
209- }
210- }
211- }
212-
213- /**
214- * Helper method to get the associated live photo file.
215- * We first look for it in the user folder, and if we
216- * cannot find it here, we look for it in the user's trashbin.
217- */
218- private function getLivePhotoPeer (int $ nodeId ): ?Node {
219- if ($ this ->userFolder === null || $ this ->userSession === null ) {
220- return null ;
221- }
222-
223- try {
224- $ metadata = $ this ->filesMetadataManager ->getMetadata ($ nodeId );
225- } catch (FilesMetadataNotFoundException $ ex ) {
226- return null ;
227- }
228-
229- if (!$ metadata ->hasKey ('files-live-photo ' )) {
230- return null ;
231- }
232-
233- $ peerFileId = (int )$ metadata ->getString ('files-live-photo ' );
234-
235- // Check the user's folder.
236- $ nodes = $ this ->userFolder ->getById ($ peerFileId );
237- if (count ($ nodes ) !== 0 ) {
238- return $ nodes [0 ];
239- }
240-
241- // Check the user's trashbin.
242- $ user = $ this ->userSession ->getUser ();
243- if ($ user !== null ) {
244- $ peerFile = $ this ->trashManager ->getTrashNodeById ($ user , $ peerFileId );
245- if ($ peerFile !== null ) {
246- return $ peerFile ;
247- }
248- }
249-
250- $ metadata ->unset ('files-live-photo ' );
251- return null ;
252- }
253-
254- /**
255- * There is currently no method to restore a file based on its fileId or path.
256- * So we have to manually find a ITrashItem from the trash item list.
257- * TODO: This should be replaced by a proper method in the TrashManager.
258- */
259- private function getTrashItem (array $ trashFolder , string $ path ): ?ITrashItem {
260- foreach ($ trashFolder as $ trashItem ) {
261- if (str_starts_with ($ path , "files_trashbin/files " .$ trashItem ->getTrashPath ())) {
262- if ($ path === "files_trashbin/files " .$ trashItem ->getTrashPath ()) {
263- return $ trashItem ;
264- }
265-
266- if ($ trashItem instanceof Folder) {
267- $ node = $ this ->getTrashItem ($ trashItem ->getDirectoryListing (), $ path );
268- if ($ node !== null ) {
269- return $ node ;
270- }
271- }
272- }
273- }
274-
275- return null ;
276- }
277164}
0 commit comments