๐Ÿ‡จ๐Ÿ‡ฆCanada @Nathan Tsai

Account created on 4 July 2014, over 10 years ago
#

Merge Requests

More

Recent comments

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

A snapshot of the most recent merge request.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Note: to support Drupal 10, we need to depend on adaptivethemes:^5.0

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Thank you everyone for your hard work! (And patience)

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Sorry for the delay, @yuvania, and thank you for the review! Merged :)

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Thank you for catching this @andrew answer!

Committed :)

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

nathan tsai โ†’ made their first commit to this issueโ€™s fork.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

nathan tsai โ†’ made their first commit to this issueโ€™s fork.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

For some reason, I had to make sure my JSON file was not pretty printed (e.g. removed the unnecessary whitespace).

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

More details re: media revisions numbers not being accurate.

(Note: I'm using Drupal 10.3.)

So, what's happening is that when a media item is loaded, it's not loading the latest revision.

E.g. When there are two revisions 454 and 455, for some reason the system is loading 454 by default (instead of 455).

--

Also, this code makes the system act really strange. Specifically, after running this code, the newest revision ID is not displayed on the new media revision UI (mentioned here: https://www.drupal.org/node/3366630 โ†’ ).

      $mediaStorage = $this->entityTypeManager()->getStorage('media');
      $lastestId = $mediaStorage->getLatestRevisionId($media->id());
      $lastestMedia = $mediaStorage->loadRevision($lastestId);

      $media->set(HrConstants::documentIsInitializedField, $lastestMedia->get(HrConstants::documentIsInitializedField)->value);
      $media->setNewRevision(TRUE);
      $media->setRevisionLogMessage('Resave to avoid revision number being incorrect.');
      $media->save();
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Reroll patch in case someone wants a snapshot

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Okay, I'm running into this problem with media (and without redis/memcache/any in-memory database system).

Transaction isolation level: REPEATABLE-READ

Unfortunately, I also can't consistently replicate this.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Requires [3247179] in order to fix the warnings.

  1. Apply patch https://git.drupalcode.org/project/composer_manager/-/merge_requests/6.diff in [3247179]
  2. Upgrade giggsey/libphonenumber-for-php to ^8.12
  3. Add instructions for users to then:
    1. Update the consolidated composer.json file at /admin/config/system/composer-manager
    2. Run composer update in the file directory /SITE_DIR/sites/default/files/composer
    • (which is the path listed at /admin/config/system/composer-manager/settings)
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Upgraded to "giggsey/libphonenumber-for-php": "^8.12".

Then had to:

  1. Update the consolidated composer.json file.
  2. Then run composer update in the file directory /SITE_DIR/sites/default/files/composer (which is the path listed at /admin/config/system/composer-manager/settings)

Now the error is gone, but when I go to /admin/config/system/composer-manager, I get:

    Warning: Undefined array key "name" in composer_manager_installed_packages() (line 325 of /SITE_DIR/sites/all/modules/composer_manager/composer_manager.admin.inc).
    Warning: Undefined array key "version" in composer_manager_installed_packages() (line 326 of /SITE_DIR/sites/all/modules/composer_manager/composer_manager.admin.inc).
    Warning: Trying to access array offset on value of type bool in composer_manager_installed_packages() (line 325 of /SITE_DIR/sites/all/modules/composer_manager/composer_manager.admin.inc).
    Warning: Trying to access array offset on value of type bool in composer_manager_installed_packages() (line 326 of /SITE_DIR/sites/all/modules/composer_manager/composer_manager.admin.inc).
    Warning: Undefined array key "name" in composer_manager_installed_packages() (line 325 of /SITE_DIR/sites/all/modules/composer_manager/composer_manager.admin.inc).
    Warning: Undefined array key "version" in composer_manager_installed_packages() (line 326 of /SITE_DIR/sites/all/modules/composer_manager/composer_manager.admin.inc).
    The following packages must be installed: giggsey/libphonenumber-for-php
    Refer to the instructions on the Composer Manager project page for updating packages.
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

I am currently working on the Chrome/Android side:

Here's is the CSS code (when the block id is: pwa_install):


#block-pwa-install .button {
background: 0 0;
padding: .4rem .5rem;
margin: .2rem 0 0 1.5rem;
border: 1px solid #f00a21;
color: #f00a21;
font-weight: 700;
text-transform: uppercase;
border-radius: .2rem;
cursor: pointer;
transition: background 0.4s, color 0.4s;
text-shadow: none; /* Override default styles */
}

#block-pwa-install .button:before {
content: "โค“";
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23F00A21'%3E%3Cpath d='M19 9h-4V3H9v6H5l7 7zM5 18v2h14v-2z'%3E%3C/path%3E%3C/svg%3E");
width: 1.3em;
display: inline-block;
color: transparent;
font-size: 1.3rem;
margin-top: -.1rem;
vertical-align: middle;
transition: background 0.4s;
}

