BookStack/app/Uploads/AttachmentService.php

186 lines
5.2 KiB
PHP
Raw Normal View History

2021-06-26 23:23:15 +08:00
<?php
namespace BookStack\Uploads;
2016-11-12 22:12:26 +08:00
use BookStack\Exceptions\FileUploadException;
use Exception;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class AttachmentService
2016-11-12 22:12:26 +08:00
{
public function __construct(
protected FileStorage $storage,
) {
}
/**
* Stream an attachment from storage.
*
* @return resource|null
*/
public function streamAttachmentFromStorage(Attachment $attachment)
{
return $this->storage->getReadStream($attachment->path);
}
/**
* Read the file size of an attachment from storage, in bytes.
*/
public function getAttachmentFileSize(Attachment $attachment): int
{
return $this->storage->getSize($attachment->path);
}
2016-11-12 22:12:26 +08:00
/**
* Store a new attachment upon user upload.
2021-10-09 05:23:17 +08:00
*
2016-11-12 22:12:26 +08:00
* @throws FileUploadException
*/
public function saveNewUpload(UploadedFile $uploadedFile, int $pageId): Attachment
2016-11-12 22:12:26 +08:00
{
$attachmentName = $uploadedFile->getClientOriginalName();
$attachmentPath = $this->putFileInStorage($uploadedFile);
$largestExistingOrder = Attachment::query()->where('uploaded_to', '=', $pageId)->max('order');
2016-11-12 22:12:26 +08:00
/** @var Attachment $attachment */
$attachment = Attachment::query()->forceCreate([
2021-06-26 23:23:15 +08:00
'name' => $attachmentName,
'path' => $attachmentPath,
'extension' => $uploadedFile->getClientOriginalExtension(),
'uploaded_to' => $pageId,
2021-06-26 23:23:15 +08:00
'created_by' => user()->id,
'updated_by' => user()->id,
'order' => $largestExistingOrder + 1,
2016-11-12 22:12:26 +08:00
]);
return $attachment;
}
/**
* Store an upload, saving to a file and deleting any existing uploads
2016-11-12 22:12:26 +08:00
* attached to that file.
2021-06-26 23:23:15 +08:00
*
2016-11-12 22:12:26 +08:00
* @throws FileUploadException
*/
public function saveUpdatedUpload(UploadedFile $uploadedFile, Attachment $attachment): Attachment
2016-11-12 22:12:26 +08:00
{
if (!$attachment->external) {
$this->deleteFileInStorage($attachment);
}
$attachmentName = $uploadedFile->getClientOriginalName();
$attachmentPath = $this->putFileInStorage($uploadedFile);
2016-11-12 22:12:26 +08:00
$attachment->name = $attachmentName;
$attachment->path = $attachmentPath;
$attachment->external = false;
$attachment->extension = $uploadedFile->getClientOriginalExtension();
$attachment->save();
2021-06-26 23:23:15 +08:00
2016-11-12 22:12:26 +08:00
return $attachment;
}
/**
* Save a new File attachment from a given link and name.
*/
public function saveNewFromLink(string $name, string $link, int $page_id): Attachment
2016-11-12 22:12:26 +08:00
{
$largestExistingOrder = Attachment::where('uploaded_to', '=', $page_id)->max('order');
2021-06-26 23:23:15 +08:00
2016-11-12 22:12:26 +08:00
return Attachment::forceCreate([
2021-06-26 23:23:15 +08:00
'name' => $name,
'path' => $link,
'external' => true,
'extension' => '',
2016-11-12 22:12:26 +08:00
'uploaded_to' => $page_id,
2021-06-26 23:23:15 +08:00
'created_by' => user()->id,
'updated_by' => user()->id,
'order' => $largestExistingOrder + 1,
2016-11-12 22:12:26 +08:00
]);
}
/**
* Updates the ordering for a listing of attached files.
2016-11-12 22:12:26 +08:00
*/
public function updateFileOrderWithinPage(array $attachmentOrder, string $pageId)
2016-11-12 22:12:26 +08:00
{
foreach ($attachmentOrder as $index => $attachmentId) {
Attachment::query()->where('uploaded_to', '=', $pageId)
->where('id', '=', $attachmentId)
->update(['order' => $index]);
2016-11-12 22:12:26 +08:00
}
}
/**
* Update the details of a file.
*/
public function updateFile(Attachment $attachment, array $requestData): Attachment
2016-11-12 22:12:26 +08:00
{
if (isset($requestData['name'])) {
$attachment->name = $requestData['name'];
}
$link = trim($requestData['link'] ?? '');
if (!empty($link)) {
2016-11-12 22:12:26 +08:00
if (!$attachment->external) {
$this->deleteFileInStorage($attachment);
$attachment->external = true;
$attachment->extension = '';
2016-11-12 22:12:26 +08:00
}
$attachment->path = $link;
2016-11-12 22:12:26 +08:00
}
2016-11-12 22:12:26 +08:00
$attachment->save();
2021-10-20 17:49:45 +08:00
return $attachment->refresh();
2016-11-12 22:12:26 +08:00
}
/**
* Delete a File from the database and storage.
2021-10-09 05:23:17 +08:00
*
* @throws Exception
2016-11-12 22:12:26 +08:00
*/
public function deleteFile(Attachment $attachment)
{
if (!$attachment->external) {
$this->deleteFileInStorage($attachment);
2016-11-12 22:12:26 +08:00
}
2021-06-26 23:23:15 +08:00
2016-11-12 22:12:26 +08:00
$attachment->delete();
}
/**
* Delete a file from the filesystem it sits on.
* Cleans any empty leftover folders.
*/
public function deleteFileInStorage(Attachment $attachment): void
2016-11-12 22:12:26 +08:00
{
$this->storage->delete($attachment->path);
2016-11-12 22:12:26 +08:00
}
/**
2021-06-26 23:23:15 +08:00
* Store a file in storage with the given filename.
2021-10-09 05:23:17 +08:00
*
2016-11-12 22:12:26 +08:00
* @throws FileUploadException
*/
protected function putFileInStorage(UploadedFile $uploadedFile): string
2016-11-12 22:12:26 +08:00
{
2021-06-26 23:23:15 +08:00
$basePath = 'uploads/files/' . date('Y-m-M') . '/';
2016-11-12 22:12:26 +08:00
return $this->storage->uploadFile(
$uploadedFile,
$basePath,
$uploadedFile->getClientOriginalExtension(),
''
);
2016-11-12 22:12:26 +08:00
}
/**
* Get the file validation rules for attachments.
*/
public static function getFileValidationRules(): array
{
return ['file', 'max:' . (config('app.upload_limit') * 1000)];
}
}