Skip to content

Commit e90516b

Browse files
authored
Merge pull request #13957 from craftcms/feature/cms-989-temp-upload-location-filesystem
Feature/cms 989 temp upload location filesystem
2 parents fc71fca + 6f5807b commit e90516b

File tree

17 files changed

+193
-235
lines changed

17 files changed

+193
-235
lines changed

CHANGELOG-WIP.md

+2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@
5353
- Volumes now have a “Subpath” setting, and can reuse filesystems so long as the subpaths don’t overlap. ([#11044](https://github.com/craftcms/cms/discussions/11044))
5454
- Volumes now have an “Alternative Text Translation Method” setting. ([#11576](https://github.com/craftcms/cms/issues/11576))
5555
- Added support for defining custom locale aliases, via a new `localeAliases` config setting. ([#12705](https://github.com/craftcms/cms/pull/12705))
56+
- Added the `tempAssetUploadFs` config setting. ([#13957](https://github.com/craftcms/cms/pull/13957))
5657
- Removed the concept of field groups.
58+
- Removed the “Temp Uploads Location” asset setting. ([#13957](https://github.com/craftcms/cms/pull/13957))
5759
- `entrify/*` commands now ask if an entry type already exists for the section.
5860
- The `resave/entries` command now accepts a `--field` option.
5961
- The `up`, `migrate/up`, and `migrate/all` commands no longer overwrite pending project config YAML changes, if new project config changes were made by migrations.

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Added the `tempAssetUploadFs` config setting. ([#13957](https://github.com/craftcms/cms/pull/13957))
6+
- Removed the “Temp Uploads Location” asset setting. ([#13957](https://github.com/craftcms/cms/pull/13957))
57
- Element search scores set on `craft\events\SearchEvent::$scores` by `craft\services\Search::EVENT_AFTER_SEARCH` or `EVENT_BEFORE_SCORE_RESULTS` now must be indexed by element ID and site ID (e.g. `'100-1'`).
68
- Deprecated `craft\events\SearchEvent::$siteId`.
79
- Fixed a bug where multi-site element queries weren’t scoring elements on a per-site basis. ([#13801](https://github.com/craftcms/cms/discussions/13801))

src/config/GeneralConfig.php

+38
Original file line numberDiff line numberDiff line change
@@ -2793,6 +2793,24 @@ class GeneralConfig extends BaseConfig
27932793
*/
27942794
public bool $storeUserIps = false;
27952795

2796+
/**
2797+
* @var string|null The handle of the filesystem that should be used for storing temporary asset uploads. A local temp folder will
2798+
* be used by default.
2799+
*
2800+
* ::: code
2801+
* ```php Static Config
2802+
* ->tempAssetUploadFs('$TEMP_ASSET_UPLOADS_FS')
2803+
* ```
2804+
* ```shell Environment Override
2805+
* CRAFT_TEMP_ASSET_UPLOAD_FS=tempAssetUploads
2806+
* ```
2807+
* :::
2808+
*
2809+
* @group Assets
2810+
* @since 5.0.0
2811+
*/
2812+
public ?string $tempAssetUploadFs = null;
2813+
27962814
/**
27972815
* @var string|array|null|false Configures Craft to send all system emails to either a single email address or an array of email addresses
27982816
* for testing purposes.
@@ -6213,6 +6231,26 @@ public function storeUserIps(bool $value = true): self
62136231
return $this;
62146232
}
62156233

6234+
/**
6235+
* The handle of the filesystem that should be used for storing temporary asset uploads. A local temp folder will
6236+
* be used by default.
6237+
*
6238+
* ```php
6239+
* ->tempAssetUploadFs('$TEMP_ASSET_UPLOADS_FS')
6240+
* ```
6241+
*
6242+
* @group Assets
6243+
* @param string|null $value
6244+
* @return self
6245+
* @see $tempAssetUploadFs
6246+
* @since 5.0.0
6247+
*/
6248+
public function tempAssetUploadFs(string|null $value): self
6249+
{
6250+
$this->tempAssetUploadFs = $value;
6251+
return $this;
6252+
}
6253+
62166254
/**
62176255
* Configures Craft to send all system emails to either a single email address or an array of email addresses
62186256
* for testing purposes.

src/controllers/AssetSettingsController.php

-62
This file was deleted.

src/controllers/VolumesController.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use craft\base\Field;
1212
use craft\base\FsInterface;
1313
use craft\elements\Asset;
14+
use craft\helpers\Assets;
1415
use craft\helpers\FileHelper;
1516
use craft\helpers\Json;
1617
use craft\models\Volume;
@@ -105,7 +106,7 @@ public function actionEditVolume(?int $volumeId = null, ?Volume $volume = null):
105106
->map(fn(FsInterface $fs) => [
106107
'label' => $fs->name,
107108
'value' => $fs->handle,
108-
'disabled' => $takenFsHandles->contains($fs->handle) && $fs->handle !== $fsHandle,
109+
'disabled' => Assets::isTempUploadFs($fs) || ($takenFsHandles->contains($fs->handle) && $fs->handle !== $fsHandle),
109110
])
110111
->all();
111112
array_unshift($fsOptions, ['label' => Craft::t('app', 'Select a filesystem'), 'value' => '']);

src/elements/Asset.php

+34-25
Original file line numberDiff line numberDiff line change
@@ -372,14 +372,12 @@ protected static function defineSources(string $context): array
372372
$sources[] = self::_assembleSourceInfoForFolder($folder, $user);
373373
}
374374

375-
// Add the Temporary Uploads location, if that's not set to a real volume
375+
// Add the Temporary Uploads location
376376
if (
377377
$context !== ElementSources::CONTEXT_SETTINGS &&
378-
!Craft::$app->getRequest()->getIsConsoleRequest() &&
379-
!Craft::$app->getProjectConfig()->get('assets.tempVolumeUid')
378+
!Craft::$app->getRequest()->getIsConsoleRequest()
380379
) {
381380
$temporaryUploadFolder = Craft::$app->getAssets()->getUserTemporaryUploadFolder();
382-
$temporaryUploadFolder->name = Craft::t('app', 'Temporary Uploads');
383381
$sources[] = self::_assembleSourceInfoForFolder($temporaryUploadFolder);
384382
}
385383

@@ -461,7 +459,8 @@ protected static function defineActions(string $source): array
461459

462460
// Only match the first folder ID - ignore nested folders
463461
if (isset($volume)) {
464-
$isTemp = $volume->getFs() instanceof Temp;
462+
$fs = $volume->getFs();
463+
$isTemp = Assets::isTempUploadFs($fs);
465464

466465
$actions[] = [
467466
'type' => PreviewAsset::class,
@@ -479,7 +478,7 @@ protected static function defineActions(string $source): array
479478
}
480479

481480
// Copy URL
482-
if ($volume->getFs()->hasUrls) {
481+
if ($fs->hasUrls) {
483482
$actions[] = CopyUrl::class;
484483
}
485484

@@ -765,7 +764,7 @@ private static function _includeFoldersInIndexElements(AssetQuery $assetQuery, ?
765764
}
766765
}
767766

768-
if ($queryFolder->getVolume()->getFs() instanceof Temp) {
767+
if (Assets::isTempUploadFs($queryFolder->getFs())) {
769768
return false;
770769
}
771770

@@ -881,9 +880,7 @@ private static function _assembleSourceInfoForFolder(VolumeFolder $folder, ?User
881880
{
882881
$volume = $folder->getVolume();
883882
$fs = $volume->getFs();
884-
if ($fs instanceof Temp) {
885-
$volumeHandle = 'temp';
886-
} elseif (!$folder->parentId) {
883+
if (!$folder->parentId) {
887884
$volumeHandle = $volume->handle ?? false;
888885
} else {
889886
$volumeHandle = false;
@@ -1333,7 +1330,7 @@ public function canView(User $user): bool
13331330
return $user->can("viewPeerAssets:$volume->uid");
13341331
}
13351332

1336-
if ($volume->getFs() instanceof Temp) {
1333+
if (Assets::isTempUploadFs($volume->getFs())) {
13371334
return true;
13381335
}
13391336

@@ -1373,7 +1370,7 @@ public function canDelete(User $user): bool
13731370

13741371
$volume = $this->getVolume();
13751372

1376-
if ($volume->getFs() instanceof Temp) {
1373+
if (Assets::isTempUploadFs($volume->getFs())) {
13771374
return true;
13781375
}
13791376

@@ -1404,7 +1401,7 @@ protected function cpEditUrl(): ?string
14041401
}
14051402

14061403
$volume = $this->getVolume();
1407-
if ($volume->getFs() instanceof Temp) {
1404+
if (Assets::isTempUploadFs($volume->getFs())) {
14081405
return null;
14091406
}
14101407

@@ -2068,10 +2065,10 @@ private function _url(mixed $transform = null, ?bool $immediately = null): ?stri
20682065
return $url;
20692066
}
20702067

2071-
// todo: uncomment for v5. Currently Imager X is relying on a relative URL being returned
2072-
//if (!$volume->getFs()->hasUrls) {
2073-
// return null;
2074-
//}
2068+
$fs = $volume->getFs();
2069+
if (!$fs->hasUrls || Assets::isTempUploadFs($fs)) {
2070+
return null;
2071+
}
20752072

20762073
return Html::encodeSpaces(Assets::generateUrl($volume, $this));
20772074
}
@@ -2711,15 +2708,27 @@ protected function metadata(): array
27112708
private function locationHtml(): string
27122709
{
27132710
$volume = $this->getVolume();
2714-
$uri = "assets/$volume->handle";
2715-
$items = [
2716-
Html::a(Craft::t('site', Html::encode($volume->name)), UrlHelper::cpUrl($uri)),
2717-
];
2711+
$isTemp = Assets::isTempUploadFs($volume->getFs());
2712+
2713+
if (!$isTemp) {
2714+
$uri = "assets/$volume->handle";
2715+
$items = [
2716+
Html::a(Craft::t('site', Html::encode($volume->name)), UrlHelper::cpUrl($uri)),
2717+
];
2718+
} else {
2719+
$items = [
2720+
Html::tag('span', Craft::t('site', Html::encode($volume->name))),
2721+
];
2722+
}
27182723
if ($this->folderPath) {
27192724
$subfolders = ArrayHelper::filterEmptyStringsFromArray(explode('/', $this->folderPath));
27202725
foreach ($subfolders as $subfolder) {
2721-
$uri .= "/$subfolder";
2722-
$items[] = Html::a($subfolder, UrlHelper::cpUrl($uri));
2726+
if (!$isTemp) {
2727+
$uri .= "/$subfolder";
2728+
$items[] = Html::a($subfolder, UrlHelper::cpUrl($uri));
2729+
} else {
2730+
$items[] = Html::tag('span', $subfolder);
2731+
}
27232732
}
27242733
}
27252734

@@ -2841,7 +2850,7 @@ public function beforeSave(bool $isNew): bool
28412850
// Set the field layout
28422851
$volume = Craft::$app->getAssets()->getFolderById($folderId)->getVolume();
28432852

2844-
if (!$volume->getFs() instanceof Temp) {
2853+
if (!Assets::isTempUploadFs($volume->getFs())) {
28452854
$this->fieldLayoutId = $volume->fieldLayoutId;
28462855
}
28472856

@@ -3061,7 +3070,7 @@ protected function htmlAttributes(string $context): array
30613070
$userSession = Craft::$app->getUser();
30623071
$imageEditable = $context === ElementSources::CONTEXT_INDEX && $this->getSupportsImageEditor();
30633072

3064-
if ($volume->getFs() instanceof Temp || $userSession->getId() == $this->uploaderId) {
3073+
if (Assets::isTempUploadFs($volume->getFs()) || $userSession->getId() == $this->uploaderId) {
30653074
$attributes['data']['own-file'] = true;
30663075
$movable = $replaceable = true;
30673076
} else {

src/fs/Temp.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class Temp extends Local
2727
*/
2828
public static function displayName(): string
2929
{
30-
return Craft::t('app', 'Temp Folder');
30+
return 'Temp';
3131
}
3232

3333
/**
@@ -40,7 +40,7 @@ public function __construct($config = [])
4040
$config['path'] = Craft::$app->getPath()->getTempAssetUploadsPath();
4141
}
4242
if (!isset($config['name'])) {
43-
$config['name'] = Craft::t('app', 'Temporary filesystem');
43+
$config['name'] = Craft::t('app', 'Temporary Uploads');
4444
}
4545

4646
parent::__construct($config);

src/helpers/Assets.php

+21
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use craft\errors\FsException;
1717
use craft\events\RegisterAssetFileKindsEvent;
1818
use craft\events\SetAssetFilenameEvent;
19+
use craft\fs\Temp;
1920
use craft\helpers\ImageTransforms as TransformHelper;
2021
use craft\models\VolumeFolder;
2122
use DateTime;
@@ -956,4 +957,24 @@ public static function iconSvg(string $extension): string
956957

957958
return Html::appendToTag($svg, $textNode);
958959
}
960+
961+
/**
962+
* Returns whether the given filesystem is used to store temporary asset uploads.
963+
*
964+
* @param FsInterface $fs
965+
* @return bool
966+
*/
967+
public static function isTempUploadFs(FsInterface $fs): bool
968+
{
969+
if ($fs instanceof Temp) {
970+
return true;
971+
}
972+
973+
if (!$fs->handle) {
974+
return false;
975+
}
976+
977+
$handle = App::parseEnv(Craft::$app->getConfig()->getGeneral()->tempAssetUploadFs);
978+
return $fs->handle === $handle;
979+
}
959980
}

src/models/Volume.php

+17
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ public function attributeLabels(): array
170170
'name' => Craft::t('app', 'Name'),
171171
'url' => Craft::t('app', 'URL'),
172172
'fsHandle' => Craft::t('app', 'Asset Filesystem'),
173+
'subpath' => Craft::t('app', 'Subpath'),
173174
'transformFsHandle' => Craft::t('app', 'Transform Filesystem'),
174175
'transformSubpath' => Craft::t('app', 'Transform Subpath'),
175176
];
@@ -199,6 +200,22 @@ protected function defineRules(): array
199200
];
200201
$rules[] = [['fieldLayout'], 'validateFieldLayout'];
201202
$rules[] = [['subpath'], fn($attribute) => $this->validateUniqueSubpath($attribute), 'skipOnEmpty' => false];
203+
$rules[] = [
204+
['fsHandle'],
205+
'compare',
206+
'compareAttribute' => 'fsHandle',
207+
'compareValue' => App::parseEnv(Craft::$app->getConfig()->getGeneral()->tempAssetUploadFs),
208+
'operator' => '!=',
209+
'message' => Craft::t('app', 'This filesystem has been reserved for temporary asset uploads. Please choose a different one for your volume.'),
210+
];
211+
$rules[] = [
212+
['transformFsHandle'],
213+
'compare',
214+
'compareAttribute' => 'transformFsHandle',
215+
'compareValue' => App::parseEnv(Craft::$app->getConfig()->getGeneral()->tempAssetUploadFs),
216+
'operator' => '!=',
217+
'message' => Craft::t('app', 'This filesystem has been reserved for temporary asset uploads. Please choose a different one for your volume.'),
218+
];
202219

203220
return $rules;
204221
}

0 commit comments

Comments
 (0)