#block-pwa-install .button:hover,
#block-pwa-install .button:focus {
background: #f00a21;
color: #fff;
}

#block-pwa-install .button:hover:before,
#block-pwa-install .button:focus:before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23fff'%3E%3Cpath d='M19 9h-4V3H9v6H5l7 7zM5 18v2h14v-2z'%3E%3C/path%3E%3C/svg%3E");
}

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Sebastian, this looks incredible! Some considerations for future iterations:

  • Text as a configuration option - make have the image url be a token/Twig variable?
  • We would also need to make sure this element looks okay on Safari desktop.
  • Allow people to remove the banner (and save it in a cookie/local storage to not show it again?)
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Final code to enable a custom prompt + bell notification.

Requires updating the script to v16.

(Remember to enable permissions for the OneSignal scripts to load!)

function MY_MODULE_onesignal_extra_js() {

  $current_path = \Drupal::service('path.current')->getPath();
  if ($current_path != '/node/777') {
    return;
  }

  $addCustomPrompt = "
    // Source: https://documentation.onesignal.com/docs/custom-link-prompt#step-3-provide-configuration
    var promptOptions = {
      promptOptions: {
        customlink: {
          enabled: true, /* Required to use the Custom Link */
          style: 'button', /* Has value of 'button' or 'link' */
          size: 'medium', /* One of 'small', 'medium', or 'large' */
          color: {
            button: '#E12D30', /* Color of the button background if style = 'button' */
            text: '#FFFFFF', /* Color of the prompt's text */
          },
          text: {
            subscribe: 'Subscribe to push notifications', /* Prompt's text when not subscribed */
            unsubscribe: 'Unsubscribe from push notifications', /* Prompt's text when subscribed */
            explanation: 'Get updates from all sorts of things that matter to you', /* Optional text appearing before the prompt button */
          },
          unsubscribeEnabled: true, /* Controls whether the prompt is visible after subscription */
        }
      }
    }

    var notifyButton = {
      notifyButton: {
          enable: true
      },
    };

    var serviceWorkerOptions = { 
      serviceWorkerParam: { scope: '/OneSignal/' },
      serviceWorkerPath: 'OneSignal/OneSignalSDKWorker.js',
    };

    Object.assign(___OneSignalDrupalModuleConfig, promptOptions, notifyButton, serviceWorkerOptions);
  ";

  return $addCustomPrompt;
}
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

The proposed change is fairly simple:

