From ae8b0e85a535603ed5521f07717373bc0a12742a Mon Sep 17 00:00:00 2001 From: Brian Canini <canini.16@osu.edu> Date: Wed, 24 Jun 2020 15:15:21 -0400 Subject: [PATCH] Updating drupal/view_unpublished (1.0.0-alpha1 => 1.0.0-rc1) --- composer.json | 2 +- composer.lock | 30 +++-- vendor/composer/installed.json | 30 +++-- web/modules/view_unpublished/.gitignore | 1 + web/modules/view_unpublished/README.txt | 106 +++++++++++++++- web/modules/view_unpublished/composer.json | 12 ++ .../src/Plugin/views/filter/NodeStatus.php | 8 +- .../src/ViewUnpublishedPermissions.php | 18 +-- .../Functional/ViewUnpublishedViewsTest.php | 8 ++ .../view_unpublished.info.yml | 11 +- .../view_unpublished/view_unpublished.install | 32 ++++- .../view_unpublished/view_unpublished.module | 118 +++++++++++++----- .../view_unpublished.views.inc | 13 +- .../view_unpublished.views_execution.inc | 6 +- 14 files changed, 290 insertions(+), 105 deletions(-) create mode 100644 web/modules/view_unpublished/.gitignore create mode 100644 web/modules/view_unpublished/composer.json diff --git a/composer.json b/composer.json index 842a05dd72..b0568ae3e8 100644 --- a/composer.json +++ b/composer.json @@ -173,7 +173,7 @@ "drupal/twitter_block": "3.0-alpha0", "drupal/userprotect": "1.0", "drupal/video_embed_field": "2.4", - "drupal/view_unpublished": "1.0-alpha1", + "drupal/view_unpublished": "1.0-rc1", "drupal/views_accordion": "1.1", "drupal/views_ajax_history": "1.2", "drupal/views_autocomplete_filters": "1.2", diff --git a/composer.lock b/composer.lock index 7b79ac7290..e0a9cdec92 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c6ac3c19b434715dca4957f94d49879b", + "content-hash": "c8836da03bf0cd1b11a1441c44c690c3", "packages": [ { "name": "alchemy/zippy", @@ -7894,32 +7894,29 @@ }, { "name": "drupal/view_unpublished", - "version": "1.0.0-alpha1", + "version": "1.0.0-rc1", "source": { "type": "git", "url": "https://git.drupalcode.org/project/view_unpublished.git", - "reference": "8.x-1.0-alpha1" + "reference": "8.x-1.0-rc1" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/view_unpublished-8.x-1.0-alpha1.zip", - "reference": "8.x-1.0-alpha1", - "shasum": "6c5928295162027cd4da8f45aba6111d11e899f0" + "url": "https://ftp.drupal.org/files/projects/view_unpublished-8.x-1.0-rc1.zip", + "reference": "8.x-1.0-rc1", + "shasum": "de254b6e7863a5badf365fb953bd676b2b2d23a5" }, "require": { - "drupal/core": "*" + "drupal/core": "^8" }, "type": "drupal-module", "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - }, "drupal": { - "version": "8.x-1.0-alpha1", - "datestamp": "1483493344", + "version": "8.x-1.0-rc1", + "datestamp": "1592594405", "security-coverage": { "status": "not-covered", - "message": "Alpha releases are not covered by Drupal security advisories." + "message": "RC releases are not covered by Drupal security advisories." } } }, @@ -7929,8 +7926,9 @@ ], "authors": [ { - "name": "amaria", - "homepage": "https://www.drupal.org/user/66428" + "name": "Agnes Chisholm", + "homepage": "https://www.drupal.org/user/66428", + "email": "amaria@chisholmtech.com" }, { "name": "beeradb", @@ -7948,7 +7946,7 @@ "description": "Select which roles should be able to see unpublished nodes.", "homepage": "https://www.drupal.org/project/view_unpublished", "support": { - "source": "http://cgit.drupalcode.org/view_unpublished" + "source": "https://git.drupalcode.org/project/view_unpublished" } }, { diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 25a764ae45..31540560aa 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -8140,33 +8140,30 @@ }, { "name": "drupal/view_unpublished", - "version": "1.0.0-alpha1", - "version_normalized": "1.0.0.0-alpha1", + "version": "1.0.0-rc1", + "version_normalized": "1.0.0.0-RC1", "source": { "type": "git", "url": "https://git.drupalcode.org/project/view_unpublished.git", - "reference": "8.x-1.0-alpha1" + "reference": "8.x-1.0-rc1" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/view_unpublished-8.x-1.0-alpha1.zip", - "reference": "8.x-1.0-alpha1", - "shasum": "6c5928295162027cd4da8f45aba6111d11e899f0" + "url": "https://ftp.drupal.org/files/projects/view_unpublished-8.x-1.0-rc1.zip", + "reference": "8.x-1.0-rc1", + "shasum": "de254b6e7863a5badf365fb953bd676b2b2d23a5" }, "require": { - "drupal/core": "*" + "drupal/core": "^8" }, "type": "drupal-module", "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - }, "drupal": { - "version": "8.x-1.0-alpha1", - "datestamp": "1483493344", + "version": "8.x-1.0-rc1", + "datestamp": "1592594405", "security-coverage": { "status": "not-covered", - "message": "Alpha releases are not covered by Drupal security advisories." + "message": "RC releases are not covered by Drupal security advisories." } } }, @@ -8177,8 +8174,9 @@ ], "authors": [ { - "name": "amaria", - "homepage": "https://www.drupal.org/user/66428" + "name": "Agnes Chisholm", + "homepage": "https://www.drupal.org/user/66428", + "email": "amaria@chisholmtech.com" }, { "name": "beeradb", @@ -8196,7 +8194,7 @@ "description": "Select which roles should be able to see unpublished nodes.", "homepage": "https://www.drupal.org/project/view_unpublished", "support": { - "source": "http://cgit.drupalcode.org/view_unpublished" + "source": "https://git.drupalcode.org/project/view_unpublished" } }, { diff --git a/web/modules/view_unpublished/.gitignore b/web/modules/view_unpublished/.gitignore new file mode 100644 index 0000000000..57872d0f1e --- /dev/null +++ b/web/modules/view_unpublished/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/web/modules/view_unpublished/README.txt b/web/modules/view_unpublished/README.txt index de68897c9d..0d212c3354 100644 --- a/web/modules/view_unpublished/README.txt +++ b/web/modules/view_unpublished/README.txt @@ -3,15 +3,15 @@ View Unpublished This small module adds the missing permissions "view any unpublished content" and "view unpublished $content_type content" to Drupal 8. -This module also integrates with the core Content overview screen at /admin/content. -If you choose the "not published" filter, Drupal will show you unpublished -content you're allowed to see. +This module also integrates with the core Content overview screen at +/admin/content. If you choose the "not published" filter, Drupal will show you +unpublished content you're allowed to see. Using view_unpublished with Views --------------------------------- -Use the "Published status or admin user" filter, NOT "published = yes". Views will then -respect your custom permissions. Thanks to hanoii (6.x) and pcambra (7.x) for -this feature. +Use the "Published status or admin user" filter, NOT "published = yes". +Views will then respect your custom permissions. Thanks to hanoii (6.x) and +pcambra (7.x) for this feature. Common issues ------------- @@ -19,3 +19,97 @@ Common issues permissions: admin/reports/status/rebuild. Note that this can take significant time on larger installs and it is HIGHLY recommended that you back up your site first. +CONTENTS OF THIS FILE +--------------------- + + * Introduction + * Requirements + * Recommended Modules + * Installation + * Configuration + * Maintainers + + +INTRODUCTION +------------ + +The View Unpublished module allows the user to grant access for specific user +roles to view unpublished nodes of a specific type. Access control is quite +granular in this regard. + +Additionally, using this module does not require any modifications to the +existing URL structure. + + * For a full description of the module visit: + https://www.drupal.org/project/view_unpublished + + * To submit bug reports and feature suggestions, or to track changes visit: + https://www.drupal.org/project/issues/view_unpublished + + +REQUIREMENTS +------------ + +This module requires no modules outside of Drupal core. + + +RECOMMENDED MODULES +------------------- + +To give specific roles the ability to publish/unpublish certain node types +without giving those roles administrative access to all nodes. + + * Override node options - https://www.drupal.org/project/override_node_options + + +INSTALLATION +------------ + + * Install the View Unpublished module as you would normally install a + contributed Drupal module. Visit https://www.drupal.org/node/1897420 for + further information. + + +CONFIGURATION +------------- + + 1. Navigate to Administration > Extend and enable the module. + 2. Navigate to Administration > People > Permissions and assign the + appropriate permissions to the roles you wish to be able to view + unpublished nodes. + +This module also integrates with the core Content overview screen at +Administration > Content. If you choose the "not published" filter, Drupal will +show the user unpublished content they're allowed to see. + +Using View Unpublished with Views: +Use the "Published status or admin user" filter, NOT "published = yes". +Views will then respect the custom permissions. + +Common issues: +If for some reason this module seems to not work, try rebuilding the node +permissions: Administration > Reports > Status > Rebuild. Note that this +can take significant time on larger installs and it is HIGHLY recommended +that you back up the site first. + + +MAINTAINERS +----------- + + * Agnes Chisholm (amaria) - https://www.drupal.org/u/amaria + * Domenic Santangelo (entendu) - https://www.drupal.org/u/entendu + +Supporting organization: + + * Bright Bacon web services - http://brightbacon.com/ + +Additional credits: + + * Brad Bowman/beeradb - Aten Design Group + * Domenic Santangelo/dsantangelo - WorkHabit + +Additional credits: + + * Brad Bowman/beeradb - Aten Design Group + * Domenic Santangelo/dsantangelo - WorkHabit + (7.x) for this feature. diff --git a/web/modules/view_unpublished/composer.json b/web/modules/view_unpublished/composer.json new file mode 100644 index 0000000000..53d451f4f4 --- /dev/null +++ b/web/modules/view_unpublished/composer.json @@ -0,0 +1,12 @@ +{ + "name": "drupal/view_unpublished", + "description": "Select which roles should be able to see unpublished nodes.", + "license": "GPL-2.0-or-later", + "authors": [ + { + "name": "Agnes Chisholm", + "email": "amaria@chisholmtech.com" + } + ], + "require": {} +} diff --git a/web/modules/view_unpublished/src/Plugin/views/filter/NodeStatus.php b/web/modules/view_unpublished/src/Plugin/views/filter/NodeStatus.php index 6631235e45..d274b36557 100644 --- a/web/modules/view_unpublished/src/Plugin/views/filter/NodeStatus.php +++ b/web/modules/view_unpublished/src/Plugin/views/filter/NodeStatus.php @@ -7,7 +7,8 @@ use Drupal\views\Annotation\ViewsFilter; /** - * Filter by view all unpublished permissions granted by view_unpublished + * Filter by view all unpublished permissions granted by view_unpublished. + * * Takes over the Published or Admin filter query. * * @ingroup views_filter_handlers @@ -16,9 +17,12 @@ */ class NodeStatus extends Status { + /** + * {@inheritdoc} + */ public function query() { $table = $this->ensureMyTable(); - $where_per_type = array(); + $where_per_type = []; foreach (NodeType::loadMultiple() as $type) { $type_id = $type->id(); $where_per_type[] = "($table.type = '$type_id' AND ***VIEWUNPUBLISHED_TYPE_$type_id*** = 1)"; diff --git a/web/modules/view_unpublished/src/ViewUnpublishedPermissions.php b/web/modules/view_unpublished/src/ViewUnpublishedPermissions.php index 65a73fc6a4..de646f4daf 100644 --- a/web/modules/view_unpublished/src/ViewUnpublishedPermissions.php +++ b/web/modules/view_unpublished/src/ViewUnpublishedPermissions.php @@ -1,13 +1,12 @@ <?php - namespace Drupal\view_unpublished; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\node\Entity\NodeType; /** - * Provides dynamic permissions for viewing unpublished nodes of different types. + * Provides dynamic permissions for viewing unpublished nodes per type. */ class ViewUnpublishedPermissions { @@ -18,10 +17,11 @@ class ViewUnpublishedPermissions { * * @return array * The node type view unpublished permissions. - * @see \Drupal\user\PermissionHandlerInterface::getPermissions() + * + * @see \Drupal\user\PermissionHandlerInterface::getPermissions() */ public function permissions() { - $perms = array(); + $perms = []; // Generate view unpublished permissions for all node types. foreach (NodeType::loadMultiple() as $type) { $perms += $this->buildPermissions($type); @@ -41,13 +41,13 @@ public function permissions() { */ protected function buildPermissions(NodeType $type) { $type_id = $type->id(); - $type_params = array('%type_name' => $type->label()); + $type_params = ['%type_name' => $type->label()]; - return array( - "view any unpublished $type_id content" => array( + return [ + "view any unpublished $type_id content" => [ 'title' => $this->t('%type_name: View any unpublished content', $type_params), - ), - ); + ], + ]; } } diff --git a/web/modules/view_unpublished/tests/src/Functional/ViewUnpublishedViewsTest.php b/web/modules/view_unpublished/tests/src/Functional/ViewUnpublishedViewsTest.php index 7da5609a02..eca018600a 100644 --- a/web/modules/view_unpublished/tests/src/Functional/ViewUnpublishedViewsTest.php +++ b/web/modules/view_unpublished/tests/src/Functional/ViewUnpublishedViewsTest.php @@ -21,6 +21,14 @@ class ViewUnpublishedViewsTest extends BrowserTestBase { */ public static $modules = ['view_unpublished', 'node', 'views']; + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + + /** + * {@inheritdoc} + */ protected function setUp() { parent::setUp(); diff --git a/web/modules/view_unpublished/view_unpublished.info.yml b/web/modules/view_unpublished/view_unpublished.info.yml index fddaee2e6f..6b74ccef9f 100644 --- a/web/modules/view_unpublished/view_unpublished.info.yml +++ b/web/modules/view_unpublished/view_unpublished.info.yml @@ -1,13 +1,12 @@ name: 'View Unpublished' description: 'Select which roles should be able to see unpublished nodes.' package: Permissions -# core: 8.x +core: 8.x type: module dependencies: - - node + - drupal:node -# Information added by Drupal.org packaging script on 2017-01-04 -version: '8.x-1.0-alpha1' -core: '8.x' +# Information added by Drupal.org packaging script on 2020-06-19 +version: '8.x-1.0-rc1' project: 'view_unpublished' -datestamp: 1483493346 +datestamp: 1592594407 diff --git a/web/modules/view_unpublished/view_unpublished.install b/web/modules/view_unpublished/view_unpublished.install index 8534e7983e..9ea76351a5 100644 --- a/web/modules/view_unpublished/view_unpublished.install +++ b/web/modules/view_unpublished/view_unpublished.install @@ -1,19 +1,47 @@ <?php + /** - * @file view_unpublished.install + * @file * Contains install and update functions for view_unpublished. */ +use Drupal\Core\Url; + /** * Implements hook_install(). */ function view_unpublished_install() { - node_access_needs_rebuild(TRUE); + _view_unpublished_flag_rebuild_if_needed(); } /** * Implements hook_uninstall(). */ function view_unpublished_uninstall() { + _view_unpublished_flag_rebuild_if_needed(); +} + +/** + * Helper that flags node_access to be rebuilt if unpublished nodes exist. + */ +function _view_unpublished_flag_rebuild_if_needed() { + $query = \Drupal::entityTypeManager()->getStorage('node')->getQuery(); + $count_unpublished = $query->condition('status', FALSE)->count()->execute(); + if ($count_unpublished > 0) { + node_access_needs_rebuild(TRUE); + } +} + +/** + * Make a node access permissions rebuild needed to fix multilingual grants. + */ +function view_unpublished_update_8001() { + // We can't just rebuild all the permissions in the update batch because of + // https://www.drupal.org/node/2785155 and the ability to run updates using + // the update_free_access setting. node_access_needs_rebuild(TRUE); + return t( + 'A rebuild of node access permissions is necessary. Rebuilding may take some time if there is a lot of content or complex permission settings. After rebuilding has completed, content will automatically use the new permissions. <a href=":rebuild">Rebuild permissions</a>', + [':rebuild' => Url::fromRoute('node.configure_rebuild_confirm')->toString()] + ); } diff --git a/web/modules/view_unpublished/view_unpublished.module b/web/modules/view_unpublished/view_unpublished.module index fc6bb3bd5e..96ac07f88f 100644 --- a/web/modules/view_unpublished/view_unpublished.module +++ b/web/modules/view_unpublished/view_unpublished.module @@ -8,63 +8,113 @@ use Drupal\Core\Session\AccountInterface; use Drupal\node\Entity\NodeType; use Drupal\node\NodeInterface; +use Drupal\Core\Routing\RouteMatchInterface; /** * Implements hook_node_access_records(). */ function view_unpublished_node_access_records(NodeInterface $node) { - // We only care about the node if is unpublished. If not, it is - // treated just like any other node and we completely ignore it. - if ($node->isPublished() === FALSE) { - $grants = array(); - // Unpublished nodes should be viewable to all editors. - $grants[] = array( - 'realm' => 'view_unpublished_content', - 'gid' => 1, - 'grant_view' => 1, - 'grant_update' => 0, - 'grant_delete' => 0, - 'priority' => 0, - ); - $grants[] = array( - 'realm' => "view_unpublished_{$node->getType()}_content", - 'gid' => 1, - 'grant_view' => 1, - 'grant_update' => 0, - 'grant_delete' => 0, - 'priority' => 0, - ); - $grants[] = array( - 'realm' => 'view_unpublished_author', - 'gid' => $node->getOwnerId(), - 'grant_view' => 1, - 'grant_update' => 0, - 'grant_delete' => 0, - 'priority' => 0, - ); - return $grants; + $grants = []; + $access_content_grants = []; + foreach ($node->getTranslationLanguages(TRUE) as $langcode => $language) { + $translated_node = $node->getTranslation($langcode); + if ($translated_node->isPublished() === TRUE) { + $access_content_grants[] = [ + 'realm' => 'view_unpublished_published_content', + 'gid' => 1, + 'grant_view' => 1, + 'grant_update' => 0, + 'grant_delete' => 0, + 'langcode' => $langcode, + ]; + } + else { + // Unpublished nodes should be viewable to all editors. + $grants[] = [ + 'realm' => 'view_unpublished_content', + 'gid' => 1, + 'grant_view' => 1, + 'grant_update' => 0, + 'grant_delete' => 0, + 'priority' => 0, + 'langcode' => $langcode, + ]; + $grants[] = [ + 'realm' => "view_unpublished_{$node->getType()}_content", + 'gid' => 1, + 'grant_view' => 1, + 'grant_update' => 0, + 'grant_delete' => 0, + 'priority' => 0, + 'langcode' => $langcode, + ]; + $grants[] = [ + 'realm' => 'view_unpublished_author', + 'gid' => $node->getOwnerId(), + 'grant_view' => 1, + 'grant_update' => 0, + 'grant_delete' => 0, + 'priority' => 0, + 'langcode' => $langcode, + ]; + } } + + // Only use the $access_content_grants if we have to. + if (count($grants) > 0) { + $grants = array_merge($grants, $access_content_grants); + } + return $grants; } /** * Implements hook_node_grants(). */ function view_unpublished_node_grants(AccountInterface $account, $op) { - $grants = array(); + $grants = []; if ($op == 'view') { if ($account->hasPermission('view own unpublished content')) { - $grants['view_unpublished_author'] = array($account->id()); + $grants['view_unpublished_author'] = [$account->id()]; + } + if ($account->hasPermission('access content')) { + $grants['view_unpublished_published_content'] = [1]; } if ($account->hasPermission('view any unpublished content')) { - $grants['view_unpublished_content'] = array(1); + $grants['view_unpublished_content'] = [1]; return $grants; } foreach (NodeType::loadMultiple() as $type) { $type_id = $type->id(); if ($account->hasPermission("view any unpublished $type_id content")) { - $grants["view_unpublished_{$type_id}_content"] = array(1); + $grants["view_unpublished_{$type_id}_content"] = [1]; } } } return $grants; } + +/** + * @file + * Contains view_unpublished.module. + */ + +/** + * Implements hook_help(). + */ +function view_unpublished_help($route_name, RouteMatchInterface $arg) { + switch ($route_name) { + case 'help.page.view_unpublished': + $output = ''; + $output .= '<h3>' . t('About') . '</h3>'; + $output .= '<p>' . t('This module allows you to grant access for specific user roles to view unpublished nodes of a specific type. Access control is quite granular in this regard.') . '</p>'; + + // Add a link to the Drupal.org project. + $output .= '<p>'; + $output .= t('Visit the <a href=":project_link">View Unpublished project pages</a> on Drupal.org for more information.', [ + ':project_link' => 'https://www.drupal.org/project/view_unpublished', + ]); + $output .= '</p>'; + + return $output; + } +} diff --git a/web/modules/view_unpublished/view_unpublished.views.inc b/web/modules/view_unpublished/view_unpublished.views.inc index 8b6106ac1b..b8714d0719 100644 --- a/web/modules/view_unpublished/view_unpublished.views.inc +++ b/web/modules/view_unpublished/view_unpublished.views.inc @@ -6,16 +6,9 @@ */ /** - * Implements hook_views_data_alter() - * - * @param array $data - * An array of all information about Views tables and fields, collected from - * hook_views_data(), passed by reference. - * - * @see hook_views_data() - * @see hook_views_data_alter() + * Implements hook_views_data_alter(). */ function view_unpublished_views_data_alter(array &$data) { - // published status + extra handler is taken over by our handler + // The published status + extra handler is taken over by our handler. $data['node_field_data']['status_extra']['filter']['id'] = 'view_unpublished_node_status'; -} \ No newline at end of file +} diff --git a/web/modules/view_unpublished/view_unpublished.views_execution.inc b/web/modules/view_unpublished/view_unpublished.views_execution.inc index 8aee7340f6..0ee308ce32 100644 --- a/web/modules/view_unpublished/view_unpublished.views_execution.inc +++ b/web/modules/view_unpublished/view_unpublished.views_execution.inc @@ -9,11 +9,11 @@ use Drupal\views\ViewExecutable; /** -* Implements hook_views_query_substitutions(). -*/ + * Implements hook_views_query_substitutions(). + */ function view_unpublished_views_query_substitutions(ViewExecutable $view) { $account = \Drupal::currentUser(); - $substitutions = array(); + $substitutions = []; foreach (NodeType::loadMultiple() as $type) { $type_id = $type->id(); $substitutions["***VIEWUNPUBLISHED_TYPE_$type_id***"] = (int) $account->hasPermission('view any unpublished ' . $type_id . ' content'); -- GitLab