You are here

workspace.module in Workspace 6

Presents a user-centric view of content.

Provides a "My workspace" link in the navigation block. When clicked it brings the user to a table showing the content they have created, with handy links to edit or delete the content, or to create new content.

Optionally provides a link to a user's content on their profile page (viewable if the current user has 'view all workspace' permission.

File

workspace.module
View source
<?php

/**
 * @file
 * Presents a user-centric view of content.
 *
 * Provides a "My workspace" link in the navigation block. When
 * clicked it brings the user to a table showing the content
 * they have created, with handy links to edit or delete the
 * content, or to create new content.
 *
 * Optionally provides a link to a user's content on their
 * profile page (viewable if the current user has 'view all
 * workspace' permission.
 */

/**
 * Implementation of hook_help().
 */
function workspace_help($path) {
  switch ($path) {
    case 'admin/help#workspace':
      $output = '<p>' . t('The workspace module provides a list of content for each user.') . '</p>';
      $output .= '<p>' . t("When enabled, each user will have a 'My workspace' link in the Navigation menu.") . '</p>';
      return $output;
  }
}

/**
 * Implementation of hook_menu().
 */
function workspace_menu() {
  $items['workspace/%user_uid_optional'] = array(
    'title' => 'My workspace',
    'page callback' => 'workspace_list_content',
    'page arguments' => array(
      1,
    ),
    'access callback' => 'workspace_access',
    'access arguments' => array(
      1,
    ),
    'weight' => -10,
  );
  $items['workspace/%user/content'] = array(
    'title' => 'Content',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'page callback' => 'workspace_list_content',
    'page arguments' => array(
      1,
    ),
    'access callback' => 'workspace_access',
    'access arguments' => array(
      1,
    ),
    'weight' => 10,
  );
  $items['workspace/%user/comments'] = array(
    'title' => 'Comments',
    'type' => MENU_LOCAL_TASK,
    'page callback' => 'workspace_list_comments',
    'page arguments' => array(
      1,
    ),
    'access callback' => 'workspace_access',
    'access arguments' => array(
      1,
      module_exists('comment'),
    ),
    'weight' => 20,
  );
  $items['workspace/%user/attachments'] = array(
    'title' => 'Attachments',
    'type' => MENU_LOCAL_TASK,
    'page callback' => 'workspace_list_files',
    'page arguments' => array(
      1,
    ),
    'access callback' => 'workspace_access',
    'access arguments' => array(
      1,
      module_exists('upload'),
    ),
    'weight' => 30,
  );
  $items['workspace/%user/configure'] = array(
    'title' => 'Configure',
    'page callback' => 'workspace_configure',
    'page arguments' => array(
      1,
    ),
    'access callback' => 'workspace_configure_access',
    'access arguments' => array(
      1,
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 50,
  );
  $items['admin/settings/workspace'] = array(
    'title' => 'Workspace',
    'description' => 'Customize workspace behavior.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'workspace_settings',
    ),
    'access arguments' => array(
      'administer workspaces',
    ),
  );

  // In this entry, 'access content' permission may seem liberal
  // but since workspace_delete() simply redirects to
  // node/*/delete deletion permissions will be applied there.
  $items['workspace/delete'] = array(
    'title' => 'Delete',
    'page callback' => 'workspace_delete',
    'access arguments' => array(
      'access content',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Menu access callback.
 */
function workspace_access($account, $module_enabled = TRUE) {
  global $user;

  // Let admin see $account
  if ($user->uid == 1 && $account->uid > 1) {
    return user_access('access content', $account) && user_access('access workspace', $account) && $module_enabled;
  }
  return user_access('access content', $user) && user_access('access workspace', $user) && (user_access('view all workspaces', $user) || $user->uid == $account->uid && $user->uid != 0) && $module_enabled;

  // If, e.g., comment module is disabled, remove comment local task.
}

/**
 * Menu access callback.
 */
function workspace_configure_access($account) {
  global $user;
  if ($user->uid == 1 && $account->uid > 1) {
    return user_access('administer workspaces', $account) || user_access('administer own workspace', $account);
  }
  return $user->uid != 0 && user_access('administer workspaces') || $user->uid == $account->uid && user_access('administer own workspace');
}

/**
 * Implementation of hook_perm().
 */
function workspace_perm() {
  return array(
    'access workspace',
    'administer own workspace',
    'administer workspaces',
    'view all workspaces',
  );
}

/**
 * Menu callback. The configuration page.
 */
function workspace_configure($account) {
  drupal_set_title(t('Workspace: @name', array(
    '@name' => $account->name,
  )));
  $output = drupal_get_form('workspace_configure_form', $account);
  return $output;
}

/**
 * Form definition for per-user configuration form.
 */
function workspace_configure_form($form_state, $account) {
  $form['maxnodes'] = array(
    '#type' => 'textfield',
    '#title' => t('Number of items'),
    '#description' => t('Maximum number of items to display in your workspace.'),
    '#default_value' => $account->workspaces ? $account->workspaces['default']['maxnodes'] : 50,
    '#size' => 4,
  );
  $form['maxfilenames'] = array(
    '#type' => 'textfield',
    '#title' => t('Number of files'),
    '#description' => t('Maximum number of filenames to display in your workspace.'),
    '#default_value' => $account->workspaces ? $account->workspaces['default']['maxfilenames'] : 50,
    '#size' => 4,
  );
  if (module_exists('comment')) {
    $form['maxcomments'] = array(
      '#type' => 'textfield',
      '#title' => t('Number of comments'),
      '#description' => t('Maximum number of comments to display in your workspace.'),
      '#default_value' => $account->workspaces['default']['maxcomments'] ? $account->workspaces['default']['maxcomments'] : 50,
      '#size' => 4,
    );
  }
  $form['uid'] = array(
    '#type' => 'value',
    '#value' => $account->uid,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save configuration'),
  );
  return $form;
}

/**
 * Validator for per-user configuration form.
 *
 * @see workspace_configure_form()
 */
function workspace_configure_form_validate($form, $form_state) {
  if (!is_numeric($form_state['values']['maxnodes'])) {
    form_set_error('maxnodes', t('Please enter a numeric value.'));
  }
  if (!is_numeric($form_state['values']['maxfilenames']) && !form_get_errors()) {
    form_set_error('maxfilenames', t('Please enter a numeric value.'));
  }
  if (module_exists('comment')) {
    if (!is_numeric($form_state['values']['maxcomments']) && !form_get_errors()) {
      form_set_error('maxfilenames', t('Please enter a numeric value.'));
    }
  }
}

/**
 * Submit handler for per-user configuration form.
 *
 * @see workspace_configure_form()
 */
function workspace_configure_form_submit($form, &$form_state) {

  // Must do a full user load to get existing serialized data.
  $account = user_load(array(
    'uid' => $form_state['values']['uid'],
  ));
  if (!isset($account->workspaces)) {
    $account->workspaces = array();
  }
  $account->workspaces['default']['maxnodes'] = (int) $form_state['values']['maxnodes'];
  $account->workspaces['default']['maxfilenames'] = (int) $form_state['values']['maxfilenames'];
  user_save($account, array(
    'workspaces' => $account->workspaces,
  ));
  drupal_set_message(t('The workspace preferences have been saved.'));
  $form_state['redirect'] = 'workspace/' . $form_state['values']['uid'];
}

/**
 * Menu callback. Display list of content.
 *
 * @param $account
 *   User object representing user whose workspace is being listed.
 */
function workspace_list_content($account) {
  global $user;
  drupal_set_title(t('Workspace: @name', array(
    '@name' => $account->name,
  )));
  $max = isset($user->workspaces) ? $user->workspaces['default']['maxnodes'] : 50;
  $comments_enabled = module_exists('comment');
  if ($comments_enabled) {

    // If the comment module is enabled, we need to get comment counts too.
    $sql = 'SELECT n.nid, n.uid, n.type, 0 as cid, n.title, n.status, n.changed, s.comment_count, 1 as node
            FROM {node} n
            LEFT JOIN {node_comment_statistics} s ON n.nid = s.nid
            WHERE n.uid = %d';
    $count_sql = 'SELECT COUNT(n.nid)
            FROM {node} n
            LEFT JOIN {node_comment_statistics} s ON n.nid = s.nid
            WHERE n.uid = %d';
  }
  else {

    // Otherwise we use a simpler query.
    $sql = 'SELECT n.nid, n.uid, n.type, 0 as cid, n.title, n.status, n.changed, 1 as node
            FROM {node} n
            WHERE n.uid = %d';
    $count_sql = 'SELECT COUNT(n.nid)
            FROM {node} n
            WHERE n.uid = %d';
  }
  $header = array(
    array(
      'data' => t('Type'),
      'field' => 'type',
    ),
    array(
      'data' => t('Title'),
      'field' => 'title',
    ),
    array(
      'data' => t('Owner'),
      'field' => 'uid',
    ),
    array(
      'data' => t('Published'),
      'field' => 'status',
    ),
    array(
      'data' => t('Modified'),
      'field' => 'changed',
      'sort' => 'desc',
    ),
    $comments_enabled ? array(
      'data' => t('Replies'),
      'field' => 'comment_count',
    ) : array(
      'data' => '',
    ),
    array(
      'data' => t('Operations'),
      'colspan' => 2,
    ),
  );
  $cols = 8;
  $result = pager_query(db_rewrite_sql($sql . tablesort_sql($header)), $max, 0, db_rewrite_sql($count_sql), $account->uid);
  $rows = workspace_build_rows($result, $account);
  $output = '';

  // Only add the content add form if the user is viewing his/her own workspace.
  if ($user->uid == 1 || user_access('view all workspaces') || $user->uid == $account->uid) {
    $output = drupal_get_form('workspace_add_form');
  }
  $output .= theme_workspace_list($header, $rows, $max, $cols);
  return $output;
}

/**
 * Menu callback. Display list of comments.
 *
 * @param $account
 *   User object representing user whose workspace is being listed.
 */
function workspace_list_comments($account) {
  drupal_set_title(t('Workspace: @name', array(
    '@name' => $account->name,
  )));
  $max = isset($account->workspaces) ? $account->workspaces['default']['maxcomments'] : 50;
  $sql = 'SELECT c.nid, c.uid, c.cid, c.subject, c.status, c.timestamp, c.pid, 0
                FROM {comments} c
                WHERE c.uid = %d';
  $count_sql = 'SELECT COUNT(cid) FROM {comments} WHERE uid = %d';

  // Build the comment listing.
  $header = array(
    array(
      'data' => t('Title'),
      'field' => 'title',
    ),
    array(
      'data' => t('Published'),
      'field' => 'status',
    ),
    array(
      'data' => t('Modified'),
      'field' => 'timestamp',
      'sort' => 'desc',
    ),
    array(
      'data' => t('Replies'),
      'field' => 'comment_count',
    ),
    array(
      'data' => t('Operations'),
      'colspan' => 2,
    ),
  );
  $cols = 6;
  $result = pager_query($sql . tablesort_sql($header), $max, 0, $count_sql, $account->uid);
  $rows = workspace_build_rows($result, $account);
  return theme_workspace_list($header, $rows, $max, $cols);
}

/**
 * Build the query result into a table, respecting access.
 *
 * @param $result
 *   A result object as returned from pager_query().
 * @param $account
 *   User object representing user whose workspace is being listed.
 */
function workspace_build_rows($result, $account) {
  global $user;
  $yes = t('yes');
  $no = t('no');
  $rows = array();
  while ($row = db_fetch_object($result)) {

    // It's a node.
    if ($row->node == 1) {

      // Edit and delete permissions are set by the node type's access hook.
      // If no access hook is found, node-level permissions are then used.
      // This approach is part of Drupal's core design.
      $may_edit = FALSE;
      $may_delete = FALSE;

      //Check the node type's access hook.
      $function = $row->type . '_access';
      if ($cck_enabled && strstr($function, 'content_')) {
        $function = 'content_access';
      }
      else {
        $function = 'node_access';
      }
      if (function_exists($function)) {
        if (!$function('view', $row, $user)) {

          // No view permission means it is not shown in the workspace.
          continue;
        }
        $may_edit = $function('update', $row, $user) ? TRUE : FALSE;
        $may_delete = $function('delete', $row, $user) ? TRUE : FALSE;
      }
      else {

        // If we can't find an access function, deny by default.
        continue;
      }

      // The name of the owner of this node.
      $name = $user->uid == $row->uid ? $user->name : db_result(db_query('SELECT name FROM {users} WHERE uid = %d', $row->uid));
      $rows[] = array(
        node_get_types('name', $row->type),
        l($row->title, "node/{$row->nid}"),
        $name,
        $row->status ? $yes : $no,
        format_date($row->changed, 'small'),
        module_exists('comment') ? array(
          'data' => $row->comment_count ? $row->comment_count : 0,
          'align' => 'right',
        ) : array(
          'data' => '',
        ),
        $may_edit ? l(t('edit'), "node/{$row->nid}/edit") : '',
        $may_delete ? l(t('delete'), "workspace/delete/{$row->nid}") : '',
      );
    }
    else {

      // It's a comment.
      $num_replies = comment_num_replies($row->cid);
      $comment->cid = $row->cid;
      $comment->nid = $row->nid;

      // Delegate access permission checks and link generation to comment.module.
      $comment_links = comment_links($comment, 0);
      $link = l(t('edit'), "comment/edit/{$comment->cid}");
      $edit_link = $comment_links['comment_edit'] ? $link : '';
      $link = l(t('delete'), "comment/delete/{$comment->cid}");
      $delete_link = $comment_links['comment_delete'] ? $link : '';
      $rows[] = array(
        l($row->subject, "node/{$row->nid}", array(), NULL, "comment-{$row->cid}", FALSE, TRUE),
        $row->status ? $no : $yes,
        format_date($row->timestamp, 'small'),
        array(
          'data' => $num_replies,
          'align' => 'right',
        ),
        $edit_link,
        $delete_link,
      );
    }
  }
  return $rows;
}

/**
 * Menu callback. List file attachments managed by upload.module.
 *
 * @param $account
 *   User object representing user whose workspace is being listed.
 */
function workspace_list_files($account) {
  global $user;
  drupal_set_title(t('Workspace: @name', array(
    '@name' => $account->name,
  )));
  $max = isset($user->workspaces) ? $user->workspaces['default']['maxfilenames'] : 50;
  $download = t('download');
  $rows = array();
  $header = array(
    array(
      'data' => t('Filename'),
      'field' => 'f.filename',
    ),
    array(
      'data' => t('Type'),
      'field' => 'f.filemime',
    ),
    array(
      'data' => t('Modified'),
      'field' => 'f.timestamp',
      'sort' => 'desc',
    ),
    array(
      'data' => t('Size'),
      'field' => 'f.filesize',
    ),
    array(
      'data' => t('Operations'),
    ),
  );
  $cols = 6;
  $sql = "SELECT u.nid, f.filemime, f.filename, f.filesize, f.timestamp, f.filepath\n          FROM {files} f\n          LEFT JOIN {upload} u ON f.fid = u.fid\n          WHERE f.uid = %d";
  $result = pager_query($sql . tablesort_sql($header), $max, 2, NULL, $account->uid);
  while ($row = db_fetch_object($result)) {
    $rows[] = array(
      l($row->filename, "node/{$row->nid}"),
      $row->filemime,
      format_date($row->timestamp, 'small'),
      format_size($row->filesize),
      l($download, file_create_url($row->filepath)),
    );
  }
  return theme('workspace_list', $header, $rows, $max, $cols);
}

/**
 * Implementation of hook_theme().
 */
function workspace_theme() {
  return array(
    'workspace_list' => array(
      'arguments' => array(
        'header' => array(),
        'rows' => array(),
        $max = 50,
        $cols = 8,
      ),
    ),
  );
}

/**
 * Theme the list of content. Turn the results into a table.
 */
function theme_workspace_list($header, $rows, $max, $cols) {
  if ($rows) {
    $pager = theme('pager', NULL, $max);
    if (!empty($pager)) {
      $rows[] = array(
        array(
          'data' => $pager,
          'colspan' => $cols,
        ),
      );
    }
    $output = theme('table', $header, $rows);
  }
  else {
    $output = t('Your workspace is currently empty.');
  }
  return $output;
}

/**
 * Menu callback. Redirect user to delete node.
 */
function workspace_delete() {
  $nid = intval(arg(2));
  if (is_numeric($nid)) {
    drupal_goto('node/' . $nid . '/delete');
  }
}

/**
 * Form definition for content addition form.
 */
function workspace_add_form() {
  global $user;
  $description = t('Choose what kind of content you would like to add.') . ' ' . l(t('Help?'), 'node/add');
  $select = t('Select...');
  $options = array(
    $select => $select,
  );
  foreach (node_get_types() as $type => $object) {
    if (module_invoke(node_get_types('module', $type), 'access', 'create', $type, $user)) {
      $options[$type] = $object->name;
    }
  }
  if (count($options) == 1) {
    return array();
  }
  $form['add'] = array(
    '#type' => 'fieldset',
    '#prefix' => '<div class="container-inline">',
    '#suffix' => '</div>',
  );
  $form['add']['content_type'] = array(
    '#type' => 'select',
    '#options' => $options,
  );
  $form['add']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Add new item'),
    '#suffix' => $description,
  );
  return $form;
}

/**
 * Submit handler for content addition form.
 *
 * Simply redirects to appropriate node/add/* page.
 *
 * @see workspace_add_form()
 */
function workspace_add_form_submit($form, $form_state) {
  $node_type = $form_state['values']['content_type'];
  if ($node_type == t('Select...')) {
    drupal_goto('node/add');
  }
  foreach (node_get_types() as $type => $object) {
    if (node_access('create', $type, $user->uid)) {
      $options[$type] = $object->name;
    }
    if (isset($options[$node_type])) {

      /* Start hack */
      if (stristr($node_type, "_") > -1) {
        $node_type = str_replace("_", "-", $node_type);
      }

      /* End hack */
      drupal_goto('node/add/' . $node_type);
    }
  }
}

/**
 * Implementation of hook_settings().
 */
function workspace_settings() {
  $roles = user_roles();

  // The anonymous user does not have a profile.
  unset($roles[DRUPAL_ANONYMOUS_RID]);
  $form['info'] = array(
    '#value' => t("Select each role for which you want the link to a user's workspace to show up in their user profile."),
  );
  foreach ($roles as $rid => $name) {
    $identifier = 'workspace_user_profile_' . $rid;
    $form[$identifier] = array(
      '#type' => 'checkbox',
      '#title' => $name,
      '#default_value' => variable_get($identifier, 0),
    );
  }
  $form['workspace_user_profile_link'] = array(
    '#type' => 'textfield',
    '#title' => t("Name of link to user's workspace"),
    '#description' => t("This will be used to display the link to a user's workspace on his or her profile page. The %username token will be replaced by the username of the user whose profile is being shown."),
    '#default_value' => variable_get('workspace_user_profile_link', t('View recent content created by %username')),
  );
  return system_settings_form($form);
}

/**
 * Implementation of hook_user().
 *
 * Place link to user's workspace on user's profile page.
 */
function workspace_user($op, &$edit, &$account) {
  global $user;
  if ($op == 'view') {
    if (workspace_access($account)) {
      $variables['%username'] = $account->name;
      $link_title = variable_get('workspace_user_profile_link', t('View recent content'));
      $link = l(strtr($link_title, $variables), 'workspace/' . $account->uid);
      $account->content['workspace'] = array(
        '#type' => 'user_profile_category',
        '#title' => variable_get('workspace_user_profile_title', t('Content')),
        'link' => array(
          '#value' => $link,
          '#type' => 'user_profile_item',
        ),
        '#weight' => -10,
      );
    }
  }
}

Functions

Namesort descending Description
theme_workspace_list Theme the list of content. Turn the results into a table.
workspace_access Menu access callback.
workspace_add_form Form definition for content addition form.
workspace_add_form_submit Submit handler for content addition form.
workspace_build_rows Build the query result into a table, respecting access.
workspace_configure Menu callback. The configuration page.
workspace_configure_access Menu access callback.
workspace_configure_form Form definition for per-user configuration form.
workspace_configure_form_submit Submit handler for per-user configuration form.
workspace_configure_form_validate Validator for per-user configuration form.
workspace_delete Menu callback. Redirect user to delete node.
workspace_help Implementation of hook_help().
workspace_list_comments Menu callback. Display list of comments.
workspace_list_content Menu callback. Display list of content.
workspace_list_files Menu callback. List file attachments managed by upload.module.
workspace_menu Implementation of hook_menu().
workspace_perm Implementation of hook_perm().
workspace_settings Implementation of hook_settings().
workspace_theme Implementation of hook_theme().
workspace_user Implementation of hook_user().