diff --git a/onesignal.module b/onesignal.module
index b1063c7e3ef42044800dce580efebbad20c60470..d17f4eef031dfc308871fd58d886a4e0784de389 100644
--- a/onesignal.module
+++ b/onesignal.module
@@ -140,8 +140,9 @@ function onesignal_page_attachments(&$attachments) {
     '#template' => "
         var OneSignal = window.OneSignal || [];
         OneSignal.push(function() {
+          var ___OneSignalDrupalModuleConfig = {{ onesignal_json|raw }};
           {{ extra_js|raw }}
-          OneSignal.init({{ onesignal_json|raw }});
+          OneSignal.init(___OneSignalDrupalModuleConfig);
         });
       ",
     '#context' => [

This allows `extra_js` to modify `___OneSignalDrupalModuleConfig`, e.g.

// Source: https://documentation.onesignal.com/docs/custom-link-prompt#step-3-provide-configuration
___OneSignalDrupalModuleConfig ['promptOptions'] = {
  customlink: {
    enabled: true, /* Required to use the Custom Link */
    style: "button", /* Has value of 'button' or 'link' */
    size: "medium", /* One of 'small', 'medium', or 'large' */
    color: {
      button: '#E12D30', /* Color of the button background if style = "button" */
      text: '#FFFFFF', /* Color of the prompt's text */
    },
    text: {
      subscribe: "Subscribe to push notifications", /* Prompt's text when not subscribed */
      unsubscribe: "Unsubscribe from push notifications", /* Prompt's text when subscribed */
      explanation: "Get updates from all sorts of things that matter to you", /* Optional text appearing before the prompt button */
    },
    unsubscribeEnabled: true, /* Controls whether the prompt is visible after subscription */
  }
}

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

I don't know how to run tests on a MR - so here's the patch!

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Opps - forgot some code clean up

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Okay, first attempt.

Not multilingual and will probably want to use a service later one. Would love to get some feedback first though :)

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Note: I set this category to "Bug Report" because I assume that it should be impossible to configure Gutenberg to lead to a 500 error.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

I think this simplest custom approach would be:

function _mymodule_node_presave(\Drupal\node\NodeInterface $node) {
_mymodule_notify_new_users($node);
}

function _mymodule_notify_new_users(\Drupal\node\NodeInterface $node) {
if ($node->getType() !== 'MY TYPE") {
return;
}

// Only send if a new node + is published.
// TODO: enable sending if initially unpublished, then later published
if (!($node->isNew() && $node->isPublished())) {
return;
}

$onesignal = \Drupal::service('onesignal');

$onesignal->addNotification([
"included_segments" => ["Subscribed Users"], // TODO: allow user to customer user
"headings" => ["en" => "English Header"],
"contents" => ["en" => "English Message"],

// optional
"chrome_web_image" => "https://yoursite.com/4x3-with-min-width-1350-large-image",
"chrome_web_icon" => "https://yoursite.com/256x256-icon",
"chrome_web_badge" => "https://yoursite.com/72x72-badge",

// optional
"data" => ["nid" => $node->id(),],
]);
}

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

I'm thinking of working on this feature.

Some ideas:

  • Alter the content type edit form
  • Store the notification template in configuration to keep things simple for now.
  • Only send out the notification if the node is published.

Any feedback?

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

I agree with adding these URLs to default values (perhaps with a description sharing why).

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Same - while the field works for "instagram", it appears api.woxo.tech doesn't work for accounts that hasn't already been processed.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

No - it seems like you need these credentials to send out notifications.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Making this back to active due to provided use case.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Sorry - I use the patches for my composer.json file, hence why I uploaded it to Drupal.org (since GitLab, AFAIK, only offer's MR diffs and commit diffs).

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

I just came across this issue again today when I tried installing the default version of the module.

The current recommended release does not work at all due to this patch not being applied.

I suggest creating a new (full) release of the module using the alpha (2.1.1-alpha1)

(Especially, since there has also been 1,044 installs so far, as of Dec 9, 2023).

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

I just came across this issue again today.

You need to use the alpha release (e.g. `composer require 'drupal/simple_image_rotate:^2.1@alpha'`) because the current release is missing a critical patch:

See https://www.drupal.org/project/simple_image_rotate/issues/3203735 ๐Ÿ› Module Missing `Drupal\Core\Config\Entity\ThirdPartySettingsInterface` Fixed for more details.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

#9 also applied successfully for me for " 7.x-1.0-rc6".

+1 for RTBC.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

@Bushra Shaikh and @elber, could you add the commands you used to apply the patch?

Then, I can test both of them to ensure the patch works properly?

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Just updating this thread: release 8.4.0-beta4 has this patch applied.

composer require 'drupal/flag:^4.0@beta'
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

So the code in question is below.

The question is: why is _nodeaccess_get_grants($node) returning an empty array for some nodes?

I also tried resaving the Node Access page, but it didn't resolve the issue.

/**
 * Implements hook_node_access().
 */
function nodeaccess_node_access(NodeInterface $node, $op, $account) {
  $settings = \Drupal::configFactory()->get('nodeaccess.settings');
  $role_map = $settings->get('role_map');
  switch ($op) {
    case 'update':
    case 'delete':
      // If the node belongs to a deleted user.
      if ($account->id() == 0 && $node->getOwnerId() == 0) {
        // We check if the role has particular access to this node.
        $grants = _nodeaccess_get_grants($node);
        $anonymous_rid = $role_map[AccountInterface::ANONYMOUS_ROLE];
        // If anonymous has rights to this node, we allow them.
        if (($grants['rid'][$anonymous_rid]['grant_update'] && $op == 'update') ||
            ($grants['rid'][$anonymous_rid]['grant_delete'] && $op == 'delete')) {
          return AccessResult::Allowed();
        }
        return AccessResult::forbidden();
      }
      break;
  }
}
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

So, the issue is the with 1.x branch.

And it appears that many other pages also receive the error (on the public-facing side of the website) looking at Google:

https://www.google.com/search?q=Warning%3A+Undefined+array+key+%22rid%22...

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Note: these are the modules I have applied that requires #19.

    "require": {
        "drupal/crop": "^2.2",
        "drupal/exif_orientation": "^1.1",
        "drupal/filefield_sources": "^1.0@alpha",
        "drupal/filename_transliteration": "^1.1",
        "drupal/image_widget_crop": "^2.4",
        "drupal/simple_image_rotate": "^2.1.1",
        "drupal/webp": "^1.0@beta",
    },
    "extra": {
        "patches": {
            "enable-patching": true,
            "drupal/webp": {
                "#3186383: Fix image regeneration for duplicate filenames with different casing": "https://www.drupal.org/files/issues/2022-02-02/webp_access_denied-3186383-11.patch",
                "#3153137: Fix regenerate images after crop": "https://www.drupal.org/files/issues/2022-10-31/webp-support-image-crop-3153137-34.patch"
            },
            "drupal/image_widget_crop": {
                "#2910886: Update the save": "https://www.drupal.org/files/issues/2022-11-18/image_style_derivative-2910886-17.patch"
            }
        }
    },
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

I encountered an issue where the derivative would not generate until the cropping was applied twice.

E.g. only when the status message of The crop "@cropType" was successfully updated for image "@filename". was shown.

I then learned that the function(ImageWidgetCropManager::imageStylesOperations) doesn't apply to the code path on the first save.

After applying, the derivatives are now generated on the first save.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Note: this issue can be worked around using the filename_transliteration module.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

FYI: We used simple_image_rotate to combat this issue :)

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Technically it did in the database but not file system.

Drupal does not update the database when a file is deleted in the file system.

Thus, AFAIK, this is a user error.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Note: Drupal 10 uses the original route names:

node.add		/node/add/{node_type}
node.add_page		/node/add
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Just a note: this commit is added to the 2.0.0-beta1 release :)

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Okay, remove the two additional parameters by just duplicating the processing config approach:

  /**
   * Preprocesses the vocabulary taxonomy tree
   */
  protected function getVocabularyTreeArray($vocabulary_tree) {
    // TODO: How can we avoid this duplicated work?
    $vocabulary_config = $this->configuration['vocabulary'];
    $vocabulary_config = explode('|', $vocabulary_config);
    $vocabulary = isset($vocabulary_config[0]) ? $vocabulary_config[0] : NULL;
    $image_field = isset($vocabulary_config[1]) ? $vocabulary_config[1] : NULL;

    ...
  }
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

