plugins/nuggie/postbit.php
changeset 0 a09fb41e48d5
child 1 6e76ca311f2d
equal deleted inserted replaced
-1:000000000000 0:a09fb41e48d5
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * Nuggie
       
     5  * Version 0.1
       
     6  * Copyright (C) 2007 Dan Fuhry
       
     7  *
       
     8  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
       
     9  * as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
       
    10  *
       
    11  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
       
    12  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
       
    13  */
       
    14 
       
    15 /**
       
    16  * Class for displaying a Nuggie blog post.
       
    17  * @package Enano
       
    18  * @subpackage Nuggie
       
    19  */
       
    20 
       
    21 class NuggiePostbit
       
    22 {
       
    23   /**
       
    24    * The unique row ID of the post. This can be false if
       
    25    * the post is being displayed as part of a preview or
       
    26    * otherwise doesn't actually exist in the database.
       
    27    * @var int
       
    28    */
       
    29   
       
    30   var $post_id = false;
       
    31   
       
    32   /**
       
    33    * The title of the post.
       
    34    * @var string
       
    35    */
       
    36   
       
    37   var $post_title;
       
    38   
       
    39   /**
       
    40    * The cleaned title of the post. This is calculated
       
    41    * internally and need not be set.
       
    42    * @var string
       
    43    */
       
    44   
       
    45   var $post_title_clean;
       
    46   
       
    47   /**
       
    48    * Who wrote this post (user ID).
       
    49    * @var int
       
    50    */
       
    51   
       
    52   var $post_author = 1;
       
    53   
       
    54   /**
       
    55    * When the post was posted. UNIX timestamp.
       
    56    * @var int
       
    57    */
       
    58   
       
    59   var $post_timestamp = 1;
       
    60   
       
    61   /**
       
    62    * The actual content of the post.
       
    63    * @var string
       
    64    */
       
    65   
       
    66   var $post_text = '';
       
    67   
       
    68   /**
       
    69    * Whether the user can edit the post or not.
       
    70    * @var bool
       
    71    */
       
    72   
       
    73   var $auth_edit = false;
       
    74   
       
    75   /**
       
    76    * The number of comments on the post
       
    77    * @var int
       
    78    */
       
    79   
       
    80   var $num_comments = 0;
       
    81   
       
    82   /**
       
    83    * The master permission set for the blog. Only used during pagination, don't worry about this
       
    84    * @var object
       
    85    */
       
    86   
       
    87   var $blog_perms;
       
    88   
       
    89   /**
       
    90    * Renders the post.
       
    91    */
       
    92   
       
    93   function render_post()
       
    94   {
       
    95     global $db, $session, $paths, $template, $plugins; // Common objects
       
    96     
       
    97     if ( file_exists( ENANO_ROOT . "/themes/{$template->theme_id}/blog_post.tpl" ) )
       
    98     {
       
    99       $parser = $template->makeParser('blog_post.tpl');
       
   100     }
       
   101     else
       
   102     {
       
   103       $tpl_code = <<<TPLBLOCK
       
   104 
       
   105       <!-- Start of blog post -->
       
   106       
       
   107       <div class="blog-post">
       
   108         <div class="blog-post-header">
       
   109           <div class="blog-post-datemark">
       
   110             {DATE_D} {DATE_j}<br />
       
   111             {DATE_M} {DATE_Y}
       
   112           </div>
       
   113           <h3><a href="{PERMALINK}">{POST_TITLE}</a></h3>
       
   114           <div class="blog-post-author">
       
   115             Posted by {USER_LINK} on {TIMESTAMP}
       
   116           </div>
       
   117           <div class="blog-post-buttons">
       
   118           <a href="{PERMALINK}#do:comments" onclick="ajaxComments();">{COMMENT_STRING}</a>
       
   119           <!-- BEGIN auth_edit -->
       
   120           &bull;
       
   121           <a href="{EDIT_LINK}">Edit this post</a>
       
   122           <!-- END auth_edit -->
       
   123           </div>
       
   124         </div>
       
   125         <div class="blog-post-body">
       
   126           {POST_TEXT}
       
   127         </div>
       
   128       </div>
       
   129       
       
   130       <!-- Finish blog post -->
       
   131       
       
   132 TPLBLOCK;
       
   133       $parser = $template->makeParserText($tpl_code);
       
   134     }
       
   135     
       
   136     $this->post_title_clean = nuggie_sanitize_title($this->post_title);
       
   137     
       
   138     // List of valid characters for date()
       
   139     $date_chars = 'dDjlNSwzWFmMntLoYyaABgGhHiseIOTZcrU';
       
   140     $date_chars = enano_str_split($date_chars);
       
   141     
       
   142     $strings = array();
       
   143     foreach ( $date_chars as $char )
       
   144     {
       
   145       $strings["DATE_$char"] = date($char, $this->post_timestamp);
       
   146     }
       
   147     
       
   148     $strings['POST_TITLE'] = htmlspecialchars($this->post_title);
       
   149     $strings['POST_TEXT'] = RenderMan::render($this->post_text);
       
   150     $strings['PERMALINK'] = makeUrlNS('Blog', $this->post_author . date('/Y/n/j/', $this->post_timestamp) . $this->post_title_clean, false, true);
       
   151     $strings['EDIT_LINK'] = makeUrlNS('Special', "Preferences/Blog/Write/{$this->post_id}", false, true);
       
   152     
       
   153     if ( $this->num_comments == 0 )
       
   154       $comment_string = 'No comments';
       
   155     else if ( $this->num_comments == 1 )
       
   156       $comment_string = '1 comment';
       
   157     else
       
   158       $comment_string = intval($this->num_comments) . ' comments';
       
   159       
       
   160     $strings['COMMENT_STRING'] = $comment_string;
       
   161     $strings['TIMESTAMP'] = date('l, F j, Y \a\t h:i <\s\m\a\l\l>A</\s\m\a\l\l>', $this->post_timestamp);
       
   162     
       
   163     $parser->assign_vars($strings);
       
   164     $parser->assign_bool(array(
       
   165         'auth_edit' => ( $this->auth_edit )
       
   166       ));
       
   167     
       
   168     return $parser->run();
       
   169   }
       
   170   /**
       
   171    * Don't worry about this, it's only called from the paginator.
       
   172    * @access private
       
   173    */
       
   174    
       
   175   function paginate_handler($_, $row)
       
   176   {
       
   177     global $db, $session, $paths, $template, $plugins; // Common objects
       
   178     
       
   179     if ( !is_object($this->blog_perms) )
       
   180     {
       
   181       $this->blog_perms = $session->fetch_page_acl($row['username'], 'Blog');
       
   182     }
       
   183     
       
   184     $perms = $session->fetch_page_acl("{$row['post_timestamp']}_{$row['post_id']}", 'Blog');
       
   185     $perms->perms = $session->acl_merge($this->blog_perms->perms, $perms->perms);
       
   186     
       
   187     /*
       
   188     if ( !$perms->get_permissions('read') )
       
   189     {
       
   190       return "POST {$this->post_id} DENIED";
       
   191     }
       
   192     */
       
   193     
       
   194     $this->post_id = intval($row['post_id']);
       
   195     $this->post_title = $row['post_title'];
       
   196     $this->post_text = $row['post_text'];
       
   197     $this->post_author = $row['username'];
       
   198     $this->post_timestamp = intval($row['post_timestamp']);
       
   199     $this->num_comments = intval($row['num_comments']);
       
   200     
       
   201     return $this->render_post();
       
   202   }
       
   203 }
       
   204 
       
   205 function nuggie_blog_uri_handler($uri)
       
   206 {
       
   207   global $db, $session, $paths, $template, $plugins; // Common objects
       
   208   $template->add_header('<link rel="stylesheet" type="text/css" href="' . scriptPath . '/plugins/nuggie/style.css" />');
       
   209   if ( strstr($uri, '/') )
       
   210   {
       
   211     //
       
   212     // Permalinked post
       
   213     //
       
   214     
       
   215     // Split and parse URI
       
   216     $particles = explode('/', $uri);
       
   217     if ( count($particles) < 5 )
       
   218       return false;
       
   219     $sz = count($particles);
       
   220     for ( $i = 5; $i < $sz; $i++ )
       
   221     {
       
   222       $particles[4] .= '/' . $particles[$i];
       
   223       unset($particles[$i]);
       
   224     }
       
   225     
       
   226     $particles[4] = nuggie_sanitize_title($particles[4]);
       
   227     $poster =& $particles[0];
       
   228     $year =& $particles[1];
       
   229     $month =& $particles[2];
       
   230     $day =& $particles[3];
       
   231     $post_title_clean =& $particles[4];
       
   232     
       
   233     $particlecomp = $db->escape(implode('/', $particles));
       
   234     
       
   235     $year = intval($year);
       
   236     $month = intval($month);
       
   237     $day = intval($day);
       
   238     
       
   239     $time_min = mktime(0, 0, 0, $month, $day, $year);
       
   240     $time_max = $time_min + 86400;
       
   241     
       
   242     $ptc = $db->escape($post_title_clean);
       
   243     $uname = $db->escape(dirtify_page_id($poster));
       
   244     
       
   245     $q = $db->sql_query("SELECT p.post_id, p.post_title, p.post_title_clean, p.post_author, p.post_timestamp, p.post_text, b.blog_name,\n"
       
   246                       . "       b.blog_subtitle, b.blog_type, b.allowed_users, u.username, u.user_level, COUNT(c.comment_id) AS num_comments\n"
       
   247                       . "      FROM " . table_prefix . "blog_posts AS p\n"
       
   248                       . "  LEFT JOIN " . table_prefix . "blogs AS b\n"
       
   249                       . "    ON ( b.user_id = p.post_author )\n"
       
   250                       . "  LEFT JOIN " . table_prefix . "users AS u\n"
       
   251                       . "    ON ( u.user_id = p.post_author )\n"
       
   252                       . "  LEFT JOIN " . table_prefix . "comments AS c\n"
       
   253                       . "    ON ( ( c.page_id = '{$particlecomp}' AND c.namespace = 'Blog' ) OR ( c.page_id IS NULL AND c.namespace IS NULL ) )\n"
       
   254                       . "  WHERE p.post_timestamp >= $time_min AND p.post_timestamp <= $time_max\n"
       
   255                       . "    AND p.post_title_clean = '$ptc' AND u.username = '$uname'\n"
       
   256                       . "  GROUP BY p.post_id;");
       
   257     if ( !$q )
       
   258       $db->_die('Nuggie post handler selecting main post data');
       
   259     
       
   260     if ( $db->numrows() < 1 )
       
   261       return false;
       
   262     
       
   263     if ( $db->numrows() > 1 )
       
   264     {
       
   265       die_friendly('Ambiguous blog posts', '<p>FIXME: You have two posts with the same title posted on the same day by the same user. I was
       
   266                                                not able to distinguish which post you wish to view.</p>');
       
   267     }
       
   268     
       
   269     $row = $db->fetchrow();
       
   270     
       
   271     //
       
   272     // Determine permissions
       
   273     //
       
   274     
       
   275     // The way we're doing this is first fetching permissions for the blog, and then merging them
       
   276     // with permissions specific to the post. This way the admin can set custom permissions for the
       
   277     // entire blog, and they'll be inherited unless individual posts have overriding permissions.
       
   278     $perms_blog = $session->fetch_page_acl($row['username'], 'Blog');
       
   279     $perms = $session->fetch_page_acl("{$row['post_timestamp']}_{$row['post_id']}", 'Blog');
       
   280     $perms->perms = $session->acl_merge($perms->perms, $perms_post->perms);
       
   281     unset($perms_blog);
       
   282     
       
   283     if ( $row['blog_type'] == 'private' )
       
   284     {
       
   285       $allowed_users = unserialize($row['allowed_users']);
       
   286       if ( !in_array($session->username, $allowed_users) && !$perms->get_permissions('nuggie_see_non_public') && $row['username'] != $session->username )
       
   287       {
       
   288         return '_err_access_denied';
       
   289       }
       
   290     }
       
   291     
       
   292     $acl_type = ( $row['post_author'] == $session->user_id ) ? 'nuggie_edit_own' : 'nuggie_edit_other';
       
   293     
       
   294     if ( !$perms->get_permissions('read') )
       
   295       return '_err_access_denied';
       
   296     
       
   297     // We're validated - display post
       
   298     $postbit = new NuggiePostbit();
       
   299     $postbit->post_id = intval($row['post_id']);
       
   300     $postbit->post_title = $row['post_title'];
       
   301     $postbit->post_text = $row['post_text'];
       
   302     $postbit->post_author = $row['username'];
       
   303     $postbit->post_timestamp = intval($row['post_timestamp']);
       
   304     $postbit->auth_edit = $perms->get_permissions($acl_type);
       
   305     $postbit->num_comments = intval($row['num_comments']);
       
   306     
       
   307     $template->tpl_strings['PAGE_NAME'] = htmlspecialchars($row['post_title']) . ' &laquo; ' . htmlspecialchars($row['blog_name']);
       
   308     
       
   309     $template->header();
       
   310     echo '&lt; <a href="' . makeUrlNS('Blog', $row['username']) . '">' . htmlspecialchars($row['blog_name']) . '</a>';
       
   311     echo $postbit->render_post();
       
   312     $template->footer();
       
   313     
       
   314     return true;
       
   315   }
       
   316   else
       
   317   {
       
   318     return nuggie_blog_index($uri);
       
   319   }
       
   320 }
       
   321 
       
   322 function nuggie_blog_index($username)
       
   323 {
       
   324   global $db, $session, $paths, $template, $plugins; // Common objects
       
   325   
       
   326   $username_esc = $db->escape($username);
       
   327   
       
   328   // First look for the user's blog so we can get permissions
       
   329   $q = $db->sql_query('SELECT b.blog_type, b.allowed_users, b.user_id, b.blog_name, b.blog_subtitle FROM ' . table_prefix . "blogs AS b LEFT JOIN " . table_prefix . "users AS u ON ( u.user_id = b.user_id ) WHERE u.username = '$username_esc';");
       
   330   if ( !$q )
       
   331     $db->_die('Nuggie main blog page doing preliminary security check');
       
   332   
       
   333   if ( $db->numrows() < 1 )
       
   334     return false;
       
   335   
       
   336   list($blog_type, $allowed_users, $user_id, $blog_name, $blog_subtitle) = $db->fetchrow_num();
       
   337   $db->free_result();
       
   338   
       
   339   $perms = $session->fetch_page_acl($username, 'Blog');
       
   340   
       
   341   if ( $blog_type == 'private' )
       
   342   {
       
   343     $allowed_users = unserialize($allowed_users);
       
   344     if ( !in_array($session->username, $allowed_users) && !$perms->get_permissions('nuggie_see_non_public') && $username != $session->username )
       
   345     {
       
   346       return '_err_access_denied';
       
   347     }
       
   348   }
       
   349   
       
   350   // Determine number of posts and prefetch ACL info
       
   351   $q = $db->sql_query('SELECT post_timestamp, post_id FROM ' . table_prefix . 'blog_posts WHERE post_author = ' . $user_id . ' AND post_published = 1;');
       
   352   if ( !$q )
       
   353     $db->_die('Nuggie main blog page doing rowcount of blog posts');
       
   354   
       
   355   $count = $db->numrows();
       
   356   
       
   357   while ( $row = $db->fetchrow($q) )
       
   358   {
       
   359     $session->fetch_page_acl("{$row['post_timestamp']}_{$row['post_id']}", 'Blog');
       
   360   }
       
   361   
       
   362   $db->free_result($q);
       
   363   
       
   364   $q = $db->sql_unbuffered_query("SELECT p.post_id, p.post_title, p.post_title_clean, p.post_author, p.post_timestamp, p.post_text, b.blog_name,\n"
       
   365                     . "       b.blog_subtitle, u.username, u.user_level, COUNT(c.comment_id) AS num_comments\n"
       
   366                     . "      FROM " . table_prefix . "blog_posts AS p\n"
       
   367                     . "  LEFT JOIN " . table_prefix . "blogs AS b\n"
       
   368                     . "    ON ( b.user_id = p.post_author )\n"
       
   369                     . "  LEFT JOIN " . table_prefix . "users AS u\n"
       
   370                     . "    ON ( u.user_id = p.post_author )\n"
       
   371                     . "  LEFT JOIN " . table_prefix . "comments AS c\n"
       
   372                     . "    ON ( ( c.page_id REGEXP CONCAT('([0-9]+)/([0-9]+)/([0-9]+)/', p.post_title_clean) AND c.namespace = 'Blog' ) OR ( c.page_id IS NULL AND c.namespace IS NULL ) )\n"
       
   373                     . "  WHERE p.post_author = $user_id AND p.post_published = 1\n"
       
   374                     . "  GROUP BY p.post_id\n"
       
   375                     . "  ORDER BY p.post_timestamp DESC;");
       
   376   if ( !$q )
       
   377     $db->_die('Nuggie main blog page selecting the whole shebang');
       
   378     
       
   379   if ( $count < 1 )
       
   380   {
       
   381     // Either the user hasn't created a blog yet, or he isn't even registered
       
   382     return false;
       
   383   }
       
   384   
       
   385   $template->tpl_strings['PAGE_NAME'] = htmlspecialchars($blog_name) . ' &raquo; ' . htmlspecialchars($blog_subtitle);
       
   386   
       
   387   $postbit = new NuggiePostbit();
       
   388   // $q, $tpl_text, $num_results, $result_url, $start = 0, $perpage = 10, $callers = Array(), $header = '', $footer = ''
       
   389   $html = paginate(
       
   390       $q,
       
   391       '{post_id}',
       
   392       $count,
       
   393       makeUrlNS('Blog', $username, "start=%s", true),
       
   394       0,
       
   395       10,
       
   396       array( 'post_id' => array($postbit, 'paginate_handler') ),
       
   397       '<span class="menuclear"></span>'
       
   398     );
       
   399   
       
   400   $template->header();
       
   401   
       
   402   echo $html;
       
   403   
       
   404   $template->footer();
       
   405   
       
   406   return true;
       
   407 }
       
   408 
       
   409 ?>