| 
									
										
										
										
											2009-05-11 13:45:00 -04:00
										 |  |  | <?php | 
					
						
							| 
									
										
										
										
											2020-03-29 18:33:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-29 19:56:35 +00:00
										 |  |  | // {{{ License
 | 
					
						
							| 
									
										
										
										
											2021-02-22 21:34:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-20 16:53:53 +00:00
										 |  |  | // This file is part of GNU social - https://www.gnu.org/software/social
 | 
					
						
							| 
									
										
										
										
											2020-03-29 19:56:35 +00:00
										 |  |  | //
 | 
					
						
							|  |  |  | // GNU social is free software: you can redistribute it and/or modify
 | 
					
						
							| 
									
										
										
										
											2020-05-10 21:43:15 +01:00
										 |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							| 
									
										
										
										
											2020-03-29 19:56:35 +00:00
										 |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // GNU social 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.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-05-10 21:43:15 +01:00
										 |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							| 
									
										
										
										
											2020-03-29 19:56:35 +00:00
										 |  |  | // along with GNU social.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2021-02-22 21:34:59 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-29 19:56:35 +00:00
										 |  |  | // }}}
 | 
					
						
							| 
									
										
										
										
											2020-03-29 18:33:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-02 15:12:31 +00:00
										 |  |  | namespace Component\Attachment\Entity; | 
					
						
							| 
									
										
										
										
											2019-09-11 08:15:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-15 16:49:29 +01:00
										 |  |  | use App\Core\Cache; | 
					
						
							| 
									
										
										
										
											2020-08-08 16:10:25 +00:00
										 |  |  | use App\Core\DB\DB; | 
					
						
							| 
									
										
										
										
											2020-08-07 02:03:55 +00:00
										 |  |  | use App\Core\Entity; | 
					
						
							| 
									
										
										
										
											2021-09-15 16:49:29 +01:00
										 |  |  | use App\Core\Event; | 
					
						
							| 
									
										
										
										
											2021-07-22 20:57:03 +01:00
										 |  |  | use App\Core\GSFile; | 
					
						
							| 
									
										
										
										
											2021-12-02 15:12:31 +00:00
										 |  |  | use App\Entity\Note; | 
					
						
							| 
									
										
										
										
											2021-08-12 03:43:11 +01:00
										 |  |  | use function App\Core\I18n\_m; | 
					
						
							| 
									
										
										
										
											2021-08-04 19:12:37 +01:00
										 |  |  | use App\Core\Log; | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  | use App\Core\Router\Router; | 
					
						
							| 
									
										
										
										
											2021-04-16 15:57:25 +00:00
										 |  |  | use App\Util\Common; | 
					
						
							| 
									
										
										
										
											2021-09-25 13:12:32 +01:00
										 |  |  | use App\Util\Exception\ClientException; | 
					
						
							| 
									
										
										
										
											2021-08-14 21:47:49 +01:00
										 |  |  | use App\Util\Exception\DuplicateFoundException; | 
					
						
							|  |  |  | use App\Util\Exception\NotFoundException; | 
					
						
							|  |  |  | use App\Util\Exception\ServerException; | 
					
						
							| 
									
										
										
										
											2020-05-10 21:43:15 +01:00
										 |  |  | use DateTimeInterface; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 14:08:27 +01:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2020-03-29 18:33:16 +00:00
										 |  |  |  * Entity for uploaded files | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @category  DB | 
					
						
							| 
									
										
										
										
											2019-06-07 14:08:27 +01:00
										 |  |  |  * @package   GNUsocial | 
					
						
							| 
									
										
										
										
											2020-03-29 18:33:16 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @author    Zach Copley <zach@status.net> | 
					
						
							|  |  |  |  * @copyright 2010 StatusNet Inc. | 
					
						
							| 
									
										
										
										
											2019-06-07 14:08:27 +01:00
										 |  |  |  * @author    Mikael Nordfeldth <mmn@hethane.se> | 
					
						
							| 
									
										
										
										
											2020-03-29 18:33:16 +00:00
										 |  |  |  * @copyright 2009-2014 Free Software Foundation, Inc http://www.fsf.org | 
					
						
							| 
									
										
										
										
											2021-02-19 23:29:43 +00:00
										 |  |  |  * @author    Hugo Sales <hugo@hsal.es> | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |  * @author    Diogo Peralta Cordeiro <mail@diogo.site> | 
					
						
							| 
									
										
										
										
											2021-02-19 23:29:43 +00:00
										 |  |  |  * @copyright 2020-2021 Free Software Foundation, Inc http://www.fsf.org | 
					
						
							| 
									
										
										
										
											2019-09-11 08:15:16 +03:00
										 |  |  |  * @license   https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later | 
					
						
							| 
									
										
										
										
											2009-05-11 13:45:00 -04:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-04-16 20:27:33 +01:00
										 |  |  | class Attachment extends Entity | 
					
						
							| 
									
										
										
										
											2009-05-11 13:45:00 -04:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-30 14:00:13 +00:00
										 |  |  |     // {{{ Autocode
 | 
					
						
							| 
									
										
										
										
											2021-05-05 16:03:03 +00:00
										 |  |  |     // @codeCoverageIgnoreStart
 | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     private int $id; | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |     private int $lives = 1; | 
					
						
							|  |  |  |     private ?string $filehash; | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     private ?string $mimetype; | 
					
						
							| 
									
										
										
										
											2021-03-10 17:20:42 +00:00
										 |  |  |     private ?string $filename; | 
					
						
							| 
									
										
										
										
											2021-04-29 20:29:21 +00:00
										 |  |  |     private ?int $size; | 
					
						
							| 
									
										
										
										
											2021-05-01 22:48:44 +01:00
										 |  |  |     private ?int $width; | 
					
						
							|  |  |  |     private ?int $height; | 
					
						
							| 
									
										
										
										
											2021-08-12 04:41:00 +01:00
										 |  |  |     private DateTimeInterface $modified; | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     public function setId(int $id): self | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->id = $id; | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-08 16:10:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     public function getId(): int | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->id; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @return int | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getLives(): int | 
					
						
							| 
									
										
										
										
											2020-06-30 18:20:50 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         return $this->lives; | 
					
						
							| 
									
										
										
										
											2020-06-30 18:20:50 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-08 16:10:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @param int $lives | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function setLives(int $lives): void | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         $this->lives = $lives; | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |     public function setFilehash(?string $filehash): self | 
					
						
							| 
									
										
										
										
											2020-08-15 07:06:33 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         $this->filehash = $filehash; | 
					
						
							| 
									
										
										
										
											2020-08-15 07:06:33 +00:00
										 |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |     public function getFilehash(): ?string | 
					
						
							| 
									
										
										
										
											2020-08-15 07:06:33 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         return $this->filehash; | 
					
						
							| 
									
										
										
										
											2020-08-15 07:06:33 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     public function setMimetype(?string $mimetype): self | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->mimetype = $mimetype; | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-08 16:10:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     public function getMimetype(): ?string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->mimetype; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-10 17:20:42 +00:00
										 |  |  |     public function setFilename(?string $filename): self | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->filename = $filename; | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getFilename(): ?string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->filename; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-29 20:29:21 +00:00
										 |  |  |     public function setSize(?int $size): self | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->size = $size; | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getSize(): ?int | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->size; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-01 22:48:44 +01:00
										 |  |  |     public function setWidth(?int $width): self | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->width = $width; | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getWidth(): ?int | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->width; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function setHeight(?int $height): self | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->height = $height; | 
					
						
							|  |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getHeight(): ?int | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return $this->height; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-02 15:48:06 +00:00
										 |  |  |     public function setModified(DateTimeInterface $modified): self | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-08-07 02:03:55 +00:00
										 |  |  |         $this->modified = $modified; | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |         return $this; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-08 16:10:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-02 15:48:06 +00:00
										 |  |  |     public function getModified(): DateTimeInterface | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-08-07 02:03:55 +00:00
										 |  |  |         return $this->modified; | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-05 16:03:03 +00:00
										 |  |  |     // @codeCoverageIgnoreEnd
 | 
					
						
							| 
									
										
										
										
											2020-08-07 02:03:55 +00:00
										 |  |  |     // }}} Autocode
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-18 22:11:07 +01:00
										 |  |  |     public function getMimetypeMajor(): ?string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $mime = $this->getMimetype(); | 
					
						
							|  |  |  |         return is_null($mime) ? $mime : GSFile::mimetypeMajor($mime); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public function getMimetypeMinor(): ?string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $mime = $this->getMimetype(); | 
					
						
							|  |  |  |         return is_null($mime) ? $mime : GSFile::mimetypeMinor($mime); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @return int | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function livesIncrementAndGet(): int | 
					
						
							| 
									
										
										
										
											2021-08-05 13:46:28 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         ++$this->lives; | 
					
						
							|  |  |  |         return $this->lives; | 
					
						
							| 
									
										
										
										
											2021-08-05 13:46:28 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |      * @return int | 
					
						
							| 
									
										
										
										
											2021-08-05 13:46:28 +01:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |     public function livesDecrementAndGet(): int | 
					
						
							| 
									
										
										
										
											2021-08-05 13:46:28 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         --$this->lives; | 
					
						
							|  |  |  |         return $this->lives; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const FILEHASH_ALGO = 'sha256'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-17 21:47:08 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Delete a file if safe, removes dependencies, cleanups and flushes | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return bool | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |     public function kill(): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if ($this->livesDecrementAndGet() <= 0) { | 
					
						
							|  |  |  |             return $this->delete(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2021-08-05 13:46:28 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:25:25 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2021-08-17 21:47:08 +01:00
										 |  |  |      * Remove the respective file from disk | 
					
						
							| 
									
										
										
										
											2021-08-12 00:25:25 +01:00
										 |  |  |      */ | 
					
						
							|  |  |  |     public function deleteStorage(): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!is_null($filepath = $this->getPath())) { | 
					
						
							|  |  |  |             if (file_exists($filepath)) { | 
					
						
							|  |  |  |                 if (@unlink($filepath) === false) { | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |                     // @codeCoverageIgnoreStart
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:25:25 +01:00
										 |  |  |                     Log::error("Failed deleting file for attachment with id={$this->getId()} at {$filepath}."); | 
					
						
							|  |  |  |                     return false; | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |                 // @codeCoverageIgnoreEnd
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:25:25 +01:00
										 |  |  |                 } else { | 
					
						
							|  |  |  |                     $this->setFilename(null); | 
					
						
							| 
									
										
										
										
											2021-08-12 04:41:00 +01:00
										 |  |  |                     $this->setSize(null); | 
					
						
							| 
									
										
										
										
											2021-08-14 15:07:17 +01:00
										 |  |  |                     // Important not to null neither width nor height
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:25:25 +01:00
										 |  |  |                     DB::persist($this); | 
					
						
							|  |  |  |                     DB::flush(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |                 // @codeCoverageIgnoreStart
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:25:25 +01:00
										 |  |  |                 Log::warning("File for attachment with id={$this->getId()} at {$filepath} was already deleted when I was going to handle it."); | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |                 // @codeCoverageIgnoreEnd
 | 
					
						
							| 
									
										
										
										
											2021-08-12 00:25:25 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-05 13:46:28 +01:00
										 |  |  |     /** | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |      * Attachment delete always removes dependencies, cleanups and flushes | 
					
						
							| 
									
										
										
										
											2021-12-10 02:38:04 +00:00
										 |  |  |      * @see kill() It's more likely that you want to use that rather than call delete directly | 
					
						
							| 
									
										
										
										
											2020-08-07 02:03:55 +00:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-08-17 21:47:08 +01:00
										 |  |  |     protected function delete(): bool | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-12-10 02:38:04 +00:00
										 |  |  |         // Friendly warning because the caller usually doesn't want to delete an attachment that is still referred elsewhere
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         if ($this->getLives() > 0) { | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |             // @codeCoverageIgnoreStart
 | 
					
						
							| 
									
										
										
										
											2021-12-10 02:38:04 +00:00
										 |  |  |             Log::warning("Deleting file {$this->getId()} with {$this->getLives()} lives. Why are you killing it so old?"); | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |             // @codeCoverageIgnoreEnd
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-10 02:38:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Collect files starting with the one associated with this attachment
 | 
					
						
							| 
									
										
										
										
											2020-08-07 02:03:55 +00:00
										 |  |  |         $files = []; | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         if (!is_null($filepath = $this->getPath())) { | 
					
						
							|  |  |  |             $files[] = $filepath; | 
					
						
							| 
									
										
										
										
											2020-08-07 02:03:55 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-10 02:38:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Collect thumbnail files and delete thumbnails
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         foreach ($this->getThumbnails() as $at) { | 
					
						
							|  |  |  |             $files[] = $at->getPath(); | 
					
						
							|  |  |  |             $at->delete(flush: false); | 
					
						
							| 
									
										
										
										
											2020-08-07 02:03:55 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-10 02:38:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Delete eventual remaining relations with Actors
 | 
					
						
							|  |  |  |         ActorToAttachment::removeWhereAttachmentId($this->getId()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Delete eventual remaining relations with Notes
 | 
					
						
							|  |  |  |         AttachmentToNote::removeWhereAttachmentId($this->getId()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Delete eventual remaining relations with Links
 | 
					
						
							|  |  |  |         AttachmentToLink::removeWhereAttachmentId($this->getId()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // Remove this attachment
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         DB::remove($this); | 
					
						
							| 
									
										
										
										
											2021-12-10 02:38:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Delete the files from disk
 | 
					
						
							| 
									
										
										
										
											2021-04-29 18:12:32 +00:00
										 |  |  |         foreach ($files as $f) { | 
					
						
							|  |  |  |             if (file_exists($f)) { | 
					
						
							|  |  |  |                 if (@unlink($f) === false) { | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |                     // @codeCoverageIgnoreStart
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |                     Log::error("Failed deleting file for attachment with id={$this->getId()} at {$f}."); | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |                     // @codeCoverageIgnoreEnd
 | 
					
						
							| 
									
										
										
										
											2021-04-29 18:12:32 +00:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |             } else { | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |                 // @codeCoverageIgnoreStart
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |                 Log::warning("File for attachment with id={$this->getId()} at {$f} was already deleted when I was going to handle it."); | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |                 // @codeCoverageIgnoreEnd
 | 
					
						
							| 
									
										
										
										
											2021-04-29 18:12:32 +00:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2020-08-07 02:03:55 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-10 02:38:04 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Flush these changes as we have deleted the files from disk
 | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         DB::flush(); | 
					
						
							|  |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-07 02:03:55 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 04:41:00 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * TODO: Maybe this isn't the best way of handling titles | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param null|Note $note | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @throws DuplicateFoundException | 
					
						
							|  |  |  |      * @throws NotFoundException | 
					
						
							|  |  |  |      * @throws ServerException | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return string | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getBestTitle(?Note $note = null): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // If we have a note, then the best title is the title itself
 | 
					
						
							|  |  |  |         if (!is_null(($note))) { | 
					
						
							| 
									
										
										
										
											2021-09-15 16:49:29 +01:00
										 |  |  |             $title = Cache::get('attachment-title-' . $this->getId() . '-' . $note->getId(), function () use ($note) { | 
					
						
							|  |  |  |                 try { | 
					
						
							|  |  |  |                     $attachment_to_note = DB::findOneBy('attachment_to_note', [ | 
					
						
							|  |  |  |                         'attachment_id' => $this->getId(), | 
					
						
							|  |  |  |                         'note_id'       => $note->getId(), | 
					
						
							|  |  |  |                     ]); | 
					
						
							|  |  |  |                     if (!is_null($attachment_to_note->getTitle())) { | 
					
						
							|  |  |  |                         return $attachment_to_note->getTitle(); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 } catch (NotFoundException) { | 
					
						
							|  |  |  |                     $title = null; | 
					
						
							|  |  |  |                     Event::handle('AttachmentGetBestTitle', [$this, $note, &$title]); | 
					
						
							|  |  |  |                     return $title; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 return null; | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |             if ($title != null) { | 
					
						
							|  |  |  |                 return $title; | 
					
						
							| 
									
										
										
										
											2021-08-12 04:41:00 +01:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // Else
 | 
					
						
							|  |  |  |         if (!is_null($filename = $this->getFilename())) { | 
					
						
							|  |  |  |             // A filename would do just as well
 | 
					
						
							|  |  |  |             return $filename; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             // Welp
 | 
					
						
							| 
									
										
										
										
											2021-08-18 17:30:02 +01:00
										 |  |  |             return _m('Untitled attachment'); | 
					
						
							| 
									
										
										
										
											2021-08-12 04:41:00 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-29 18:12:32 +00:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Find all thumbnails associated with this attachment. Don't bother caching as this is not supposed to be a common operation | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function getThumbnails() | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-04-29 18:12:32 +00:00
										 |  |  |         return DB::findBy('attachment_thumbnail', ['attachment_id' => $this->id]); | 
					
						
							| 
									
										
										
										
											2020-03-30 15:13:51 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-16 15:57:25 +00:00
										 |  |  |     public function getPath() | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |         $filename = $this->getFilename(); | 
					
						
							| 
									
										
										
										
											2021-08-19 01:45:11 +01:00
										 |  |  |         return is_null($filename) ? null : Common::config('attachments', 'dir') . DIRECTORY_SEPARATOR . $filename; | 
					
						
							| 
									
										
										
										
											2021-04-16 15:57:25 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-05 21:04:20 +00:00
										 |  |  |     public function getUrl(int $type = Router::ABSOLUTE_URL): string | 
					
						
							| 
									
										
										
										
											2021-04-25 21:26:53 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-12-05 21:04:20 +00:00
										 |  |  |         return Router::url(id: 'attachment_view', args: ['id' => $this->getId()], type: $type); | 
					
						
							| 
									
										
										
										
											2021-08-18 14:04:17 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-25 13:12:32 +01:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @param null|string $size | 
					
						
							|  |  |  |      * @param bool        $crop | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @throws ClientException | 
					
						
							|  |  |  |      * @throws NotFoundException | 
					
						
							|  |  |  |      * @throws ServerException | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return AttachmentThumbnail | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-12-02 21:24:51 +00:00
										 |  |  |     public function getThumbnail(?string $size = null, bool $crop = false): ?AttachmentThumbnail | 
					
						
							| 
									
										
										
										
											2021-09-25 13:12:32 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         return AttachmentThumbnail::getOrCreate(attachment: $this, size: $size, crop: $crop); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-22 15:08:30 +01:00
										 |  |  |     public function getThumbnailUrl(?string $size = null) | 
					
						
							| 
									
										
										
										
											2021-08-18 14:04:17 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-09-22 15:08:30 +01:00
										 |  |  |         return Router::url('attachment_thumbnail', ['id' => $this->getId(), 'size' => $size ?? Common::config('thumbnail', 'default_size')]); | 
					
						
							| 
									
										
										
										
											2021-04-25 21:26:53 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-29 18:33:16 +00:00
										 |  |  |     public static function schemaDef(): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return [ | 
					
						
							| 
									
										
										
										
											2021-04-15 22:28:28 +00:00
										 |  |  |             'name'   => 'attachment', | 
					
						
							| 
									
										
										
										
											2020-03-29 18:33:16 +00:00
										 |  |  |             'fields' => [ | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |                 'id'       => ['type' => 'serial',    'not null' => true], | 
					
						
							|  |  |  |                 'lives'    => ['type' => 'int',       'not null' => true, 'description' => 'RefCount'], | 
					
						
							|  |  |  |                 'filehash' => ['type' => 'varchar',   'length' => 64,  'description' => 'sha256 of the file contents, if the file is stored locally'], | 
					
						
							| 
									
										
										
										
											2021-08-18 22:11:07 +01:00
										 |  |  |                 'mimetype' => ['type' => 'varchar',   'length' => 255,  'description' => 'resource mime type 127+1+127 as per rfc6838#section-4.2'], | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |                 'filename' => ['type' => 'varchar',   'length' => 191, 'description' => 'file name of resource when available'], | 
					
						
							|  |  |  |                 'size'     => ['type' => 'int',       'description' => 'size of resource when available'], | 
					
						
							|  |  |  |                 'width'    => ['type' => 'int',       'description' => 'width in pixels, if it can be described as such and data is available'], | 
					
						
							|  |  |  |                 'height'   => ['type' => 'int',       'description' => 'height in pixels, if it can be described as such and data is available'], | 
					
						
							|  |  |  |                 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], | 
					
						
							| 
									
										
										
										
											2020-03-29 18:33:16 +00:00
										 |  |  |             ], | 
					
						
							|  |  |  |             'primary key' => ['id'], | 
					
						
							|  |  |  |             'unique keys' => [ | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |                 'attachment_filehash_uniq' => ['filehash'], | 
					
						
							|  |  |  |                 'attachment_filename_uniq' => ['filename'], | 
					
						
							| 
									
										
										
										
											2020-03-29 18:33:16 +00:00
										 |  |  |             ], | 
					
						
							|  |  |  |             'indexes' => [ | 
					
						
							| 
									
										
										
										
											2021-08-14 16:47:45 +01:00
										 |  |  |                 'file_filehash_idx' => ['filehash'], | 
					
						
							| 
									
										
										
										
											2020-03-29 18:33:16 +00:00
										 |  |  |             ], | 
					
						
							| 
									
										
										
										
											2020-08-13 23:56:31 +03:00
										 |  |  |         ]; | 
					
						
							| 
									
										
										
										
											2015-02-19 18:59:28 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-02-03 00:22:18 +01:00
										 |  |  | } |