Skip to content

Commit

Permalink
feat(files): file plugin files are now stored with the entity
Browse files Browse the repository at this point in the history
  • Loading branch information
jdalsem committed Sep 29, 2022
1 parent 92c50dd commit 9df0cd0
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 149 deletions.
6 changes: 6 additions & 0 deletions docs/appendix/upgrade-notes/4.x-to-5.0.rst
Expand Up @@ -36,6 +36,12 @@ Async or system upgrades are no longer classes that implement interfaces but ext
The reason for this change is to be able to access the ``ElggUpgrade`` entity from the ``Batch`` that runs a part of the upgrade.
You can access the upgrade by calling ``$this->getUpgrade()``.

Files plugin
------------

Files uploaded using the file plugin are no longer stored with the owner but with the file entity. File icons have also been changed.
Icon images are only available for image file types. Icon sizes have been changed to use the default icon sizes.

Javascript
----------

Expand Down
9 changes: 7 additions & 2 deletions engine/classes/ElggDiskFilestore.php
Expand Up @@ -208,9 +208,14 @@ public function getFileSize(\ElggFile $file): int {
* @throws InvalidParameterException
*/
public function getFilenameOnFilestore(\ElggFile $file): string {
$owner_guid = $file->getOwnerGuid();

$owner_guid = null;
if (!empty($file->guid) && $file->getSubtype() === 'file') {
$owner_guid = $file->guid;
}

if (!$owner_guid) {
$owner_guid = _elgg_services()->session->getLoggedInUserGuid();
$owner_guid = $file->owner_guid ?: _elgg_services()->session->getLoggedInUserGuid();
}

if (!$owner_guid) {
Expand Down
Expand Up @@ -52,15 +52,17 @@ public function testFilenameOnFilestore() {

function testElggFileDelete() {
$user = $this->owner;
$dir = new EntityDirLocator($user->guid);


$file = new ElggFile();
$file->owner_guid = $user->guid;
$file->save();

$file->setFilename('testing/ElggFileDelete');
$this->assertTrue(is_resource($file->open('write')));
$this->assertIsInt($file->write('Test'));
$this->assertTrue($file->close());
$file->save();

$dir = new EntityDirLocator($file->guid);

$filename = $file->getFilenameOnFilestore();
$filepath = _elgg_services()->config->dataroot . $dir . "testing/ElggFileDelete";
Expand Down
29 changes: 3 additions & 26 deletions mod/file/actions/file/upload.php
Expand Up @@ -55,44 +55,21 @@
$file->save();

if ($uploaded_file && $uploaded_file->isValid()) {
// remove old icons
$sizes = elgg_get_icon_sizes($file->getType(), $file->getSubtype());
$master_location = null;
foreach ($sizes as $size => $props) {
$icon = $file->getIcon($size);
if ($size === 'master') {
// needs to be kept in case upload fails
$master_location = $icon->getFilenameOnFilestore();
continue;
}

$icon->delete();
}

// save master file
if (!$file->acceptUploadedFile($uploaded_file)) {
return elgg_error_response(elgg_echo('file:uploadfailed'));
}

if (!$file->save()) {
return elgg_error_response(elgg_echo('file:uploadfailed'));
}

// remove old icons
$file->deleteIcon();

// update icons
if ($file->getSimpleType() === 'image') {
$file->saveIconFromElggFile($file);
}

// check if we need to remove the 'old' master icon
$master = $file->getIcon('master');
if ($master->getFilenameOnFilestore() !== $master_location) {
unlink($master_location);
}

// remove legacy metadata
unset($file->thumbnail);
unset($file->smallthumb);
unset($file->largethumb);
}

// file saved so clear sticky form
Expand Down
84 changes: 3 additions & 81 deletions mod/file/classes/Elgg/File/Icons.php
Expand Up @@ -11,30 +11,10 @@
*/
class Icons {

/**
* Handle an object being deleted
*
* @param \Elgg\Event $event 'delete', 'object'
*
* @return void
*/
public static function deleteIconOnElggFileDelete(\Elgg\Event $event) {
$file = $event->getObject();
if (!$file instanceof \ElggFile) {
return;
}
if (!$file->guid) {
// this is an ElggFile used as temporary API
return;
}

$file->deleteIcon();
}

/**
* Set custom icon sizes for file objects
*
* @param \Elgg\Hook $hook "entity:icon:url", "object"
* @param \Elgg\Hook $hook "entity:icon:sizes", "object"
*
* @return array
*/
Expand All @@ -45,71 +25,13 @@ public static function setIconSizes(\Elgg\Hook $hook) {
}

$return = $hook->getValue();

$return['small'] = [
'w' => 60,
'h' => 60,
'square' => true,
'upscale' => true,
];
$return['medium'] = [
'w' => 153,
'h' => 153,
'square' => true,
'upscale' => true,
];
$return['large'] = [

$return['xlarge'] = [
'w' => 600,
'h' => 600,
'upscale' => false,
];

return $return;
}

/**
* Set custom file thumbnail location
*
* @param \Elgg\Hook $hook "entity:icon:file", "object"
*
* @return \ElggIcon
*/
public static function setIconFile(\Elgg\Hook $hook) {

$entity = $hook->getEntityParam();
if (!$entity instanceof \ElggFile) {
return;
}

$size = $hook->getParam('size', 'large');
switch ($size) {
case 'small' :
$filename_prefix = 'thumb';
$metadata_name = 'thumbnail';
break;

case 'medium' :
$filename_prefix = 'smallthumb';
$metadata_name = 'smallthumb';
break;

default :
$filename_prefix = "{$size}thumb";
$metadata_name = $filename_prefix;
break;
}

$icon = $hook->getValue();

$icon->owner_guid = $entity->owner_guid;
if (isset($entity->$metadata_name)) {
$icon->setFilename($entity->$metadata_name);
} else {
$filename = pathinfo($entity->getFilenameOnFilestore(), PATHINFO_FILENAME);
$filename = "file/{$filename_prefix}{$filename}.jpg";
$icon->setFilename($filename);
}

return $icon;
}
}
6 changes: 2 additions & 4 deletions mod/file/classes/Elgg/File/Seeder.php
Expand Up @@ -26,12 +26,12 @@ public function seed() {

$filename = pathinfo($path, PATHINFO_FILENAME);

$file = $this->createObject($attributes, [], ['save' => false]);
$file = $this->createObject($attributes);
if (!$file instanceof \ElggFile) {
continue;
}

$file->setFilename("file/$filename");
$file->setFilename("file/{$filename}");
$file->open('write');
$file->close();

Expand All @@ -42,8 +42,6 @@ public function seed() {
continue;
}

$file->saveIconFromElggFile($file);

$this->createComments($file);
$this->createLikes($file);

Expand Down
128 changes: 128 additions & 0 deletions mod/file/classes/Elgg/File/Upgrades/MoveFiles.php
@@ -0,0 +1,128 @@
<?php

namespace Elgg\File\Upgrades;

use Elgg\Database\QueryBuilder;
use Elgg\Upgrade\AsynchronousUpgrade;
use Elgg\Upgrade\Result;

/**
* Move ElggFile files to entity location
*/
class MoveFiles extends AsynchronousUpgrade {

/**
* {@inheritDoc}
*/
public function getVersion(): int {
return 2022092801;
}

/**
* {@inheritDoc}
*/
public function needsIncrementOffset(): bool {
return false;
}

/**
* {@inheritDoc}
*/
public function shouldBeSkipped(): bool {
return empty($this->countItems());
}

/**
* {@inheritDoc}
*/
public function countItems(): int {
return elgg_count_entities($this->getOptions());
}

/**
* {@inheritDoc}
*/
public function run(Result $result, $offset): Result {

$batch = elgg_get_entities($this->getOptions([
'offset' => $offset,
]));

/* @var $entity \ElggFile */
foreach ($batch as $entity) {
if (!$entity->exists()) {
$result->addSuccesses();
$entity->_elgg_file_migrated = time();
continue;
}

$old_location = $entity->getFilenameOnFilestore();
$new_file = new \ElggFile();
$new_file->owner_guid = $entity->guid;
$new_file->setFilename($entity->getFilename());
$new_file->open('write');
$new_file->close();

if (!rename($old_location, $new_file->getFilenameOnFilestore())) {
$result->addFailures();
continue;
}

// generate master icon for new location
if ($entity->simpletype === 'image') {
$entity->saveIconFromElggFile($new_file);
}

$entity->_elgg_file_migrated = time();

// remove thumbnails
if ($entity->simpletype === 'image') {
foreach (['thumb', 'smallthumb', 'largethumb', 'masterthumb'] as $prefix) {
$old_thumb = new \ElggFile();
$old_thumb->owner_guid = $entity->owner_guid;

$base_filename = "{$entity->filestore_prefix}/{$prefix}{$entity->upload_time}". pathinfo($entity->originalfilename, PATHINFO_FILENAME);

foreach (['jpg', 'webp'] as $extension) {
$old_thumb->setFilename("{$base_filename}.{$extension}");
$old_thumb->delete();
}
}
}

$result->addSuccesses();
}

return $result;
}

/**
* Options for elgg_get_entities()
*
* @param array $options additional options
*
* @return array
* @see elgg_get_entities()
*/
protected function getOptions(array $options = []): array {
$defaults = [
'type' => 'object',
'subtype' => 'file',
'limit' => 100,
'batch' => true,
'batch_inc_offset' => $this->needsIncrementOffset(),
'created_before' => $this->getUpgrade()->time_created,
'wheres' => [
function (QueryBuilder $qb, $main_alias) {
$sub = $qb->subquery('metadata');
$sub->select('entity_guid')
->where($qb->compare('name', '=', '_elgg_file_migrated', ELGG_VALUE_STRING));

return $qb->compare("{$main_alias}.guid", 'not in', $sub->getSQL());
}
],
];

return array_merge($defaults, $options);
}
}
15 changes: 3 additions & 12 deletions mod/file/elgg-plugin.php
Expand Up @@ -21,6 +21,9 @@
],
],
],
'upgrades' => [
'Elgg\File\Upgrades\MoveFiles',
],
'actions' => [
'file/upload' => [],
],
Expand Down Expand Up @@ -76,11 +79,6 @@
GroupToolContainerLogicCheck::class => [],
],
],
'entity:icon:file' => [
'object' => [
'Elgg\File\Icons::setIconFile' => [],
],
],
'entity:icon:sizes' => [
'object' => [
'Elgg\File\Icons::setIconSizes' => [],
Expand Down Expand Up @@ -108,13 +106,6 @@
],
],
],
'events' => [
'delete' => [
'object' => [
'Elgg\File\Icons::deleteIconOnElggFileDelete' => ['priority' => 999],
],
],
],
'widgets' => [
'filerepo' => [
'context' => ['profile', 'dashboard'],
Expand Down

0 comments on commit 9df0cd0

Please sign in to comment.