From 56c2afc39c74b3a842cb9f657be419fc3526b73e Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Wed, 6 Dec 2017 21:05:51 +0000 Subject: [PATCH 01/20] Add orphaned objects capability to core --- includes/orphaned_objects.inc | 268 ++++++++++++++++++++++++++++++++++ islandora.module | 9 +- 2 files changed, 276 insertions(+), 1 deletion(-) create mode 100644 includes/orphaned_objects.inc diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc new file mode 100644 index 00000000..e4bd0536 --- /dev/null +++ b/includes/orphaned_objects.inc @@ -0,0 +1,268 @@ + array( + 'title' => t('Manage orphaned objects'), + 'description' => t('View a list of orphaned objects.'), + ), + ); +} + +/** + * Builds the management form for the Orphaned Objects module. + * + * @param array $form + * An array representing a form within Drupal. + * @param array $form_state + * An array containing the Drupal form state. + * + * @return array + * An array containing the form to be rendered. + */ +function islandora_orphaned_objects_manage_form($form, $form_state) { + if (isset($form_state['show_confirm'])) { + $form['confirm_message'] = array( + '#type' => 'item', + '#markup' => format_plural(count($form_state['pids_to_delete']), + 'Are you sure you want to delete the 1 object?', + 'Are you sure you want to delete the @count objects?'), + ); + $form['confirm_submit'] = array( + '#type' => 'submit', + '#value' => t('Confirm'), + '#weight' => 2, + '#submit' => array('islandora_orphaned_objects_manage_confirm_submit'), + ); + $form['cancel_submit'] = array( + '#type' => 'submit', + '#value' => t('Cancel'), + '#weight' => 3, + ); + } + else { + $orphaned_objects = islandora_orphaned_objects_get_orphaned_objects(); + $rows = array(); + foreach ($orphaned_objects as $orphaned_object) { + $pid = $orphaned_object['object']['value']; + if (islandora_namespace_accessible($pid)) { + $rows[$pid] = array(l($orphaned_object['title']['value'] . " (" . $pid . ")", "islandora/object/$pid")); + } + } + ksort($rows); + $form['management_table'] = array( + '#type' => 'tableselect', + '#header' => array(t('Object')), + '#options' => $rows, + '#attributes' => array(), + '#empty' => t('No orphaned objects were found.'), + ); + if (!empty($rows)) { + $form['submit_selected'] = array( + '#type' => 'submit', + '#name' => 'islandora-orphaned-objects-submit-selected', + '#validate' => array('islandora_orphaned_objects_manage_delete_selected_validate'), + '#submit' => array('islandora_orphaned_objects_manage_delete_submit'), + '#value' => t('Delete Selected'), + ); + $form['submit_all'] = array( + '#type' => 'submit', + '#name' => 'islandora-orphaned-objects-submit-all', + '#submit' => array('islandora_orphaned_objects_manage_delete_submit'), + '#value' => t('Delete All'), + ); + } + } + return $form; +} +/** + * Validation for the Islandora Orphaned Objects management form. + * + * @param array $form + * An array representing a form within Drupal. + * @param array $form_state + * An array containing the Drupal form state. + */ +function islandora_orphaned_objects_manage_delete_selected_validate($form, $form_state) { + $selected = array_filter($form_state['values']['management_table']); + if (empty($selected)) { + form_error($form['management_table'], t('At least one object must be selected to delete!')); + } +} +/** + * Submit handler for the delete buttons in the workflow management form. + * + * @param array $form + * An array representing a form within Drupal. + * @param array $form_state + * An array containing the Drupal form state. + */ +function islandora_orphaned_objects_manage_delete_submit(&$form, &$form_state) { + if ($form_state['triggering_element']['#name'] == 'islandora-orphaned-objects-submit-selected') { + $selected = array_keys(array_filter($form_state['values']['management_table'])); + } + else { + $selected = array_keys($form_state['values']['management_table']); + } + $form_state['pids_to_delete'] = $selected; + // Rebuild to show the confirm form. + $form_state['rebuild'] = TRUE; + $form_state['show_confirm'] = TRUE; +} +/** + * Submit handler for the workflow management confirm form. + * + * @param array $form + * An array representing a form within Drupal. + * @param array $form_state + * An array containing the Drupal form state. + */ +function islandora_orphaned_objects_manage_confirm_submit($form, &$form_state) { + $batch = islandora_orphaned_objects_delete_create_batch($form_state['pids_to_delete']); + batch_set($batch); +} + +/** + * Query for orphaned objects. + * + * @return array + * An array containing the results of the orphaned objects queries. + */ +function islandora_orphaned_objects_get_orphaned_objects() { + $connection = islandora_get_tuque_connection(); + // First query: get standard objects. + $object_query = << ; + ?collection . + ?object ?title; + OPTIONAL { + ?collection ?model . + } + FILTER(!bound(?model)) +} +EOQ; + // Second query: get paged objects. + $paged_query = << ; + ?book . + ?object ?title; + OPTIONAL { + ?book ?model . + } + FILTER(!bound(?model)) + } +EOQ; + $optionals = (array) module_invoke('islandora_xacml_api', 'islandora_basic_collection_get_query_optionals', 'view'); + $filter_modules = array( + 'islandora_xacml_api', + 'islandora', + ); + $filters = array(); + foreach ($filter_modules as $module) { + $filters = array_merge_recursive($filters, (array) module_invoke($module, 'islandora_basic_collection_get_query_filters', 'view')); + } + $filter_map = function ($filter) { + return "FILTER($filter)"; + }; + // Use separate queries for different object types. + $sparql_query_objects = format_string($object_query, array( + '!optionals' => !empty($optionals) ? ('OPTIONAL {{' . implode('} UNION {', $optionals) . '}}') : '', + '!filters' => !empty($filters) ? implode(' ', array_map($filter_map, $filters)) : '', + )); + $sparql_query_paged = format_string($paged_query, array( + '!optionals' => !empty($optionals) ? ('OPTIONAL {{' . implode('} UNION {', $optionals) . '}}') : '', + '!filters' => !empty($filters) ? implode(' ', array_map($filter_map, $filters)) : '', + )); + $object_results = $connection->repository->ri->sparqlQuery($sparql_query_objects); + $paged_results = $connection->repository->ri->sparqlQuery($sparql_query_paged); + // Merge results of both queries into a single variable and return. + $results = array_merge($object_results, $paged_results); + return $results; +} + +/** + * Constructs the batch that will go out and delete objects. + * + * @param array $pids + * The array of pids to be deleted. + * + * @return array + * An array detailing the batch that is about to be run. + */ +function islandora_orphaned_objects_delete_create_batch($pids) { + // Set up a batch operation. + $batch = array( + 'operations' => array( + array('islandora_orphaned_objects_delete_batch_operation', array($pids)), + ), + 'title' => t('Deleting the selected objects...'), + 'init_message' => t('Preparing to delete objects.'), + 'progress_message' => t('Time elapsed: @elapsed
Estimated time remaining @estimate.'), + 'error_message' => t('An error has occurred.'), + 'finished' => 'islandora_orphaned_objects_delete_batch_finished', + 'file' => drupal_get_path('module', 'islandora_orphaned_objects') . '/includes/batch.inc', + ); + return $batch; +} +/** + * Constructs and performs the deleting batch operation. + * + * @param array $pids + * An array of pids to be deleted. + * @param array $context + * The context of the Drupal batch. + */ +function islandora_orphaned_objects_delete_batch_operation($pids, &$context) { + if (empty($context['sandbox'])) { + $context['sandbox'] = array(); + $context['sandbox']['progress'] = 0; + $context['sandbox']['pids'] = $pids; + $context['sandbox']['total'] = count($pids); + $context['results']['success'] = array(); + } + if (!empty($context['sandbox']['pids'])) { + $target_pid = array_pop($context['sandbox']['pids']); + $target_object = islandora_object_load($target_pid); + $context['message'] = t('Deleting @label (@pid) (@current of @total)...', array( + '@label' => $target_object->label, + '@pid' => $target_object->pid, + '@current' => $context['sandbox']['progress'], + '@total' => $context['sandbox']['total'], + )); + islandora_delete_object($target_object); + $context['results']['success'][] = $target_pid; + $context['sandbox']['progress']++; + } + $context['finished'] = ($context['sandbox']['total'] == 0) ? 1 : ($context['sandbox']['progress'] / $context['sandbox']['total']); +} +/** + * Finished function for the orphaned objects delete batch. + * + * @param bool $success + * Whether the batch was successful or not. + * @param array $results + * An array containing the results of the batch operations. + * @param array $operations + * The operations array that was used in the batch. + */ +function islandora_orphaned_objects_delete_batch_finished($success, $results, $operations) { + if ($success) { + $message = format_plural(count($results['success']), 'One object deleted.', '@count objects deleted.'); + } + else { + $message = t('Finished with an error.'); + } + drupal_set_message($message); +} diff --git a/islandora.module b/islandora.module index 0efc7cc4..4be85067 100644 --- a/islandora.module +++ b/islandora.module @@ -397,7 +397,14 @@ function islandora_menu() { 'type' => MENU_NORMAL_ITEM, 'access arguments' => array(ISLANDORA_MANAGE_DELETED_OBJECTS), ); - + $items['admin/reports/orphaned_objects/list'] = array( + 'title' => 'Orphaned objects', + 'description' => 'List of orphaned objects.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('islandora_orphaned_objects_manage_form'), + 'access arguments' => array('manage orphaned objects'), + 'file' => 'includes/orphaned_objects.inc', + ); $items['admin/islandora/restore/manage'] = array( 'description' => 'Restore or permanantly remove objects with Deleted status', 'title' => 'Manage Deleted Objects', From 2e17b7d98fce67ab2e48cfbdab1915636258779f Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Tue, 12 Dec 2017 14:44:51 +0000 Subject: [PATCH 02/20] Add Islandora to various descriptions and titles --- includes/orphaned_objects.inc | 4 ++-- islandora.module | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index e4bd0536..c2816215 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -11,8 +11,8 @@ function islandora_orphaned_objects_permission() { return array( 'manage orphaned objects' => array( - 'title' => t('Manage orphaned objects'), - 'description' => t('View a list of orphaned objects.'), + 'title' => t('Manage orphaned Islandora objects'), + 'description' => t('View a list of orphaned Islandora objects.'), ), ); } diff --git a/islandora.module b/islandora.module index 4be85067..89808a9e 100644 --- a/islandora.module +++ b/islandora.module @@ -398,8 +398,8 @@ function islandora_menu() { 'access arguments' => array(ISLANDORA_MANAGE_DELETED_OBJECTS), ); $items['admin/reports/orphaned_objects/list'] = array( - 'title' => 'Orphaned objects', - 'description' => 'List of orphaned objects.', + 'title' => 'Orphaned Islandora objects', + 'description' => 'List of orphaned Islandora objects.', 'page callback' => 'drupal_get_form', 'page arguments' => array('islandora_orphaned_objects_manage_form'), 'access arguments' => array('manage orphaned objects'), From 962782c5f615648919b8c9370d812ef3fe4a67e1 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Wed, 17 Jan 2018 20:10:20 +0000 Subject: [PATCH 03/20] Simplify and make a single query --- includes/orphaned_objects.inc | 37 +++++++++-------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index c2816215..8e598911 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -140,29 +140,17 @@ function islandora_orphaned_objects_get_orphaned_objects() { $connection = islandora_get_tuque_connection(); // First query: get standard objects. $object_query = << ; - ?collection . - ?object ?title; - OPTIONAL { - ?collection ?model . - } - FILTER(!bound(?model)) -} -EOQ; - // Second query: get paged objects. - $paged_query = << ; - ?book . - ?object ?title; - OPTIONAL { - ?book ?model . - } + ?p ?otherobject . + ?object ?title; + FILTER( regex( str(?p), "/fedora-system:def/relations-external#")) + OPTIONAL { + ?otherobject ?model . + } FILTER(!bound(?model)) - } +} EOQ; $optionals = (array) module_invoke('islandora_xacml_api', 'islandora_basic_collection_get_query_optionals', 'view'); $filter_modules = array( @@ -181,14 +169,7 @@ EOQ; '!optionals' => !empty($optionals) ? ('OPTIONAL {{' . implode('} UNION {', $optionals) . '}}') : '', '!filters' => !empty($filters) ? implode(' ', array_map($filter_map, $filters)) : '', )); - $sparql_query_paged = format_string($paged_query, array( - '!optionals' => !empty($optionals) ? ('OPTIONAL {{' . implode('} UNION {', $optionals) . '}}') : '', - '!filters' => !empty($filters) ? implode(' ', array_map($filter_map, $filters)) : '', - )); - $object_results = $connection->repository->ri->sparqlQuery($sparql_query_objects); - $paged_results = $connection->repository->ri->sparqlQuery($sparql_query_paged); - // Merge results of both queries into a single variable and return. - $results = array_merge($object_results, $paged_results); + $results = $connection->repository->ri->sparqlQuery($sparql_query_objects); return $results; } From bb19d996171944ba6fb6c7616aeab25cf648d8a3 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Mon, 26 Feb 2018 15:31:17 +0000 Subject: [PATCH 04/20] Amend SPARQL query to exclude objects with any living parent. --- includes/orphaned_objects.inc | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index 8e598911..c4140170 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -138,20 +138,33 @@ function islandora_orphaned_objects_manage_confirm_submit($form, &$form_state) { */ function islandora_orphaned_objects_get_orphaned_objects() { $connection = islandora_get_tuque_connection(); - // First query: get standard objects. + // SPARQL: get orphaned objects, exclude any with a living parent. $object_query = << +SELECT ?object ?p ?otherobject ?title WHERE { ?object ; ?p ?otherobject . ?object ?title; - FILTER( regex( str(?p), "/fedora-system:def/relations-external#")) - OPTIONAL { - ?otherobject ?model . - } - FILTER(!bound(?model)) + OPTIONAL { + ?otherobject ?model . + } . + FILTER (!bound(?model)) + + # Filter by "parent" relationships - isMemberOf, isMemberOfCollection, isPageOf. + FILTER (?p = || ?p = || ?p = ) + +# Exclude objects with live parents - isMemberOf, isMemberOfCollection, isPageOf. + OPTIONAL { + {?object ?liveparent } + UNION {?object ?liveparent } + UNION { ?object ?liveparent } . + ?liveparent . + } + FILTER (!bound(?liveparent)) } EOQ; + $optionals = (array) module_invoke('islandora_xacml_api', 'islandora_basic_collection_get_query_optionals', 'view'); $filter_modules = array( 'islandora_xacml_api', From 3a25a1fa5e8f3035d4aec7206b46c5385458852d Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Mon, 26 Feb 2018 18:16:01 +0000 Subject: [PATCH 05/20] Make permissions work --- includes/orphaned_objects.inc | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index c4140170..545fafc1 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -5,18 +5,6 @@ * A list of orphaned Islandora objects. */ -/** - * Implements hook_permission(). - */ -function islandora_orphaned_objects_permission() { - return array( - 'manage orphaned objects' => array( - 'title' => t('Manage orphaned Islandora objects'), - 'description' => t('View a list of orphaned Islandora objects.'), - ), - ); -} - /** * Builds the management form for the Orphaned Objects module. * From 5894477687a4cc684e315558ca9d6f4e8b3b4362 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Mon, 26 Feb 2018 18:48:05 +0000 Subject: [PATCH 06/20] XACML OK --- includes/orphaned_objects.inc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index 545fafc1..9eb7b806 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -149,8 +149,10 @@ WHERE { UNION { ?object ?liveparent } . ?liveparent . } + !optionals + !filters FILTER (!bound(?liveparent)) -} +} ORDER BY ?object EOQ; $optionals = (array) module_invoke('islandora_xacml_api', 'islandora_basic_collection_get_query_optionals', 'view'); From 92a9096f1250735ebfe6f7c088d367b8aa88acf2 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Mon, 26 Feb 2018 19:01:23 +0000 Subject: [PATCH 07/20] Permissions --- islandora.module | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/islandora.module b/islandora.module index 89808a9e..0cde906e 100644 --- a/islandora.module +++ b/islandora.module @@ -631,6 +631,10 @@ function islandora_permission() { 'title' => t('Replace datastreams'), 'description' => t('Add new datastream content as latest version.'), ), + 'manage orphaned objects' => array( + 'title' => t('Manage orphaned Islandora objects'), + 'description' => t('View a list of orphaned Islandora objects.'), + ), ); if (variable_get('islandora_deny_inactive_and_deleted', FALSE)) { $permissions[ISLANDORA_ACCESS_INACTIVE_AND_DELETED_OBJECTS] = array( From ecca2654e58bceaf4d8d3057dab30222ee6368e8 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Mon, 26 Feb 2018 20:05:51 +0000 Subject: [PATCH 08/20] Change query to SELECT DISTINCT, remove ?p ?otherobject --- includes/orphaned_objects.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index 9eb7b806..8f61a8a1 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -129,7 +129,7 @@ function islandora_orphaned_objects_get_orphaned_objects() { // SPARQL: get orphaned objects, exclude any with a living parent. $object_query = << -SELECT ?object ?p ?otherobject ?title +SELECT DISTINCT ?object ?title WHERE { ?object ; ?p ?otherobject . From bc2918c86365861e1172c3b8b7dfbc1456ea8926 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Tue, 27 Feb 2018 14:27:29 +0000 Subject: [PATCH 09/20] Function names and delete path --- includes/orphaned_objects.inc | 8 ++++---- islandora.module | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index 8f61a8a1..e4a861cd 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -6,7 +6,7 @@ */ /** - * Builds the management form for the Orphaned Objects module. + * Builds the Orphaned Islandora Objects management form. * * @param array $form * An array representing a form within Drupal. @@ -37,7 +37,7 @@ function islandora_orphaned_objects_manage_form($form, $form_state) { ); } else { - $orphaned_objects = islandora_orphaned_objects_get_orphaned_objects(); + $orphaned_objects = islandora_get_orphaned_objects(); $rows = array(); foreach ($orphaned_objects as $orphaned_object) { $pid = $orphaned_object['object']['value']; @@ -124,7 +124,7 @@ function islandora_orphaned_objects_manage_confirm_submit($form, &$form_state) { * @return array * An array containing the results of the orphaned objects queries. */ -function islandora_orphaned_objects_get_orphaned_objects() { +function islandora_get_orphaned_objects() { $connection = islandora_get_tuque_connection(); // SPARQL: get orphaned objects, exclude any with a living parent. $object_query = << t('Time elapsed: @elapsed
Estimated time remaining @estimate.'), 'error_message' => t('An error has occurred.'), 'finished' => 'islandora_orphaned_objects_delete_batch_finished', - 'file' => drupal_get_path('module', 'islandora_orphaned_objects') . '/includes/batch.inc', + 'file' => drupal_get_path('module', 'islandora') . '/includes/orphaned_objects.inc', ); return $batch; } diff --git a/islandora.module b/islandora.module index 0cde906e..ee2cc6b2 100644 --- a/islandora.module +++ b/islandora.module @@ -402,7 +402,7 @@ function islandora_menu() { 'description' => 'List of orphaned Islandora objects.', 'page callback' => 'drupal_get_form', 'page arguments' => array('islandora_orphaned_objects_manage_form'), - 'access arguments' => array('manage orphaned objects'), + 'access arguments' => array('ISLANDORA_MANAGE_ORPHANED_OBJECTS'), 'file' => 'includes/orphaned_objects.inc', ); $items['admin/islandora/restore/manage'] = array( @@ -631,7 +631,7 @@ function islandora_permission() { 'title' => t('Replace datastreams'), 'description' => t('Add new datastream content as latest version.'), ), - 'manage orphaned objects' => array( + 'ISLANDORA_MANAGE_ORPHANED_OBJECTS' => array( 'title' => t('Manage orphaned Islandora objects'), 'description' => t('View a list of orphaned Islandora objects.'), ), From 7b5a601128e297b24964ee5587f13dedbc6791b8 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Tue, 27 Feb 2018 15:04:06 +0000 Subject: [PATCH 10/20] Show list of objects to confirmation page --- includes/orphaned_objects.inc | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index e4a861cd..6ac54115 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -18,11 +18,23 @@ */ function islandora_orphaned_objects_manage_form($form, $form_state) { if (isset($form_state['show_confirm'])) { + $pids = $form_state['pids_to_delete']; + if (count($form_state['pids_to_delete']) == 1) { + $pid_paths = '' . $pids[0] . ''; + } + elseif (count($form_state['pids_to_delete']) <= 10) { + $pid_paths = '
    '; + foreach($pids as $pid) { + $pid_paths = $pid_paths . '
  • ' . $pid . '
  • '; + $pid_links[] = '' . $pid . ''; + } + $pid_paths = $pid_paths . '
'; + } $form['confirm_message'] = array( '#type' => 'item', '#markup' => format_plural(count($form_state['pids_to_delete']), - 'Are you sure you want to delete the 1 object?', - 'Are you sure you want to delete the @count objects?'), + 'Are you sure you want to delete the object ' . $pid_paths . '? This action cannot be reversed.', + 'Are you sure you want to delete these @count objects? This action cannot be reversed.' . $pid_paths), ); $form['confirm_submit'] = array( '#type' => 'submit', From 34ff60a0a8880faa0c756e2b712d71f51d7cb0ee Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Tue, 27 Feb 2018 15:11:13 +0000 Subject: [PATCH 11/20] Add warning to report page --- includes/orphaned_objects.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index 6ac54115..829b4811 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -49,6 +49,8 @@ function islandora_orphaned_objects_manage_form($form, $form_state) { ); } else { + drupal_set_message(t('Some objects may intentionally have no parents. If deleting objects, please be + absolutely sure that these objects are no longer required.'), 'warning'); $orphaned_objects = islandora_get_orphaned_objects(); $rows = array(); foreach ($orphaned_objects as $orphaned_object) { From 31a5e877389f5c921fce6d1c1ef7d933738dc3f1 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Tue, 27 Feb 2018 15:33:48 +0000 Subject: [PATCH 12/20] Rename functions and define permissions constant --- includes/orphaned_objects.inc | 28 ++++++++++++++-------------- islandora.module | 3 ++- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index 829b4811..f7100acf 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -16,7 +16,7 @@ * @return array * An array containing the form to be rendered. */ -function islandora_orphaned_objects_manage_form($form, $form_state) { +function islandora_manage_orphaned_objects_form($form, $form_state) { if (isset($form_state['show_confirm'])) { $pids = $form_state['pids_to_delete']; if (count($form_state['pids_to_delete']) == 1) { @@ -40,7 +40,7 @@ function islandora_orphaned_objects_manage_form($form, $form_state) { '#type' => 'submit', '#value' => t('Confirm'), '#weight' => 2, - '#submit' => array('islandora_orphaned_objects_manage_confirm_submit'), + '#submit' => array('islandora_manage_orphaned_objects_confirm_submit'), ); $form['cancel_submit'] = array( '#type' => 'submit', @@ -71,14 +71,14 @@ function islandora_orphaned_objects_manage_form($form, $form_state) { $form['submit_selected'] = array( '#type' => 'submit', '#name' => 'islandora-orphaned-objects-submit-selected', - '#validate' => array('islandora_orphaned_objects_manage_delete_selected_validate'), - '#submit' => array('islandora_orphaned_objects_manage_delete_submit'), + '#validate' => array('islandora_delete_selected_orphaned_objects_validate'), + '#submit' => array('islandora_delete_orphaned_objects_submit'), '#value' => t('Delete Selected'), ); $form['submit_all'] = array( '#type' => 'submit', '#name' => 'islandora-orphaned-objects-submit-all', - '#submit' => array('islandora_orphaned_objects_manage_delete_submit'), + '#submit' => array('islandora_delete_orphaned_objects_submit'), '#value' => t('Delete All'), ); } @@ -93,7 +93,7 @@ function islandora_orphaned_objects_manage_form($form, $form_state) { * @param array $form_state * An array containing the Drupal form state. */ -function islandora_orphaned_objects_manage_delete_selected_validate($form, $form_state) { +function islandora_delete_selected_orphaned_objects_validate($form, $form_state) { $selected = array_filter($form_state['values']['management_table']); if (empty($selected)) { form_error($form['management_table'], t('At least one object must be selected to delete!')); @@ -107,7 +107,7 @@ function islandora_orphaned_objects_manage_delete_selected_validate($form, $form * @param array $form_state * An array containing the Drupal form state. */ -function islandora_orphaned_objects_manage_delete_submit(&$form, &$form_state) { +function islandora_delete_orphaned_objects_submit(&$form, &$form_state) { if ($form_state['triggering_element']['#name'] == 'islandora-orphaned-objects-submit-selected') { $selected = array_keys(array_filter($form_state['values']['management_table'])); } @@ -127,8 +127,8 @@ function islandora_orphaned_objects_manage_delete_submit(&$form, &$form_state) { * @param array $form_state * An array containing the Drupal form state. */ -function islandora_orphaned_objects_manage_confirm_submit($form, &$form_state) { - $batch = islandora_orphaned_objects_delete_create_batch($form_state['pids_to_delete']); +function islandora_manage_orphaned_objects_confirm_submit($form, &$form_state) { + $batch = islandora_delete_orphaned_objects_create_batch($form_state['pids_to_delete']); batch_set($batch); } @@ -199,17 +199,17 @@ EOQ; * @return array * An array detailing the batch that is about to be run. */ -function islandora_orphaned_objects_delete_create_batch($pids) { +function islandora_delete_orphaned_objects_create_batch($pids) { // Set up a batch operation. $batch = array( 'operations' => array( - array('islandora_orphaned_objects_delete_batch_operation', array($pids)), + array('islandora_delete_orphaned_objects_batch_operation', array($pids)), ), 'title' => t('Deleting the selected objects...'), 'init_message' => t('Preparing to delete objects.'), 'progress_message' => t('Time elapsed: @elapsed
Estimated time remaining @estimate.'), 'error_message' => t('An error has occurred.'), - 'finished' => 'islandora_orphaned_objects_delete_batch_finished', + 'finished' => 'islandora_delete_orphaned_objects_batch_finished', 'file' => drupal_get_path('module', 'islandora') . '/includes/orphaned_objects.inc', ); return $batch; @@ -222,7 +222,7 @@ function islandora_orphaned_objects_delete_create_batch($pids) { * @param array $context * The context of the Drupal batch. */ -function islandora_orphaned_objects_delete_batch_operation($pids, &$context) { +function islandora_delete_orphaned_objects_batch_operation($pids, &$context) { if (empty($context['sandbox'])) { $context['sandbox'] = array(); $context['sandbox']['progress'] = 0; @@ -255,7 +255,7 @@ function islandora_orphaned_objects_delete_batch_operation($pids, &$context) { * @param array $operations * The operations array that was used in the batch. */ -function islandora_orphaned_objects_delete_batch_finished($success, $results, $operations) { +function islandora_delete_orphaned_objects_batch_finished($success, $results, $operations) { if ($success) { $message = format_plural(count($results['success']), 'One object deleted.', '@count objects deleted.'); } diff --git a/islandora.module b/islandora.module index ee2cc6b2..38d4c4d4 100644 --- a/islandora.module +++ b/islandora.module @@ -39,6 +39,7 @@ define('ISLANDORA_MANAGE_DELETED_OBJECTS', 'manage deleted objects'); define('ISLANDORA_REVERT_DATASTREAM', 'revert to old datastream'); define('ISLANDORA_REGENERATE_DERIVATIVES', 'regenerate derivatives for an object'); define('ISLANDORA_REPLACE_DATASTREAM_CONTENT', 'replace a datastream with new content, preserving version history'); +define('ISLANDORA_MANAGE_ORPHANED_OBJECTS', 'view and delete a list of orphaned objects'); // Hooks. define('ISLANDORA_VIEW_HOOK', 'islandora_view_object'); @@ -401,7 +402,7 @@ function islandora_menu() { 'title' => 'Orphaned Islandora objects', 'description' => 'List of orphaned Islandora objects.', 'page callback' => 'drupal_get_form', - 'page arguments' => array('islandora_orphaned_objects_manage_form'), + 'page arguments' => array('islandora_manage_orphaned_objects_form'), 'access arguments' => array('ISLANDORA_MANAGE_ORPHANED_OBJECTS'), 'file' => 'includes/orphaned_objects.inc', ); From 5ecc9aab0aca7c0ade982d69ea93ebed7fda619e Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Tue, 27 Feb 2018 15:37:31 +0000 Subject: [PATCH 13/20] Remove quotes from permissions --- islandora.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/islandora.module b/islandora.module index 38d4c4d4..dee7ce79 100644 --- a/islandora.module +++ b/islandora.module @@ -632,7 +632,7 @@ function islandora_permission() { 'title' => t('Replace datastreams'), 'description' => t('Add new datastream content as latest version.'), ), - 'ISLANDORA_MANAGE_ORPHANED_OBJECTS' => array( + ISLANDORA_MANAGE_ORPHANED_OBJECTS => array( 'title' => t('Manage orphaned Islandora objects'), 'description' => t('View a list of orphaned Islandora objects.'), ), From f62b91e121738666c25d66a38270cfb625f217a8 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Tue, 27 Feb 2018 15:55:46 +0000 Subject: [PATCH 14/20] Coding standards --- includes/orphaned_objects.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index f7100acf..fe6b62e3 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -21,10 +21,10 @@ function islandora_manage_orphaned_objects_form($form, $form_state) { $pids = $form_state['pids_to_delete']; if (count($form_state['pids_to_delete']) == 1) { $pid_paths = '' . $pids[0] . ''; - } - elseif (count($form_state['pids_to_delete']) <= 10) { + } + elseif (count($form_state['pids_to_delete']) <= 10) { $pid_paths = '
    '; - foreach($pids as $pid) { + foreach ($pids as $pid) { $pid_paths = $pid_paths . '
  • ' . $pid . '
  • '; $pid_links[] = '' . $pid . ''; } From 898c5534f6343b7ed36b26a29559f3e1ba7a0ef4 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Tue, 27 Feb 2018 16:05:48 +0000 Subject: [PATCH 15/20] Coding standards, and remove unneeded variable. --- includes/orphaned_objects.inc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index fe6b62e3..460fc3c0 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -19,22 +19,18 @@ function islandora_manage_orphaned_objects_form($form, $form_state) { if (isset($form_state['show_confirm'])) { $pids = $form_state['pids_to_delete']; - if (count($form_state['pids_to_delete']) == 1) { - $pid_paths = '' . $pids[0] . ''; - } - elseif (count($form_state['pids_to_delete']) <= 10) { + if (count($form_state['pids_to_delete']) <= 10) { $pid_paths = '
      '; foreach ($pids as $pid) { $pid_paths = $pid_paths . '
    • ' . $pid . '
    • '; - $pid_links[] = '' . $pid . ''; } $pid_paths = $pid_paths . '
    '; } $form['confirm_message'] = array( '#type' => 'item', '#markup' => format_plural(count($form_state['pids_to_delete']), - 'Are you sure you want to delete the object ' . $pid_paths . '? This action cannot be reversed.', - 'Are you sure you want to delete these @count objects? This action cannot be reversed.' . $pid_paths), + 'Are you sure you want to delete this object? This action cannot be reversed.', + 'Are you sure you want to delete these @count objects? This action cannot be reversed.') . $pid_paths, ); $form['confirm_submit'] = array( '#type' => 'submit', From d443a7c3e88c3ae5c2b6f8eaec2ff088a15a1ec7 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Mon, 5 Mar 2018 18:28:52 +0000 Subject: [PATCH 16/20] Turn list of pids_to_delete into an array, and correct warning text --- includes/orphaned_objects.inc | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index 460fc3c0..f651f4f2 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -20,18 +20,28 @@ function islandora_manage_orphaned_objects_form($form, $form_state) { if (isset($form_state['show_confirm'])) { $pids = $form_state['pids_to_delete']; if (count($form_state['pids_to_delete']) <= 10) { - $pid_paths = '
      '; + $pid_paths = array(); foreach ($pids as $pid) { - $pid_paths = $pid_paths . '
    • ' . $pid . '
    • '; + $pid_paths[] = l($pid, '/islandora/object/' . $pid); } - $pid_paths = $pid_paths . '
    '; } $form['confirm_message'] = array( '#type' => 'item', '#markup' => format_plural(count($form_state['pids_to_delete']), 'Are you sure you want to delete this object? This action cannot be reversed.', - 'Are you sure you want to delete these @count objects? This action cannot be reversed.') . $pid_paths, + 'Are you sure you want to delete these @count objects? This action cannot be reversed.'), ); + if (count($pids) <= 10) { + $form['pids_to_delete'] = array( + '#type' => 'markup', + '#theme' => 'item_list', + '#list_type' => 'ol', + ); + $options = array('attributes' => array('target' => '_blank')); + foreach ($pids as $pid) { + $form['pids_to_delete']['#items'][] = l($pid, "/islandora/object/{$pid}", $options); + } + } $form['confirm_submit'] = array( '#type' => 'submit', '#value' => t('Confirm'), @@ -45,8 +55,10 @@ function islandora_manage_orphaned_objects_form($form, $form_state) { ); } else { - drupal_set_message(t('Some objects may intentionally have no parents. If deleting objects, please be - absolutely sure that these objects are no longer required.'), 'warning'); + drupal_set_message(t('This page lists objects that have at least one parent, according to their RELS-EXT, that does not + exist in the Fedora repository. These orphans might exist due to a failed batch ingest, their parents being deleted, + or a variety of other reasons. Some of these orphans may exist intentionally. + Please be cautious when deleting, as this action is irreversible.'), 'warning'); $orphaned_objects = islandora_get_orphaned_objects(); $rows = array(); foreach ($orphaned_objects as $orphaned_object) { @@ -81,6 +93,7 @@ function islandora_manage_orphaned_objects_form($form, $form_state) { } return $form; } + /** * Validation for the Islandora Orphaned Objects management form. * From 3c2cc26ab75d0179a05b6f52715be50bf2f9e2ed Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Mon, 5 Mar 2018 18:31:41 +0000 Subject: [PATCH 17/20] Remove unnecessary code --- includes/orphaned_objects.inc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index f651f4f2..40964f8b 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -19,12 +19,6 @@ function islandora_manage_orphaned_objects_form($form, $form_state) { if (isset($form_state['show_confirm'])) { $pids = $form_state['pids_to_delete']; - if (count($form_state['pids_to_delete']) <= 10) { - $pid_paths = array(); - foreach ($pids as $pid) { - $pid_paths[] = l($pid, '/islandora/object/' . $pid); - } - } $form['confirm_message'] = array( '#type' => 'item', '#markup' => format_plural(count($form_state['pids_to_delete']), From f299fb7486d662d3957bef1ddd9f63e3f00efc1d Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Wed, 7 Mar 2018 14:02:19 +0000 Subject: [PATCH 18/20] Remove quotes from access arguments --- islandora.module | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/islandora.module b/islandora.module index dee7ce79..b5959db6 100644 --- a/islandora.module +++ b/islandora.module @@ -403,7 +403,7 @@ function islandora_menu() { 'description' => 'List of orphaned Islandora objects.', 'page callback' => 'drupal_get_form', 'page arguments' => array('islandora_manage_orphaned_objects_form'), - 'access arguments' => array('ISLANDORA_MANAGE_ORPHANED_OBJECTS'), + 'access arguments' => array(ISLANDORA_MANAGE_ORPHANED_OBJECTS), 'file' => 'includes/orphaned_objects.inc', ); $items['admin/islandora/restore/manage'] = array( From deca1766cc30af3b3689013dfc80f1274cf4b547 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Mon, 12 Mar 2018 19:08:00 +0000 Subject: [PATCH 19/20] Fix pid undefined constant --- includes/orphaned_objects.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index 40964f8b..1e063ffb 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -238,7 +238,7 @@ function islandora_delete_orphaned_objects_batch_operation($pids, &$context) { $target_object = islandora_object_load($target_pid); $context['message'] = t('Deleting @label (@pid) (@current of @total)...', array( '@label' => $target_object->label, - '@pid' => $target_object->pid, + '@pid' => $target_pid, '@current' => $context['sandbox']['progress'], '@total' => $context['sandbox']['total'], )); From 482c9e6999e1eabf0e01d67cbf59305089d9bc21 Mon Sep 17 00:00:00 2001 From: Brandon Weigel Date: Tue, 20 Mar 2018 18:45:11 +0000 Subject: [PATCH 20/20] Add error message for delete failure --- includes/orphaned_objects.inc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/includes/orphaned_objects.inc b/includes/orphaned_objects.inc index 1e063ffb..502177f9 100644 --- a/includes/orphaned_objects.inc +++ b/includes/orphaned_objects.inc @@ -243,7 +243,13 @@ function islandora_delete_orphaned_objects_batch_operation($pids, &$context) { '@total' => $context['sandbox']['total'], )); islandora_delete_object($target_object); - $context['results']['success'][] = $target_pid; + $object_check = islandora_object_load($target_pid); + if ($object_check) { + drupal_set_message(t('Could not delete ' . $target_pid . '. You may not have permission to manage this object.'), 'error'); + } + else { + $context['results']['success'][] = $target_pid; + } $context['sandbox']['progress']++; } $context['finished'] = ($context['sandbox']['total'] == 0) ? 1 : ($context['sandbox']['progress'] / $context['sandbox']['total']);