Allow users to delete Shorthand Stories

Created on 25 March 2025, 4 months ago

Problem/Motivation

Currently, users cannot delete shorthand stories from Drupal, which, over time, fills the file system up with data that cannot be removed, including repulls of new versions the old versions cannot be removed.

Steps to reproduce

Pull a story
Try to delete it (There is no delete option)
Over time the filesystem size will grow.

Proposed resolution

Allow users to delete content and old versions of the stories.

✨ Feature request
Status

Active

Version

5.0

Component

Code

Created by

πŸ‡¦πŸ‡ΊAustralia shorthand

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @shorthand
  • πŸ‡¦πŸ‡ΊAustralia shorthand
  • πŸ‡¦πŸ‡ΊAustralia shorthand
  • πŸ‡ΊπŸ‡¦Ukraine ooa33

    I've created a drush command to remove unused shorthand files. The drush command depends on the content type and uses shorthand, so pay attention to the constant SHORTHAND_STORY_NODE_TYPE. Here is a code of the drush command:

    
    use Drupal\Core\Entity\EntityTypeManagerInterface;
    use Drupal\Core\File\FileSystemInterface;
    use Drupal\node\NodeStorageInterface;
    use Drush\Commands\DrushCommands;
    
    /**
     * Command for clean up unused shorthands.
     */
    class CleanUpShorthandCommand extends DrushCommands {
    
      /**
       * Shorthand story node type.
       */
      const string SHORTHAND_STORY_NODE_TYPE = 'shorthand_story';
    
      const string SHORTHAND_STORY_BASE_PATH = 'shorthand/stories';
    
      /**
       * Entity type manager.
       *
       * @var \Drupal\node\NodeStorageInterface
       */
      protected NodeStorageInterface $nodeStorage;
    
      /**
       * The file system service.
       *
       * @var \Drupal\Core\File\FileSystemInterface
       */
      protected FileSystemInterface $fileSystem;
    
      /**
       * UpdatePressReleasesCommand constructor.
       *
       * @param \Drupal\Core\Entity\EntityTypeManagerInterface $nodeStorage
       *   Entity type manager.
       * @param \Drupal\Core\File\FileSystemInterface $file_system
       *   The file handler.
       *
       * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
       * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
       */
      public function __construct(EntityTypeManagerInterface $nodeStorage, FileSystemInterface $file_system) {
        parent::__construct();
        $this->nodeStorage = $nodeStorage->getStorage('node');
        $this->fileSystem = $file_system;
      }
    
      /**
       * Drush command to clean up not used shorthands.
       *
       * @command common:clean-up-shorthand
       * @aliases cush
       */
      public function run() {
        $confirm = $this->io()->confirm('Are you sure you want to delete all not used shorthands?', TRUE);
        if (!$confirm) {
          $this->output()->writeln('Command cancelled.');
          return;
        }
    
        // Shorthand nodes.
        $nodes = $this->nodeStorage->loadByProperties([
          'type' => self::SHORTHAND_STORY_NODE_TYPE,
        ]);
    
        $usedShorthands = [];
        if ($nodes) {
          foreach ($nodes as $node) {
            $parts = explode('/', $node->field_shorthand->value);
            if (count($parts)) {
              $usedShorthands[$parts[0]] = $parts[1];
            }
          }
        }
    
        $destination_uri = 'public://' . static::SHORTHAND_STORY_BASE_PATH;
        $storyFolders = $this->fileSystem->scanDirectory($destination_uri, '/.*/', [
          'recurse' => FALSE,
          'key' => 'filename',
        ]);
        $localStories = array_keys($storyFolders);
        foreach ($localStories as $story) {
          $storyVariants = $this->fileSystem->scanDirectory($destination_uri . '/' . $story, '/.*/', [
            'recurse' => FALSE,
            'key' => 'filename',
          ]);
          if (empty($usedShorthands[$story])) {
            // Remove the story folder.
            $folder = $destination_uri . '/' . $story;
            $this->fileSystem->deleteRecursive($folder);
            $this->writeln(t('Removed shorthand: @title', [
              '@title' => $story,
            ]));
          }
          else {
            foreach ($storyVariants as $storyVariant => $data) {
              if ($storyVariant != $usedShorthands[$story]) {
                $folder = $destination_uri . '/' . $story . '/' . $storyVariant;
                $this->fileSystem->deleteRecursive($folder);
                $this->writeln(t('Removed shorthand: @title @version', [
                  '@title' => $story,
                  '@version' => $storyVariant,
                ]));
              }
            }
          }
        }
    
        $this->io()->success('All unused shorthand stories removed.');
      }
    
    }
    
  • πŸ‡¦πŸ‡ΊAustralia jannakha Brisbane!

    @ooa33 - do you mind putting your code as a merge request?

  • Status changed to Needs work 19 days ago
  • First commit to issue fork.
  • Merge request !54Added drush commands β†’ (Open) created by VladimirAus
  • πŸ‡¦πŸ‡ΊAustralia VladimirAus Brisbane, Australia

    Code pushed ready for review

  • πŸ‡§πŸ‡ͺBelgium joevagyok

    I think it would be very useful to have actual clickable actions under /admin/content/shorthand table besides "Update story", like "Delete story" and "Delete story versions" that would take you to a confirmation page where you can select with checkboxes the version the user wish to delete.

  • πŸ‡¦πŸ‡ΊAustralia VladimirAus Brisbane, Australia

    @joevagyok sounds like a great idea.
    Please create new issue and merge request.

  • πŸ‡§πŸ‡ͺBelgium joevagyok

    @vladimiraus I am not sure if the new issue is really necessary. This issue is perfectly describes the problem. I think a new MR would be sufficient, but I can create a new issue if you insist.

Production build 0.71.5 2024