I don't like the additional two parameters: $image_field and $vocabulary.

Ideally, we create another method to process the config for us:

  /**
   * Get volcabulary name and image field
   */
  protected function getVocabularyConfig() {
    $vocabulary_config = $this->configuration['vocabulary'];
    $vocabulary_config_split = explode('|', $vocabulary_config);

    return [
      'vocabulary' => $vocabulary_config_split[0] ?? null,
      'image_field' => $vocabulary_config_split[1] ?? null,
    ]
  }

Or even better, we preprocess the form options when submitting to form, to create the additional keys: $this->configuration['vocabulary_name'] and $this->configuration['image_field'].

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

I created a new method to preprocess the result of TermStorage::loadTree (including removing the duplicates):

  /**
   * Preprocesses the vocabulary taxonomy tree
   */
  protected function getVocabularyTreeArray($vocabulary_tree, $image_field, $vocabulary) {
     ...
  }
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

When looking at <a href="https://api.drupal.org/api/drupal/core%21modules%21taxonomy%21src%21TermStorage.php/function/TermStorage%3A%3AloadTree/8.8.x">TermStorage::loadTree</a>, we see:

         if (isset($this->treeParents[$vid][$load_entities ? $term
            ->id() : $term->tid])) {

            // Clone the term so that the depth attribute remains correct
            // in the event of multiple parents.
            $term = clone $term;
          }

