Drupal StackExchange

Content edit links?

1 day 15 hours ago

I'm new to Drupal 8 and can't figure out a way to show the edit contextual links for content displayed through the Views module. This was simple in Drupal 7, but in Drupal 8, a view only shows the links for editing; there are no edit or quickedit links for the content.

It does seem to work with nodes and taxonomy terms, but not custom blocks.

iamfredrik

Using a session for anonymous users

1 day 16 hours ago

I set some session data for a user I auto logged out. Then tried to retrieve that session data in a form validation. It is not there.

class MFAController extends ControllerBase { public function sendOTP(int $uid, Request $request): RedirectResponse { if (empty($uid)) { \Drupal::logger('mfa')->error('Invalid request. The uid is missing.'); return $this->redirect('system.403'); } user_logout(); $user = User::load($uid); // reload the desired user for uid $passcode = Functions::passcode($user); $session = $request->getSession(); $session->set('mfa_otp', $passcode); $session->set('mfa_otp_time', time()); Functions::mailPasscode($user, $passcode); return $this->redirect('mfa.otp_form', ['uid' => $uid, 'resend' => 0]); } public function resendOTP(int $uid, Request $request): RedirectResponse { if (empty($uid)) { \Drupal::logger('mfa')->error('Invalid request. The uid is missing.'); return $this->redirect('system.403'); } $user = User::load($uid); // reload the desired user for uid $passcode = Functions::passcode($user); $session = $request->getSession(); $session->set('mfa_otp', $passcode); $session->set('mfa_otp_time', time()); Functions::mailPasscode($user, $passcode); return $this->redirect('mfa.otp_form', ['uid' => $uid, 'resend' => 1]); } }

The form validation is the following one.

public function validateForm(array &$form, FormStateInterface $form_state): void { $passcode = $form_state->getValue('passcode'); $session = $this->getRequest()->getSession(); $otp = (int) ($session->get('mfa_otp') ?: 0); $otp_time = (int) ($session->get('mfa_otp_time') ?: 0); if ($otp == 0 || $otp_time == 0) { $form_state->setErrorByName('passcode', 'Onetime passcode is missing in your session.'); $uid = $form_state->getValue('uid'); $user = User::load($uid); \Drupal::logger('mfa')->error('Onetime passcode is missing in ' . $user->getDisplayName() . "($uid)'s" . ' session.'); return; } if ($passcode != $otp) $form_state->setErrorByName('passcode', "Passcode is not valid."); if (time() - $otp_time > \Drupal::config('mfa.settings')->get('passcode_lifetime')) { $form_state->setErrorByName('passcode', "Passcode has expired. Please click the resend link below and generate a new passcode and try again."); } } }

resendOTP() in my controller works. It does the same thing except does not call user_logout() because the user is already logged out. It has access restricted to the anonymous role. So calling user_logout() is messing up the session and is probably not the same session accessed by the form validate function.

How do I fix this?

Donald Winston

Automatically trigger Acquia pipelines job when content is updated

1 day 17 hours ago

My team is fetching a large portion of our site's content at build time by using the i18n Gatsby plugin and downloading content from Drupal. The content we are fetching at build time rarely needs to be changed, but when it does, we now have to manually run an Acquia pipelines job and deploy the new artifact in order to display the updated content. This is inconvenient and time-consuming, especially since the content authors making these changes are typically not folks who have access to run a pipelines job or deploy a build.

Is there a straightforward way to automatically trigger a pipelines job when content is updated/added/deleted in Drupal? So far, the only solution my teammates and I have been able to think of is to use the Drupal Webhooks module to trigger a GitHub workflow, which would then do something like create a GitHub tag, which we could then configure to trigger a pipelines job. (We currently have our repo set up to start a pipelines job whenever a PR is opened in GitHub.)

Can we do this in a less roundabout way, for instance by using the Drupal Webhooks module to directly start a pipelines job in Acquia? From what we could tell, there isn't a way to do this, but it would be nice to avoid having to go through so many steps to set it up.

Also, is there a way to automatically deploy artifacts to a given environment? (I don't think we would want to do this in production, because it seems kind of risky, but might be nice to have it set up this way for one of our lower environments.)

Thank you in advance!

Amy

Minimum number of selections required

1 day 17 hours ago

Is it possible to require at least 5 out of 10 checkbox options to be selected in one web form field usung webform_validation module or built in custom properties?

I'm new to Drupal 10. In Drupal 7, I was using webform_validation and "Minimum number of selections required".

I could, but I don't want to use hooks nor custom functions.

Artur Śmigielski

Dynamic select lists in ajax configuration form [closed]

1 day 17 hours ago

I have a module in drupal 9 with a configuration form in the back office, I saw multiple answers on the web but none of them was optimized and compatible with drupal 9. In this form, the admin has to choose between two radio button options "Import" and "Export", and based on this choice, a select list called import_country_select or another completely different one called export_country_select, will be displayed. I will only put the code for the import_country_select case. Once import_country_select changes, the admin will choose two preferred cities which are two distinct select lists preferred_city_number_1 and preferred_city_number_2 listing different cities belonging to the previously selected country (I will only put the code for the "preferred_city_number_1").

1- Is my code correct or can it be optimized? I saw some posts stating that it's not recommended to return a form element in the ajax callback, it's better to return a response, but I didn't know what to write in my case.

2- My second concern is that I saw some examples where they do $form_state->setRebuild(TRUE); in the callback, why is that being used?

3- '#validated' => 'true', Is it correct to use to solve the "Illegal choice detected" error ?

4- In my method, I create the preferred_city_number_1 with an empty options array. Is there a way to add this form element on ajaxCallback instead of creating it first then only populating its options on callback?

5- And lastly, after some research I didn't quite understand whether or not we should use form_state inside the scope of buildForm.

/** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state): array { $config = $this->config('mymodule.settings'); $form['first_section'] = [ '#type' => 'details', '#title' => $this->t('Export/Import Settings'), '#weight' => 1, '#collapsible' => TRUE, ]; $form['first_section']['export_or_import'] = [ '#type' => 'radios', '#title' => $this->t('Do you want to use this module for export or import?'), '#options' => [ 'option_import' => $this->t('Import'), 'option_export' => $this->t('Export'), ], ]; $form['first_section']['import_country_select'] = [ '#type' => 'select', '#title' => $this->t('Choose a country:'), '#empty_option'=> $this->t('-Select-'), '#options' => [ 'country_1' => $this->t('France'), 'country_2' => $this->t('Belgium'), 'country_3' => $this->t('Canada'), ], '#states' => [ 'visible' => [ ':input[name="export_or_import"]' => ['value' => 'option_import'], ], ], '#ajax' => [ 'callback' => '::selectUpdateAjaxCallback', 'event' => 'change', 'wrapper' => 'replace-select-div', 'progress' => [ 'type' => 'throbber', 'message' => $this->t('Loading...'), ], ] ]; $form['first_section']['import_preferred_cities'] = [ '#type' => 'details', '#title' => $this->t('Preferred cities (Import)'), '#weight' => 1, '#collapsible' => TRUE, '#states' => [ 'visible' => [ ':input[name="export_or_import"]' => ['value' => 'option_import'], ], ], ]; $form['first_section']['import_preferred_cities']['preferred_city_number_1'] = [ '#type' => 'select', '#title' => $this->t('Select your preferred city:'), '#empty_option'=> $this->t('-Select-'), '#options' => [], '#states' => [ 'visible' => [ ':input[name="export_or_import"]' => ['value' => 'option_import'], ], ], '#prefix' => '<div id="replace-select-div">', '#suffix' => '</div>', '#validated' => 'true', ]; return parent::buildForm($form, $form_state); } public function selectUpdateAjaxCallback(array &$form, FormStateInterface $form_state) { $citiesByCountry = [ 'country_1' => ['Paris', 'Lyon'], 'country_2' => ['Brussels', 'Leuven'], 'country_3' => ['Toronto', 'Ottawa'], ]; $selectedOption = $form_state->getValue("import_country_select"); $form['first_section']['import_preferred_cities']['preferred_city_number_1']['#options'] = $citiesByCountry[$selectedOption]; return $form['first_section']['import_preferred_cities']['preferred_city_number_1']; }
de2

How can I create a dynamic page? [closed]

1 day 17 hours ago

I'm a Drupal beginner. I want to create a page to list the tours and add a section that can contain some filters (price, destination, traveler rating, and date).

What is the best solution for this? Should I create a view?

Mohamed Ouhammou

Restrict translation and editing of node to one language

1 day 17 hours ago
Edit

I found this in Workbench Access issue queue: https://www.drupal.org/project/workbench_access/issues/2982941#comment-12670744

It seems as if I need to deactivate the translate *bundle* *node* permissions, because if those are set, the permission will be short circuited and no other access restrictions may apply, and create a hole bunch of new *translate *bundle* *node* *language* permissions on my own. In my case we have 15 node types and 6 languages. That would result in 90 new permissions. That is overwhelming.

Original Question

I'm trying to restrict the access to creating and editing of nodes in the Drupal admin section to only one language for a user. I didn't find a module which provides for this feature. Is there any module that does this?

I then tried to create my own module. I came up with this solution

File: custom_i18n_access.module <?php use Drupal\node\NodeInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Access\AccessResult; /** * Implements hook_node_access(). * * Prevent editor role to edit and/or delete fr/en nodes. Quick and dirty. */ function custom_i18n_access_node_access(NodeInterface $node, $op, AccountInterface $account) { $roles = $account->getRoles(); if (in_array('administrator', $roles)) { return AccessResult::neutral(); } if ($op !== 'update' && $op !== 'delete') { return AccessResult::neutral(); } // Access should be restricted only if this permission is set if (!$account->hasPermission('custom_i18n_access_restrict')) { return AccessResult::neutral(); } $current_language = \Drupal::languageManager()->getCurrentLanguage(); $lang = $current_language->getId(); if ($account->hasPermission("custom_i18n_access_{$lang}_allow")) { return AccessResult::neutral(); } return AccessResult::forbidden(); } File: custom_i18n_access.permissions.yml permission_callbacks: - Drupal\custom_i18n_access\Permissions::permissions File: src/Permissions.php <?php namespace Drupal\custom_i18n_access; class Permissions { public function permissions() { $languages = \Drupal::languageManager()->getLanguages(); $permissions["custom_i18n_access_restrict"] = [ 'title' => t("Restrict language access"), 'description' => 'Restrict the edit access of nodes', ]; foreach($languages as $lang) { $permissions["custom_i18n_access_{$lang->getId()}_allow"] = [ 'title' => t("Allow to edit @lang content", ['@lang' => $lang->getName()]), ]; } return $permissions; } }

This custom module successfully restricts the editing and deleting of existing content to only the language I specified in the permissions. But it does not prevent new translations of the content into other languages.

As I see it, the HOOK_node_access hook is not called for every language when on the translations subtask page. How can I achieve this? Is there a different hook for that? I didn't find any help online.

yunzen

Making File Field description required

1 day 20 hours ago

My users always skip adding the "description" to the file field because they can. I tried implementing the code posted here:

How do I make Drupal File Description Field Required?

(and thank you) -- but I have a question. My users now do see a red asterisk suggesting that the description is required ... but if they do not enter a description, they may still click save and create the node ... with no description entered in the box. Any ideas on how to get this to really force the issue and require the description?

drupal curious