Stephen Ficklin 4 år sedan
förälder
incheckning
bc704f46d2

+ 4 - 4
tripal/includes/TripalBundleController.inc

@@ -191,18 +191,18 @@ class TripalBundleController extends EntityAPIControllerExportable {
       $response = 0;
     }
     else {
-      $response = "";
+      $response = [];
     }
     while (($bundle_record = $results->fetchObject())) {
       $bid = $bundle_record->id;
       $bundle_response = $this->findOrphans($bid, $count, $offset, $limit);
       if (is_array($bundle_response)) {
         foreach ($bundle_response as $key => $value) {
-          $response += $value;
+          $response[] = $value;
         }
       }
       else {
-        $response += $bundle_response;
+        $response[] = $bundle_response;
       }
     }
     return $response;
@@ -257,7 +257,7 @@ class TripalBundleController extends EntityAPIControllerExportable {
       $bundle = tripal_load_bundle_entity(['id' => $id]);
       $response = module_invoke_all('bundle_delete_orphans', $bundle, $eids, $job);
 
-      // Now remove the entities. 
+      // Now remove the entities.
       $num_deleted = db_delete('tripal_entity')
         ->condition('id', $eids, 'IN')
         ->execute();

+ 47 - 3
tripal/includes/TripalEntityController.inc

@@ -58,7 +58,7 @@ class TripalEntityController extends EntityAPIController {
   }
 
   /**
-   * Overrides EntityAPIController::delete().
+   * Provides an unpublish function.
    *
    * @param array $ids
    *    An array of the ids denoting which entities to delete.
@@ -66,7 +66,7 @@ class TripalEntityController extends EntityAPIController {
    *    Optionally a DatabaseTransaction object to use. Allows overrides to
    *   pass in their transaction object.
    */
-  public function delete($ids, $transaction = NULL) {
+  public function unpublish($ids, $transaction = NULL) {
 
     if (!$transaction) {
       $transaction = db_transaction();
@@ -80,7 +80,7 @@ class TripalEntityController extends EntityAPIController {
       foreach ($entities as $entity) {
 
         // Invoke hook_entity_delete().
-        module_invoke_all('entity_delete', $entity, $entity->type);
+        module_invoke_all('entity_unpublish', $entity, $entity->type);
 
         // Delete any field data for this entity.
         field_attach_delete('TripalEntity', $entity);
@@ -102,6 +102,50 @@ class TripalEntityController extends EntityAPIController {
     return TRUE;
   }
 
+  /**
+   * Overrides EntityAPIController::delete().
+   *
+   * @param array $ids
+   *    An array of the ids denoting which entities to delete.
+   * @param DatabaseTransaction $transaction
+   *    Optionally a DatabaseTransaction object to use. Allows overrides to
+   *   pass in their transaction object.
+   */
+  public function delete($ids, $transaction = NULL) {
+    global $user;
+
+    // Next delete the entities
+    if (!$transaction) {
+      $transaction = db_transaction();
+    }
+
+    try {
+
+      // First load the entity.
+      $entities = entity_load('TripalEntity', $ids);
+      $this->unpublish($ids, $transaction);
+
+      // Then properly delete each one.
+      foreach ($entities as $entity) {
+        module_invoke_all('entity_delete', $entity, $entity->type);
+      }
+
+    } catch (Exception $e) {
+      if ($transaction) {
+        $transaction->rollback();
+      }
+      watchdog_exception('tripal', $e);
+      throw $e;
+      return FALSE;
+    }
+
+    // Now remove any orphaned entities
+    tripal_add_job('Delete Orphaned Entities', 'tripal_chado',
+        'tripal_unpublish_orphans', [0], $user->uid, 10, [], TRUE);
+
+    return TRUE;
+  }
+
   /**
    * Sets the title for an entity.
    *

+ 89 - 18
tripal/includes/TripalEntityUIController.inc

@@ -100,7 +100,15 @@ class TripalEntityUIController extends EntityDefaultUIController {
       'type' => MENU_LOCAL_TASK,
       'weight' => 10,
     ];
-    // Menu item for deleting tripal data entities.
+    $items['bio_data/' . $wildcard . '/unpublish'] = [
+      'title' => 'Unpublish',
+      'page callback' => 'drupal_get_form',
+      'page arguments' => ['tripal_entity_unpublish_form', 1],
+      'access callback' => 'tripal_entity_access',
+      'access arguments' => ['unpublish', 1],
+      'type' => MENU_CALLBACK,
+      'weight' => 11,
+    ];
     $items['bio_data/' . $wildcard . '/delete'] = [
       'title' => 'Delete',
       'page callback' => 'drupal_get_form',
@@ -108,7 +116,7 @@ class TripalEntityUIController extends EntityDefaultUIController {
       'access callback' => 'tripal_entity_access',
       'access arguments' => ['delete', 1],
       'type' => MENU_CALLBACK,
-      'weight' => 10,
+      'weight' => 12,
     ];
     return $items;
   }
@@ -393,8 +401,8 @@ function tripal_content_overview_form($form, &$form_state) {
     if (entity_access('edit', 'TripalEntity', $entity, $user)) {
       $links .= '  ' . l('edit', 'bio_data/' . $entity->id . '/edit');
     }
-    if (entity_access('delete', 'TripalEntity', $entity, $user)) {
-      $links .= '  ' . l('delete', 'bio_data/' . $entity->id . '/delete');
+    if (entity_access('unpublish', 'TripalEntity', $entity, $user)) {
+      $links .= '  ' . l('unpublish', 'bio_data/' . $entity->id . '/unpublish');
     }
 
     // Add information to the table.
@@ -530,15 +538,23 @@ function tripal_entity_form($form, &$form_state, $term_id = '', $entity = NULL)
       '#weight' => 1000,
     ];
 
+    if (entity_access('unpublish', 'TripalEntity', $entity, $user)) {
+      $form['unpublish_button'] = [
+        '#type' => 'submit',
+        '#value' => t('Unpublish'),
+        '#name' => 'unpublish_data',
+        '#weight' => 1002,
+      ];
+    }
     // Put the delete button on the far-right so that it's harder
     // to accidentally click it.
     if (entity_access('delete', 'TripalEntity', $entity, $user)) {
       $form['delete_button'] = [
-        '#type' => 'submit',
-        '#value' => t('Delete'),
-        '#name' => 'delete_data',
-        '#weight' => 1002,
-        '#attributes' => ['style' => 'float: right'],
+          '#type' => 'submit',
+          '#value' => t('Delete'),
+          '#name' => 'delete_data',
+          '#weight' => 1003,
+          '#attributes' => ['style' => 'float: right'],
       ];
     }
   }
@@ -677,6 +693,7 @@ function tripal_entity_form_validate($form, &$form_state) {
  */
 function tripal_entity_form_submit($form, &$form_state) {
   $entity = $form_state['TripalEntity'];
+  global $user;
 
   if ($form_state['clicked_button']['#name'] == 'cancel_data') {
     if (property_exists($entity, 'id')) {
@@ -689,7 +706,15 @@ function tripal_entity_form_submit($form, &$form_state) {
   }
 
   if ($form_state['clicked_button']['#name'] == 'delete_data') {
-    $form_state['redirect'] = 'bio_data/' . $entity->id . '/delete';
+    if (entity_access('delete', 'TripalEntity', $entity, $user)) {
+      $form_state['redirect'] = 'bio_data/' . $entity->id . '/delete';
+    }
+    return;
+  }
+  if ($form_state['clicked_button']['#name'] == 'unpublish_data') {
+    if (entity_access('unpublish', 'TripalEntity', $entity, $user)) {
+      $form_state['redirect'] = 'bio_data/' . $entity->id . '/unpublish';
+    }
     return;
   }
 
@@ -876,11 +901,56 @@ function theme_tripal_add_list($variables) {
   return $output;
 }
 
+/**
+ * Form callback: confirmation form for unpublishing a tripal_entity.
+ *
+ * @param $tripal_entity
+ *   The tripal_entity to delete
+ *
+ * @see confirm_form()
+ */
+function tripal_entity_unpublish_form($form, &$form_state, $entity) {
+  $form_state['entity'] = $entity;
+  $form['#submit'][] = 'tripal_entity_unpublish_form_submit';
+
+  $form = confirm_form($form,
+    t('Unpublish the record "%title"?',
+      ['%title' => $entity->title]), 'admin/content/bio_data',
+    '<p>' . t('This action cannot be undone.') . '</p>',
+      t('Yes, Unpublish'), t('No, Cancel'), 'confirm');
+
+  return $form;
+}
+
+/**
+ * Submit callback for tripal_entity_unpublish_form
+ */
+function tripal_entity_unpublish_form_submit($form, &$form_state) {
+  global $user;
+  $entity = $form_state['entity'];
+
+  if (!entity_access('unpublish', 'TripalEntity', $entity, $user)) {
+    drupal_set_message(t('You do not have permission to unpublish this content.'), "error");
+    $form_state['redirect'] = 'admin/content/bio_data';
+    return;
+  }
+
+  $entity_controller = new TripalEntityController($entity->type);
+
+  if ($entity_controller->unpublish([$entity->id])) {
+    drupal_set_message(t('The record "%name" has been unpublished. The record, however, remains in the database and you can republish it later.', ['%name' => $entity->title]));
+    $form_state['redirect'] = 'admin/content/bio_data';
+  }
+  else {
+    drupal_set_message(t('The record "%name" was not unpublished.', ['%name' => $entity->title]), "error");
+  }
+}
+
 /**
  * Form callback: confirmation form for deleting a tripal_entity.
  *
- * @param $tripal_entity The
- *          tripal_entity to delete
+ * @param $tripal_entity
+ *   The tripal_entity to delete
  *
  * @see confirm_form()
  */
@@ -889,15 +959,15 @@ function tripal_entity_delete_form($form, &$form_state, $entity) {
   $form['#submit'][] = 'tripal_entity_delete_form_submit';
 
   $form = confirm_form($form,
-    t('Click the delete button below to confirm deletion of the record titled: %title',
-      ['%title' => $entity->title]), 'admin/content/tripal_entity',
-    '<p>' . t('This action cannot be undone.') . '</p>', t('Delete'), t('Cancel'), 'confirm');
+      t('Delete the record "%title"?',
+          ['%title' => $entity->title]), 'admin/content/bio_data',
+      '<p>' . t('This action cannot be undone. It will result in this record being unpublished and completely removed from the database. Any downstream records that depend on this entry will also be unpublished and completely removed as well. Please delete with caution!') . '</p>', t('Yes, Delete'), t('No, Cancel'), 'confirm');
 
   return $form;
 }
 
 /**
- * Submit callback for tripal_entity_delete_form
+ * Submit callback for tripal_entity_unpublish_form
  */
 function tripal_entity_delete_form_submit($form, &$form_state) {
   global $user;
@@ -912,11 +982,12 @@ function tripal_entity_delete_form_submit($form, &$form_state) {
   $entity_controller = new TripalEntityController($entity->type);
 
   if ($entity_controller->delete([$entity->id])) {
-    drupal_set_message(t('The record title "%name" has been deleted.', ['%name' => $entity->title]));
+    drupal_set_message(t('The record "%name" was deleted along with any dependent, downstream records.  Deleted records are no longer in the database. However, the site may still have published records. Therefore, a job has been added to remove any published but orphaned records.', ['%name' => $entity->title]));
     $form_state['redirect'] = 'admin/content/bio_data';
   }
   else {
-    drupal_set_message(t('The tripal_entity %name was not deleted.', ['%name' => $entity->title]), "error");
+    drupal_set_message(t('The record "%name" was not deleted.', ['%name' => $entity->title]), "error");
+    $form_state['redirect'] = 'admin/content/bio_data';
   }
 }
 

+ 3 - 1
tripal/includes/tripal.entity.inc

@@ -428,7 +428,7 @@ function tripal_field_property_get($entity, array $options, $field_name, $entity
  * tripal_entity_info() under the 'access callback' element.
  *
  * @param $op
- *   The operation. One of: create, view, edit, delete.
+ *   The operation. One of: create, view, edit, unpublish, delete.
  * @param $entity
  *   The entity to check access for.
  * @param $account
@@ -495,6 +495,8 @@ function tripal_entity_access($op, $entity = NULL, $account = NULL, $entity_type
       return user_access('view ' . $bundle_name, $account);
     case 'edit':
       return user_access('edit ' . $bundle_name, $account);
+    case 'unpublish':
+      return user_access('unpublish ' . $bundle_name, $account);
     case 'delete':
       return user_access('delete ' . $bundle_name, $account);
   }

+ 6 - 1
tripal/tripal.module

@@ -763,9 +763,13 @@ function tripal_permission() {
       'description' => t('Allow the user to edit %label content', array('%label' => $bundle->label)),
       'restrict access' => TRUE,
     );
+    $permissions['unpublish ' . $bundle->name] = array(
+      'title' => t('%label: Unpublish Content', array('%label' => $bundle->label)),
+      'description' => t('Allow the user to unpublish %label content. Unpublishing of content removes it from visibility on the site but does not delete the record in the underlying database.', array('%label' => $bundle->label)),
+    );
     $permissions['delete ' . $bundle->name] = array(
       'title' => t('%label: Delete Content', array('%label' => $bundle->label)),
-      'description' => t('Allow the user to delete %label content', array('%label' => $bundle->label)),
+      'description' => t('Allow the user to delete %label content. When content is deleted it is first unpublished and then deleted from the database.', array('%label' => $bundle->label)),
       'restrict access' => TRUE,
     );
   }
@@ -868,6 +872,7 @@ function tripal_admin_paths() {
     $paths = array(
       'bio_data/*/edit' => TRUE,
       'bio_data/*/delete' => TRUE,
+      'bio_data/*/unpublish' => TRUE,
       'bio_data/add' => TRUE,
       'bio_data/add/*' => TRUE,
     );

+ 40 - 2
tripal_chado/includes/tripal_chado.entity.inc

@@ -147,9 +147,47 @@ function tripal_chado_entity_delete($entity, $type) {
     return;
   }
 
-  // Delete the removed entity from the corresponding chado_bio_data_x table
+  // Remove the base record for this entity from the Chado tables.
   $bundle = $entity->bundle;
-  db_delete("chado_{$bundle}")->condition('entity_id', $entity->id)->execute();
+  if (db_table_exists("chado_{$bundle}")) {
+    $chado_table = $entity->chado_table;
+    $table_def = chado_get_schema($chado_table);
+    $pkey_field = $table_def['primary key'][0];
+    $match = [
+        $pkey_field => $entity->chado_record_id,
+    ];
+
+    // Here we need to set the active database to Chado
+    // because records will cascade delete. If one of the tables that
+    // gets items removed is the featureloc then there will be
+    // errors about undefined PLSQL functions.
+    $previous_db = chado_set_active('chado');
+    try {
+      chado_delete_record($entity->chado_table, $match);
+      chado_set_active($previous_db);
+    } catch (Exception $e) {
+      chado_set_active($previous_db);
+      throw $e;
+    }
+  }
+}
+
+/**
+ *
+ * Implements hook_entity_unpublish().
+ *
+ * This is not a Drupal hook, but one added by Tripal.
+ */
+function tripal_chado_entity_unpublish($entity, $type) {
+  if ($type !== 'TripalEntity') {
+    return;
+  }
+
+  // Remove the entity from the corresponding chado_bio_data_x table
+  $bundle = $entity->bundle;
+  if (db_table_exists("chado_{$bundle}")) {
+    db_delete("chado_{$bundle}")->condition('entity_id', $entity->id)->execute();
+  }
 }
 
 /**