Jelajahi Sumber

Merge branch '7.x-3.x-dashboard' into 7.x-3.x-refactor

Stephen Ficklin 8 tahun lalu
induk
melakukan
19ac33ad2c

+ 147 - 0
tripal/api/tripal.entities.api.inc

@@ -192,6 +192,60 @@ function hook_bundle_create(&$bundle, $storage_args) {
  */
 function hook_bundle_postcreate(&$bundle) {
 
+}
+/**
+ * Allows a module to add admin notifications to the associated tripal table
+ * during the cron run.
+ *
+ */
+function hook_tripal_cron_notification() {
+
+}
+/**
+ * Allows a module to write to the admin notification table
+ * during the cron run.
+ *
+ * @param $title
+ *   A generic phrase indicating what the notification is for.
+ * @param $details
+ *   A human-readable sentence or two describing the issue.
+ * @param $type
+ *   A one word type indicating the type of notification. Tripal types include:  Jobs, Fields.
+ *   If not type is required please pass NULL.
+ * @param $actions
+ *   A serialized PHP associative array containing the link and URL for each action.
+ *   If not type is required please pass NULL.
+ * @param $submitter_id
+ *   A unique ID provided by the submitter for checking to make sure that the notification is not added more than once.
+ */
+function tripal_add_notifcation($title, $details, $type, $actions, $submitter_id) {
+  $transaction = db_transaction();
+
+  // Check the notification isn't already in the admin notification table.
+  $dedup = db_select('tripal_admin_notfications', 'tan')
+    ->fields('tan')
+    ->condition('submitter_id', $submitter_id, '=')
+    ->execute()->fetchAll();
+
+  if (empty($dedup)) {
+    try {
+      $record = new stdClass;
+      $record->details = $details;
+      $record->title = $title;
+      $record->submitter_id = $submitter_id;
+      $record->actions = serialize($actions);
+      $record->enabled = 1;
+      $record->type = $type;
+      $success = drupal_write_record('tripal_admin_notfications', $record);
+    }
+    catch (Exception $e) {
+      $transaction->rollback();
+      watchdog('tripal_cron', 'Could not write notification to database.');
+    }
+    if ($success) {
+      watchdog('tripal_cron', 'New field notification created.');
+    }
+  }
 }
 /**
  * Creates a new Tripal Entity type (i.e. bundle).
@@ -392,6 +446,99 @@ function tripal_get_content_types() {
     ->fetchAll();
 }
 
+/**
+ * Implements hook_cron().
+ */
+function tripal_cron() {
+  if (variable_get('tripal_admin_notification_creation_during_cron', TRUE)) {
+    $modules = module_implements('tripal_cron_notification');
+    foreach ($modules as $module) {
+      $function = $module . '_tripal_cron_notification';
+      $function();
+    }
+    watchdog('tripal_cron', 'tripal_cron ran');
+  }
+}
+
+/**
+ * Refreshes the bundle such that new fields added by modules will be found during cron.
+ *
+ * @param $bundle_name
+ *   The name of the bundle to refresh (e.g. bio_data_4).
+ */
+function tripal_tripal_cron_notification() {
+  $num_created = 0;
+
+  // Get all bundle names to cycle through.
+  $all_bundles = db_select('tripal_bundle', 'tb')
+    ->fields('tb', array('name'))
+    ->execute()->fetchAll();
+
+  foreach ($all_bundles as $bundle_name){
+    // Get the bundle object.
+    $bundle = tripal_load_bundle_entity(array('name' => $bundle_name->name));
+    if (!$bundle) {
+      tripal_report_error('tripal', TRIPAL_ERROR, "Unrecognized bundle name '%bundle'.",
+        array('%bundle' => $bundle_name));
+      return FALSE;
+    }
+    // Allow modules to add fields to the new bundle.
+    $modules = module_implements('bundle_create_fields');
+    foreach ($modules as $module) {
+      $function = $module . '_bundle_create_fields';
+      $info = $function('TripalEntity', $bundle);
+      foreach ($info as $field_name => $details) {
+
+        // If the field already exists then skip it.
+        $field = field_info_field($details['field_name']);
+        if ($field) {
+          continue;
+        }
+
+        // Create notification that new fields exist.
+        $detail_info = ' Tripal has detected a new field ' . $details['field_name'] .' for ' . $bundle->label. ' content type is available for import.';
+        $title = 'New field available for import';
+        $actions['Import'] = 'admin/import/field/' . $details['field_name'] . '/' . $bundle_name->name . '/' . $module . '/field';
+        $type = 'Field';
+        $submitter_id = $details['field_name'] . '-' . $bundle_name->name . '-' . $module;
+
+        tripal_add_notifcation($title, $detail_info, $type, $actions, $submitter_id);
+        $num_created++;
+      }
+    }
+
+    // Allow modules to add instances to the new bundle.
+    $modules = module_implements('bundle_create_instances');
+    foreach ($modules as $module) {
+      $function = $module . '_bundle_create_instances';
+      $info = $function('TripalEntity', $bundle);
+      foreach ($info as $field_name => $details) {
+
+        // If the field is already attached to this bundle then skip it.
+        $field = field_info_field($details['field_name']);
+        if ($field and array_key_exists('bundles', $field) and
+          array_key_exists('TripalEntity', $field['bundles']) and
+          in_array($bundle->name, $field['bundles']['TripalEntity'])) {
+          continue;
+        }
+
+        // Create notification that new fields exist.
+        $detail_info = ' Tripal has detected a new field ' . $details['field_name'] .' for ' . $bundle->label. ' content type is available for import.';
+        $title = 'New field available for import';
+        $actions['Import'] = 'admin/import/field/' . $details['field_name'] . '/' . $bundle->name . '/' . $module . '/instance';
+        $type = 'Field';
+        $submitter_id = $details['field_name'] . '-' . $bundle_name->name . '-' . $module;
+
+        tripal_add_notifcation($title, $detail_info, $type, $actions, $submitter_id);
+        $num_created++;
+      }
+    }
+    if ($num_created == 0) {
+      watchdog('tripal_cron', '<pre>No new fields for '. print_r($bundle_name->name, TRUE) .'</pre>');
+    }
+  }
+}
+
 /**
  * Retrieves information about a given content type.
  *

+ 111 - 0
tripal/includes/tripal_admin_usage_page.inc

@@ -0,0 +1,111 @@
+<?php
+
+/**
+ * Create the admin page for the dashboard.
+ *
+ */
+function tripal_admin_usage_page() {
+  // set the breadcrumb
+  $breadcrumb = array();
+  $breadcrumb[] = l('Home', '<front>');
+  $breadcrumb[] = l('Administration', 'admin');
+  $breadcrumb[] = l('Tripal', 'admin/tripal');
+  drupal_set_breadcrumb($breadcrumb);
+  tripal_add_d3js();
+  //drupal_add_js(drupal_get_path ('module', 'tripal') . '/theme/js/tripal_galaxy.dashboard.js');
+  drupal_add_css(drupal_get_path ('module', 'tripal') . '/theme/css/tripal.dashboard.css');
+  drupal_add_library('system', 'drupal.collapse');
+  $output = '<h2>Tripal Administrative Notifications and Info</h2>';
+  return $output;
+}
+
+/**
+ * Import the field from the admin notification table on
+ * the dashboard.
+ *
+ * @param $field_name
+ *   The name of the field to be imported.
+ *
+ *  * @param $bundle_id
+ *   The ID of the bundle associated with that field.
+ *
+ */
+function tripal_admin_notification_import_field($field_name_note, $bundle_id, $module, $field_or_instance) {
+  // Get the bundle object.
+  $bundle = tripal_load_bundle_entity(array('name' => $bundle_id));
+  if (!$bundle) {
+    tripal_report_error('tripal', TRIPAL_ERROR, "Unrecognized bundle name '%bundle'.",
+      array('%bundle' => $bundle_id));
+    drupal_goto("admin/tripal/dashboard");
+    return FALSE;
+  }
+
+  if($field_or_instance == 'field'){
+    $function = $module . '_bundle_create_fields';
+    $info = $function('TripalEntity', $bundle);
+    foreach ($info as $field_name => $details) {
+      if($details['field_name'] == $field_name_note) {
+        // Create the field.
+        $instance = field_create_field($details);
+        drupal_set_message(t("Created field: %field", array('%field' => $info[ $field_name ]['label'])));
+
+        if (!$instance) {
+          tripal_set_message(t("Could not create new field: %field.",
+            array('%field' =>  $field_name_note)), TRIPAL_ERROR);
+        }
+      }
+    }
+  }
+  else if($field_or_instance == 'instance'){
+    $function = $module . '_bundle_create_instances';
+    $info = $function('TripalEntity', $bundle);
+    foreach ($info as $field_name => $details) {
+      if($details['field_name'] == $field_name_note) {
+        // Create the field instance.
+        $instance = field_create_instance($details);
+        drupal_set_message(t("Created field: %field", array('%field' => $info[ $field_name ]['label'])));
+
+        if (!$instance) {
+          tripal_set_message(t("Could not create new field: %field.",
+            array('%field' =>  $field_name_note)), TRIPAL_ERROR);
+        }
+      }
+    }
+  }
+
+  $submitter_id = $field_name_note . '-' . $bundle_id . '-' . $module;
+  if($instance){
+    // Delete the notification table entry.
+    db_delete('tripal_admin_notfications')
+      ->condition('submitter_id', $submitter_id, '=')
+      ->execute();
+  }
+  else {
+    drupal_set_message(t("There was a problem creating: %field", array('%field' => $info[ $field_name ]['label'])));
+  }
+
+  drupal_goto("admin/tripal/dashboard");
+}
+
+/**
+ * Disable the notification of the field on the dashboard.
+ *
+ * @param $note_id
+ *   The ID of the note in the tripal_admin_notifications table
+ * that will be dismissed.
+ */
+function tripal_disable_admin_notification($note_id) {
+  $success = db_update('tripal_admin_notfications')
+          ->fields(array(
+            'enabled' => 0,
+          ))
+          ->condition('note_id', $note_id, '=')
+          ->execute();
+  if($success){
+    drupal_set_message("That notification has been dismissed and will no longer appear.");
+  }
+  else {
+    drupal_set_message("Could not dismiss notification.", 'error');
+  }
+  drupal_goto("admin/tripal/dashboard");
+}

+ 117 - 1
tripal/tripal.install

@@ -191,7 +191,8 @@ function tripal_schema() {
 
   // Adds a table for additional information related to bundles.
   $schema['tripal_bundle_variables'] = tripal_tripal_bundle_variables_schema();
-
+  // Adds a table for administrative notifications on the dashboard.
+  $schema['tripal_admin_notfications'] = tripal_tripal_admin_notifications_schema();
   return $schema;
 }
 function tripal_tripal_jobs_schema() {
@@ -702,6 +703,62 @@ function tripal_tripal_bundle_variables_schema() {
   return $schema;
 }
 
+/**
+ * Additional Tripal Admin Notification Information.
+ *
+ * This table is used for information describing administrative
+ * notifications. For example, when new fields are available.
+ */
+function tripal_tripal_admin_notifications_schema() {
+
+  $schema = array(
+    'description' => 'This table is used for information describing administrative
+     notifications. For example, when new fields are available.',
+    'fields' => array (
+      'note_id' => array (
+        'type' => 'serial',
+        'not null' => TRUE,
+      ),
+      'details' => array (
+        'description' => 'Description and additional information relating to the notification.',
+        'type' => 'text',
+        'not null' => TRUE,
+      ),
+      'title' => array (
+        'description' => 'Title of the notification.',
+        'type' => 'text',
+        'not null' => TRUE,
+      ),
+      'actions' => array (
+        'description' => 'Actions that can be performed on the notification, like disimissal or import.',
+        'type' => 'text',
+        'not null' => FALSE,
+      ),
+      'submitter_id' => array (
+        'description' => 'A unique id that should be specific to the notification to ensure notifications are not duplicated.',
+        'type' => 'text',
+        'not null' => TRUE,
+      ),
+      'enabled' => array (
+        'description' => 'Boolean indicating whether the notification is enabled or disabled (disabled will not be shown on the dashboard).',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 1,
+      ),
+      'type' => array (
+        'description' => 'Type of the notification, relating to what tripal function the notification belongs to, IE Fields, Jobs, Vocabulary.',
+        'type' => 'text',
+        'not null' => FALSE,
+      ),
+    ),
+    'primary key' => array (
+      0 => 'note_id',
+    ),
+  );
+
+  return $schema;
+}
+
 /**
  * Change tripal_vocab.vocabulary to varchar(128)
  */
@@ -720,3 +777,62 @@ function tripal_update_7300() {
     throw new DrupalUpdateException('Could not perform update: '. $error);
   }
 }
+
+/**
+ * Create new admin notifications table.
+ */
+function tripal_update_7301() {
+  $transaction = db_transaction();
+  try {
+    $schema['tripal_admin_notfications'] = array(
+      'description' => 'This table is used for information describing administrative
+       notifications. For example, when new fields are available.',
+      'fields' => array (
+        'note_id' => array (
+          'type' => 'serial',
+          'not null' => TRUE,
+        ),
+        'details' => array (
+          'description' => 'Description and additional information relating to the notification.',
+          'type' => 'text',
+          'not null' => TRUE,
+        ),
+        'title' => array (
+          'description' => 'Title of the notification.',
+          'type' => 'text',
+          'not null' => TRUE,
+        ),
+        'actions' => array (
+          'description' => 'Actions that can be performed on the notification, like disimissal or import.',
+          'type' => 'text',
+          'not null' => FALSE,
+        ),
+        'submitter_id' => array (
+          'description' => 'A unique id that should be specific to the notification to ensure notifications are not duplicated.',
+          'type' => 'text',
+          'not null' => TRUE,
+        ),
+        'enabled' => array (
+          'description' => 'Boolean indicating whether the notification is enabled or disabled (disabled will not be shown on the dashboard).',
+          'type' => 'int',
+          'not null' => TRUE,
+          'default' => 1,
+        ),
+        'type' => array (
+          'description' => 'Type of the notification, relating to what tripal function the notification belongs to, IE Fields, Jobs, Vocabulary.',
+          'type' => 'text',
+          'not null' => FALSE,
+        ),
+      ),
+        'primary key' => array (
+          0 => 'note_id',
+        ),
+    );
+    db_create_table('tripal_admin_notfications', $schema['tripal_admin_notfications']);
+  }
+  catch (\PDOException $e) {
+      $transaction->rollback();
+      $error = $e->getMessage();
+      throw new DrupalUpdateException('Could not perform update: '. $error);
+  }
+}

+ 136 - 0
tripal/tripal.module

@@ -118,6 +118,18 @@ function tripal_menu() {
     'weight' => 8,
     'access arguments' => array('administer tripal'),
   );
+
+  $items['admin/tripal/dashboard'] = array(
+    'title' => 'Dashboard',
+    'description' => t("A dashboard view of Tripal including new fields for entities."),
+    'weight' => 0,
+    'page callback' => 'tripal_admin_usage_page',
+    'access arguments' => array('administer tripal'),
+    'type' => MENU_NORMAL_ITEM,
+    'file' => 'includes/tripal_admin_usage_page.inc',
+    'file path' => drupal_get_path('module', 'tripal'),
+  );
+
   $items['admin/tripal/terms/import'] = array(
     'title' => 'Import Vocabulary',
     'description' => t("Import vocabularies and terms in OBO format."),
@@ -247,6 +259,27 @@ function tripal_menu() {
     'file path' => drupal_get_path('module', 'tripal'),
   );
 
+  /*
+   * Dashboard Action Item callbacks.
+   */
+  $items['admin/disable/notification/%'] = array(
+    'page callback' => 'tripal_disable_admin_notification',
+    'page arguments' => array(3),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+    'file' => 'includes/tripal_admin_usage_page.inc',
+    'file path' => drupal_get_path('module', 'tripal'),
+  );
+
+  $items['admin/import/field/%/%/%/%'] = array(
+    'page callback' => 'tripal_admin_notification_import_field',
+    'page arguments' => array(3, 4, 5, 6),
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+    'file' => 'includes/tripal_admin_usage_page.inc',
+    'file path' => drupal_get_path('module', 'tripal'),
+  );
+
   /*
    * Term Lookup
    */
@@ -603,3 +636,106 @@ function tripal_check_new_fields($bundle_name) {
   tripal_refresh_bundle_fields($bundle_name);
   drupal_goto("admin/structure/bio_data/manage/$bundle_name/fields");
 }
+
+
+/**
+ * Implements hook_block_info().
+ */
+function tripal_block_info() {
+  $blocks = array();
+
+  $blocks['notifications_block'] = array(
+    'info' => t('Dashboard Notifications'),
+    'visibility' => BLOCK_VISIBILITY_LISTED,
+    'pages' => 'admin/tripal/dashboard',
+    'status' => TRUE,
+    'region' => 'content',
+    'properties' => array(
+      'administrative' => TRUE,
+    ),
+  );
+  return $blocks;
+}
+
+/**
+ * Implements hook_block_view().
+ */
+function tripal_block_view($delta = ''){
+  // The $delta parameter tells us which block is being requested.
+  switch ($delta) {
+    case 'notifications_block':
+      // Create your block content here
+      $block['content'] = '';
+
+      // Prepare table header
+      $header = array(
+        'title' => array('data' => t('Title')),
+        'details' => array('data' => t('Details')),
+        'type' => array('data' => t('Type'), 'field' => 'tan.type'),
+        'actions' => array('data' => t('Actions'))
+      );
+
+      $query = db_select('tripal_admin_notfications', 'tan')
+        ->extend('TableSort');
+
+      $results = $query->fields('tan')
+        ->condition('enabled', 1, '=')
+        ->orderByHeader($header)
+        ->execute()->fetchAll();
+      $rows = array();
+
+      foreach($results as $result){
+        $data['operation'] = ' | ';
+        $data['operation'] .= l(t('Dismiss Notification'), 'admin/disable/notification/' . $result->note_id);
+
+        $actions = unserialize($result->actions);
+        foreach($actions as $action){
+          $label = key($actions);
+          $link = $action;
+        }
+
+        $rows[] = array(
+          'Title' => $result->title,
+          'Details' => $result->details,
+          'Type' => $result->type,
+          'Actions' => l(t($label), $link) . $data['operation'],
+        );
+      }
+      if(!empty($rows)) {
+        //Number of records shown in per page
+        $per_page = 10;
+        $current_page = pager_default_initialize(count($rows), $per_page);
+        $chunks = array_chunk($rows, $per_page, TRUE);
+
+        // Output of table with the paging
+        $table = theme('table',
+          array(
+            "header" => $header,
+            "rows" => $chunks[ $current_page ],
+            "attributes" => array(),
+            "sticky" => TRUE,
+            "caption" => "",
+            "colgroups" => array(),
+            "empty" => t("No notifications.")
+          )
+        );
+        $table .= theme('pager', array('quantity', count($rows)));
+
+        $fieldset_table = array(
+          '#title' => t('Notifications'),
+          '#collapsed' => FALSE,
+          '#collapsible' => TRUE,
+          '#attributes' => array('class' => array('collapsible')),
+          '#children' => $table,
+        );
+
+        //return pager with limited number of records.
+        $block['content'] = theme('fieldset', array('element' => $fieldset_table));
+      }
+      else {
+        $block['content'] = 'There are no notifications at this time.';
+      }
+      break;
+  }
+  return $block;
+}

+ 1 - 1
tripal_ds/theme/js/tripal_ds.js

@@ -14,7 +14,7 @@
         $(this).css('cursor', 'pointer');
         $(this).css('margin', '0px 5px');
         $(this).click(function () {
-          var fs = $(this).parent().parent().parent().parent().parent();
+          var fs = $(this).parents('.field-group-fieldset');
           if($(fs).hasClass('showTripalPane'))  {
             $(fs).removeClass('showTripalPane');
             $(fs).addClass('hideTripalPane');