array('name' => 'Announcement', 'description' => 'An Announcement. Use this page to add an announcement page.', 'module' => 'announcement')); } /** * Implementation of hook_access(). * * This function allows the announcement module to limit access to the node type * it defines depending on the operation currently being performed and the * permissions defined in the Drupal user permissions administration page. * * @param $op * The Drupal operation currently being performed. Here we want to control access * for the ‘create’, ‘view’, ‘update’ and ‘delete’ operations. * @param $node * The node object on which this operation is being performed. * @return * A boolean value depending on whether the operation can be performed or not. * * More detail at http://api.drupal.org/api/HEAD/function/hook_access */ function announcement_access($op, $node) { global $user; if ($op == 'create') { return user_access('create announcement'); } else if ($op == 'view') { return user_access('access content'); } else if ($op == 'update' || $op == 'delete') { if($user->uid == $node->uid || user_access('edit announcement')) { return true; } else { return false; } } else { return false; } } /** * Implementation of hook_menu(). * * This function allows the announcement module to register URL paths and * determine how these requests are to be handled. Depending on the * registration a link may be placed in a menu or as a tab at the top of * the page. * * NOTE: For version 5.*, you need to register the URL path, * admin/settings/announcement, to map to a callback function to create * a form to manipulate its settings. * * @param $may_cache * This is a boolean used to determine if a registered URL path should * be cached or not. Usually, those URL path that include some dynamic * value should not be cached. * @return * An array of registered URL path objects. These contain at least the * registered URL path, a string of text used as a title for these paths, * an access flag built by testing the access list, a type to determine * how this registration be used, and the name of the callback function * that should be called when this URL path is requested. * * More detail at http://api.drupal.org/api/HEAD/function/hook_menu * */ function announcement_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array('path' => 'announcements/add', 'title' => t('Add a new Announcement'), 'access' => node_access('create', 'announcement'), 'type' => MENU_CALLBACK, 'callback arguments' => array('announcement'), 'callback' => 'node_add'); $items[] = array('path' => 'announcements', 'title' => t('Announcements'), 'access' => user_access('access content'), 'type' => MENU_CALLBACK, 'callback' => 'announcement_all'); } else { $items[] = array('path' => 'announcements/pager', 'title' => t('Announcements Pager Example'), 'access' => user_access('administer site'), 'type' => MENU_CALLBACK, 'callback' => 'announcement_pager'); if(is_numeric(arg(1))) { $node = node_load(arg(1)); $items[] = array('path' => 'announcements/' . arg(1), 'title' => t('View an Announcement'), 'access' => node_access('view', $node), 'type' => MENU_CALLBACK, 'callback' => 'node_page'); $items[] = array('path' => 'announcements/' . arg(1) . '/view', 'title' => t('View an Announcement'), 'access' => node_access('view', $node), 'type' => MENU_CALLBACK, 'callback' => 'node_page'); $items[] = array('path' => 'announcements/' . arg(1) . '/edit', 'title' => t('Edit an Announcement'), 'access' => node_access('edit', $node), 'type' => MENU_CALLBACK, 'callback' => 'node_page'); $items[] = array('path' => 'announcements/' . arg(1) . '/delete', 'access' => node_access('delete', $node), 'type' => MENU_CALLBACK, 'callback' => 'node_delete_confirm'); } } return $items; } /** * * This function builds a themed set of links, known as the pager, to each * page of a paginated list of announcements. This is usually placed at the * bottom of each of these paginated pages. * * @return * A string of XHTML used to render the pager. * */ function announcement_pager() { $result = pager_query(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n WHERE type = 'announcement' ORDER BY n.created DESC"), variable_get('default_nodes_main', 10)); while ($announcement = db_fetch_object($result)) { $output .= node_view(node_load($announcement->nid), 1); } $output .= theme('pager', NULL, variable_get('default_nodes_main', 10)); return $output; } /** * Implementation of hook_cron(). * * This function allows the announcement module to insert its own actions when * the cron.php script is run – usually by the system cron system. This is useful * when performing periodic asynchronous tasks like, as in this case, checking to * see if any announcements have expired. * * @return * Nothing. * * More detail at http://api.drupal.org/api/HEAD/function/hook_cron * */ function announcement_cron() { // Mark expired announcements as unpublished so that non-administrative // users cannot see them on the site through standard node mechanisms $queryResult = db_query("UPDATE {node} AS n INNER JOIN {announcement} AS a ON n.nid = a.nid " . "SET n.status = 0 WHERE n.type='announcement' AND n.status = 1 AND a.expiration_date < %d", time()); } /** * Implementation of hook_link(). * * This function allows the announcement module to insert its own links * into certain parts of Drupal generated content. In this case add, edit * and delete links are added to Drupal rendered announcements depending * on the access permissions of the current user. * * @param $type * A string identifying the type of link being requested. In this case, * the links placed below an announcement node. * @param $node * The node object currently being requested. * @param $teaser * A boolean indicating if the full announcement is being displayed or * just its teaser. * @return * An array of link objects as created by the l() function. * * More detail at http://api.drupal.org/api/HEAD/function/hook_link * */ function announcement_link($type, $node = NULL, $teaser = FALSE) { global $user; $links = array(); if($type == 'node' && $node->type == 'announcement') { if(node_access('create', 'announcement')) { $links[] = l(t('Add'), "node/add/announcement", array('title' => t('Add a new announcement'))); } if(node_access('update', $node)) { $links[] = l(t('Edit'), "announcements/$node->nid/edit", array('title' => t('Edit Announcement ') . $node->title)); $links[] = l(t('Delete'), "announcements/$node->nid/delete", array('title' => t('Delete Announcement ') . $node->title)); } } return $links; } /** * Implementation of hook_settings(). * * This function provides an administrative interface for controlling * various settings for the announcement module. * * NOTE: This hook is not used in Drupal v5.* * (http://drupal.org/node/64279#hook-settings) * * @return * An array description, in the Drupal Forms API format, of the elements * to render the settings interface. * * More detail at http://api.drupal.org/api/4.7/function/hook_settings * */ function announcement_settings() { $form = array(); $form['announcement_block_max_list_count'] = array('#type' => 'textfield', '#title' => t('Maximum number of block announcements'), '#default_value' => variable_get('announcement_block_max_list_count', 3), '#description' => t('The maximum number of items listed in the announcement block'), '#required' => FALSE, '#weight' => 0 ); $form['announcement_display_classification'] = array('#type' => 'checkbox', '#title' => t('Display additional announcement classification'), '#default_value' => variable_get('announcement_display_classification', 1), '#description' => t('Insert the additional classification in the announcement modules'), '#required' => FALSE, '#weight' => 0 ); return $form; } /** * This function is called to retrieve the form that is displayed when one attempts * to "create" an announcement. */ function announcement_form(&$node) { if ($node->expiration_date == NULL) { $node->expiration_date = time() + (365 * 86400); } if ($node->publish_date == NULL) { $node->publish_date = time(); } $form['title'] = array('#type' => 'textfield', '#title' => t('Title'), '#default_value' => $node->title, '#description' => t('Title of the announcement'), '#required' => TRUE, '#weight' => 1 ); $form['publication'] = array('#type'=> 'fieldset', '#collapsible' => FALSE, '#title' => t('Publication dates'), '#weight' => 5 ); $form['publication']['publish_date'] = array( '#prefix' => '
', '#suffix' => '
', '#type' => 'date', '#title' => t('Publication date'), '#default_value' => _announcement_unixtime2drupaldate($node->publish_date) ); $form['publication']['expiration_date'] = array( '#prefix' => '
', '#suffix' => '
', '#type' => 'date', '#title' => t('Expiration date'), '#default_value' => _announcement_unixtime2drupaldate($node->expiration_date) ); $form['abstract'] = array('#type' => 'textarea', '#title' => t('Abstract'), '#default_value' => $node->abstract, '#rows' => 3, '#description' => t('Short summary of the full announcement'), '#required' => TRUE, '#weight' => 9 ); $form['body'] = array('#type' => 'textarea', '#title' => t('Body'), '#default_value' => $node->body, '#description' => t('Full content for the announcement which is shown with the abstract on the details page'), '#required' => TRUE, '#weight' => 10 ); return $form; } /** * Only show those announcements that have not expired for the average user. * If they have access to edit, show all announcements */ function announcement_all() { if (user_access('edit announcement')) { $queryResult = db_query("SELECT n.nid FROM node n INNER JOIN announcement a ON n.nid = a.nid " . "WHERE n.type='announcement' ORDER BY n.sticky DESC, A.publish_date DESC"); } else { $queryResult = db_query("SELECT n.nid FROM node n INNER JOIN announcement a ON n.nid = a.nid " . "WHERE n.type='announcement' AND a.expiration_date > %d ORDER BY n.sticky DESC, a.publish_date DESC", date("U")); } $page_content = array(); $page_content[] = "

Announcements

"; while ($announcement = db_fetch_object($queryResult)) { $announcement = node_load($announcement->nid); $announcement->url = url('announcements/' . $announcement->nid); $page_content[] = theme('announcement_compact', $announcement); } return implode('', $page_content); } /** * hook_view implementation */ function announcement_view(&$node, $teaser = FALSE, $page = FALSE) { if ($page) { $node->url = url('announcements/' . $node->nid); } } /** * hook_validate implementation * This just checks to ensure that the expiration date is after the publish date. * No node attributes are set. */ function announcement_validate($node) { if ($node) { $publish_date = _announcement_drupaldate2unixtime($node->publish_date); $expiration_date = _announcement_drupaldate2unixtime($node->expiration_date); if ($publish_date >= $expiration_date) { form_set_error('publish_date', t('The publish date of an announcement must be before its expiration date.')); } } } /** * hook_submit implementation * Prepare the node for submission into the database. * Update the date values to integer values */ function announcement_submit(&$node) { $node->publish_date = _announcement_drupaldate2unixtime($node->publish_date); $node->expiration_date = _announcement_drupaldate2unixtime($node->expiration_date); $now = time(); if($now > $node->publish_date && $now < $node->expiration_date) { $node->status = 1; } else { $node->status = 0; } $vocab = announcement_get_vocabulary_by_name('IBC'); $term = taxonomy_get_term_by_name('announcements'); $node->taxonomy = _announcement_merge_tid($vocab->vid, $term[0]->tid, $node->taxonomy); } /** * return the vocabulary object based on its name */ function announcement_get_vocabulary_by_name ($name) { $results = db_query('SELECT * FROM {vocabulary} WHERE name = "%s"', $name); if (db_num_rows($results) > 0) { return db_fetch_object($results); } else { return null; } } function _announcement_merge_tid($vid, $tid, $taxonomy) { $values = array_values($taxonomy[$vid]); // get all tid values from array for vocabulary if (!in_array($tid, $values)) { // if the tid is not there $taxonomy[] = $tid; // add it } return $taxonomy; } /** * Database hooks when loading, inserting, updating or deleting an announcement */ /** * This function is called to allow the module a chance to load extra information that * it stores about an announcement. */ function announcement_load(&$node) { $additions = db_fetch_object(db_query('SELECT * FROM {announcement} WHERE nid = %d', $node->nid)); return $additions; } /** * This function is called to allow the module to take action when a new node is * being inserted in the database. * */ function announcement_insert($node) { db_query("INSERT INTO {announcement} (nid, abstract, publish_date, expiration_date) VALUES (%d, '%s', '%d', '%d')", $node->nid, $node->abstract, $node->publish_date, $node->expiration_date); } /** * As an existing node is being updated in the database, we need to do our own * database updates, i.e., put info into announcement table. */ function announcement_update($node) { db_query("UPDATE {announcement} SET abstract='%s', publish_date = '%s', expiration_date = '%s' WHERE nid = %d", $node->abstract, $node->publish_date, $node->expiration_date, $node->nid); } /** * This function is called to allow the module to take action when a node is * being deleted from the database. */ function announcement_delete($node) { db_query('DELETE FROM {announcement} WHERE nid = %d', $node->nid); } /** * Implementation of hook_block(). */ function announcement_block($op = 'list', $delta = 0, $edit = array()) { global $user; if ($op == 'list') { $blocks[0]['info'] = t('Recently updated announcements'); $blocks[1]["info"] = t('List nodes in the IBC vocabulary'); return $blocks; } else if ($op == 'view') { $block = array(); //$output = ''; switch ($delta) { case 0: $announcement_items = array(); if (user_access('access content')) { $q = 'SELECT N.uid,N.nid,N.title,A.publish_date,N.status '. 'FROM {node} N JOIN {announcement} A USING(nid) '. "WHERE N.type='announcement' ". 'AND N.status = 1 '. 'AND A.publish_date < %d ' . 'AND A.expiration_date > %d ' . 'ORDER BY A.publish_date DESC '; $now = time(); $items = variable_get('announcement_block_max_list_count', 3); $announcements = db_query_range($q, $now, $now, 0, $items); while (db_num_rows($announcements) > 0 and $announcement = db_fetch_object($announcements)) { $announcement_items[] = $announcement; } } $block['subject'] = t('Announcements'); $block['content'] = theme('announcement_block_list', $announcement_items); break; case 1: if (user_access("access content")) { $vocabulary = announcement_get_vocabulary_by_name('IBC'); $block["subject"]= t('IBC'); $block["content"]= announcement_vocab_vert($vocabulary->vid); } } return $block; } } /** * adapated from the taxonomy_dhtml module */ function announcement_vocab_vert($vocabulary_id, $op = NULL) { $tree = taxonomy_get_tree($vocabulary_id); // build an array which holds all children of current term. necessary to build a proper 'or' value in the HREF foreach ($tree as $term) { //$url = "taxonomy/term/$term->tid/9"; $url = "taxonomy/term/$term->tid"; if ($op) { $url .= "/$op"; } $link = l(t($term->name), $url, array("title" => t($term->description))); $out .= _taxonomy_depth($term->depth, " ")."- $link"; $count = taxonomy_term_count_nodes($term->tid); if ($count) { $out .= " ($count)"; $out .= _announcement_by_terms($term->tid); } else { $out .= " (0)"; } $out .= "
"; } return $out; } /** * Show all the announcements classified by this term. */ function _announcement_by_terms($tid) { $result = ''; $tids = array( $tid ); $nodes = taxonomy_select_nodes($tids, 'or', 0, FALSE); while ($r = db_fetch_object($nodes)) { $url = "announcements/". $r->nid; $result .= "
  -  " . l($r->title, $url, array("title" => t($r->title))); } return $result; } /** * Implementation of hook_nodeapi(). * If the operation is “update index”, we want to add the abstract * of this announcement to the search index. */ function announcement_nodeapi(&$node, $op) { switch ($op) { // Add abstract field from announcement table to the search index case 'update index': if ($node->type == 'announcement') { $text = ''; $q = db_query( 'SELECT a.abstract FROM node n LEFT JOIN announcement a ON n.nid = a.nid '. 'WHERE n.nid = %d', $node->nid); if ($r = db_fetch_object($q)) { $text = $r->abstract; } return $text; } } } /* * Theme functions * * There are two theme functions: * * theme_announcement - Generic theme function that will work for all themes and theme engines * * phptemplate_annoucement - Theme function that will be used by the phptemplate engine */ function theme_announcement($announcement) { return ''; } function theme_announcement_compact($announcement) { return ''; } function theme_announcement_block_list($announcement_list) { return ''; } function phptemplate_announcement($announcement) { return _theme_phptemplate_announcement($announcement, 'announcement'); } function phptemplate_announcement_compact($announcement) { return _theme_phptemplate_announcement($announcement, 'announcement_compact'); } function phptemplate_announcement_block_list($announcement_list) { global $user; return _phptemplate_callback('announcement_block_list', array('announcements' => $announcement_list, 'user'=> $user)); } function _theme_phptemplate_announcement($announcement, $announcement_template) { $expired = FALSE; if ($announcement->expiration_date < time()) { $expired = TRUE; } $variables = array( 'title' => $announcement->title, 'body' => $announcement->body, 'links' => $announcement->links ? theme('links', $announcement->links) : '', 'abstract' => $announcement->abstract, 'published' => format_date($announcement->publish_date,'custom','j M, Y'), 'expires' => format_date($announcement->expiration_date,'custom','j M, Y'), 'exipired' => $expired, 'node' => $announcement ); return _phptemplate_callback($announcement_template, $variables); } function _announcement_drupaldate2unixtime($drupal_date) { $year = $drupal_date["year"]; $month = $drupal_date["month"]; $day = $drupal_date["day"]; return mktime(0,0,0, (int)$month, (int)$day, (int)$year); } function _announcement_unixtime2drupaldate($unixtime) { return array('day' => format_date($unixtime, 'custom', 'j'), 'month' => format_date($unixtime, 'custom', 'n'), // numeric 1-12 representation 'year' => format_date($unixtime, 'custom', 'Y')); } ?>