Therefore, we need to filter out duplicates.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Crossposting from https://www.drupal.org/project/feeds/issues/3337811#comment-15145862: ๐Ÿ› Argument #1 ($value) must be of type Countable|array, null given in FeedsProcessor->clean() Fixed

If looking for a work around so that feeds will unpublish missing nodes even when the response is empty...

Set your importer to include the published status.

Then use the following code to ensure there's always at least one node in your response.

...I did not realize that feeds do not import nodes when the response is empty or there are no items.

For future reference, I added the following code for my REST Export to ensure there is always at least one item in my response.

use Drupal\views\ViewExecutable;
use Drupal\views\ResultRow;
use Drupal\node\Entity\Node;

/**
 * Implements hook_views_post_execute().
 */
function HOOK_views_post_execute(ViewExecutable $view) {
  if ($view->id() == 'MY_VIEW_ID') {
    // Feeds does not import an empty response. Therefore, add a 
    // dummy feeds item
    if ($view->total_rows === 0) {
      $dummyNode = Node::create([
        'type' => 'job_posting',
        'nid'  => -1, // Our GUID. This is valid because we never save the node
        'title' => 'PLACEHOLDER NODE',
        'status' => 0, // Be unpublished, so it doesn't appear on the importing website
      ]);
      $view->result[] = new ResultRow([
        '_entity' => $dummyNode,
      ]);
    }
  }
}
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Oh wait, my issue was technically different. Removing the "related" issue.

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

@MegaChriz, thank you for pointing that out. I did not realize that feeds do not import nodes when the response is empty or there are no items.

For future reference, I added the following code for my REST Export to ensure there is always at least one item in my response.

use Drupal\views\ViewExecutable;
use Drupal\views\ResultRow;
use Drupal\node\Entity\Node;

/**
 * Implements hook_views_post_execute().
 */
function HOOK_views_post_execute(ViewExecutable $view) {
  if ($view->id() == 'MY_VIEW_ID') {
    // Feeds does not import an empty response. Therefore, add a 
    // dummy feeds item
    if ($view->total_rows === 0) {
      $dummyNode = Node::create([
        'type' => 'job_posting',
        'nid'  => -1, // This is valid because we never save the node
        'title' => 'PLACEHOLDER NODE',
        'status' => 0, // Be unpublished, so it doesn't appear on the website
      ]);
      $view->result[] = new ResultRow([
        '_entity' => $dummyNode,
      ]);
    }
  }
}
๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

Thank you for your contribution, @dineshkumarbollu!

Added some comments in an MR: could you review them?

https://git.drupalcode.org/project/send_emails/-/merge_requests/20

๐Ÿ‡จ๐Ÿ‡ฆCanada Nathan Tsai

An alternative workaround:

1. Require composer require mglaman/composer-drupal-lenient:^1.0

2. Patch the module

  "extra": {
      "patches": {
            "drupal/auto_login_url": {
                "#3303974: Support Drupal 10": "https://www.drupal.org/files/issues/2022-08-16/auto_login_url.2.x-dev.rector.patch"
            }
      }
  }

3. Allow drupal/auto_login_url to be installed even if the Drupal platform requirement is not met.

  "extra": {
        "drupal-lenient": {
            "allowed-list": [
                "drupal/token",
                "drupal/superfish",
                "drupal/redirect_anonymous_users",
                "drupal/body_scroll_lock",
                "drupal/auto_login_url"
            ]
        }
  }
<code>

4. Require <code>composer require drupal/auto_login_url
Production build 0.71.5 2024