First commit! Woohoo! Basic status of things is in extended description.
* You can write blog posts and view them in a standard blog-like index page
* All blogs are per-user and blogs can be made public or private
* Setting permissions on a per-blog/per-post basis should work except for some inheritance issues
* Planets are not in any way implemented
* Tagging posts does not work
* Basically the only thing you can do is write and display posts and make comments. It's basic, but it works.
More to come very soon!
<?php
/*
* Nuggie
* Version 0.1
* Copyright (C) 2007 Dan Fuhry
*
* This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
*/
function nuggie_user_cp($section)
{
global $db, $session, $paths, $template, $plugins; // Common objects
if ( $section != 'Blog' )
return false;
if ( getConfig('nuggie_installed') != '1' )
{
echo '<h3>Nuggie not installed</h3>';
echo '<p>It looks like Nuggie isn\'t installed yet. You\'ll need to <a href="' . makeUrlNS('Special', 'NuggieInstall') . '">install Nuggie</a> before you can do anything more.</p>';
return true;
}
$subsection = $paths->getParam(1);
$initted = true;
$q = $db->sql_query('SELECT blog_id, blog_name, blog_subtitle, blog_type, allowed_users FROM ' . table_prefix . "blogs WHERE user_id = {$session->user_id};");
if ( !$q )
$db->_die('Nuggie User CP selecting blog info');
if ( $db->numrows() < 1 )
{
$subsection = 'Settings';
$initted = false;
}
list(, $blog_name, $blog_desc, $blog_type, $allowed_users) = $db->fetchrow_num($q);
switch($subsection)
{
case false:
case 'Home':
echo 'module Home';
break;
case 'Settings':
switch ( isset($_POST['do_save']) )
{
// We're doing this so we can break out if we need to (if form validation fails)
case true:
$errors = array();
$blog_name = trim($_POST['blog_name']);
$blog_desc = trim($_POST['blog_desc']);
$blog_access = trim($_POST['blog_access']);
$allowed_users = $_POST['allowed_users'];
if ( empty($blog_name) )
$errors[] = 'Please enter a name for your blog.';
if ( !in_array($blog_access, array('public', 'private')) )
$errors[] = 'Hacking attempt on blog_access: must be one of public, private.';
if ( count($allowed_users) > 500 )
$errors[] = 'You\'re asking that an unreasonable number of users have access to this blog. If you really have that many readers, you may want to ask the administrator of this site to make a usergroup with read access to your blog.';
if ( count($allowed_users) < 1 && $blog_access == 'private' )
$errors[] = 'Please enter at least one username that will have access to your blog. Note that your account always has access to your blog.';
if ( $blog_access == 'public' )
{
$allowed_users = 'NULL';
}
else
{
if ( is_array($allowed_users) && count($errors) < 1 )
{
$allowed_users = array_values(array_unique($allowed_users));
foreach ( $allowed_users as $i => $_ )
{
if ( empty( $allowed_users[$i] ) )
{
unset($allowed_users[$i]);
}
else
{
$allowed_users[$i] = $db->escape($allowed_users[$i]);
}
}
$fragment = "username='" . implode("' OR username='", $allowed_users) . "'";
$e = $db->sql_query('SELECT COUNT(username) AS num_valid FROM ' . table_prefix . "users WHERE $fragment;");
if ( !$e )
$db->_die('Nuggie user CP validating usernames');
$row = $db->fetchrow();
if ( intval($row['num_valid']) != count($allowed_users) )
$errors[] = 'One or more of the usernames you entered does not exist.';
}
else
{
$errors[] = 'Invalid datatype on allowed_users.';
}
}
if ( count($errors) > 0 )
{
$initted = true;
echo '<div class="error-box" style="margin: 0 0 10px 0">
<b>The following problems prevented your blog settings from being saved:</b>
<ul>
<li>
' . implode("</li>\n <li>", $errors) . '
</li>
</ul>
</div>';
break;
}
else
{
// Save changes
if ( !is_string($allowed_users) )
$allowed_users = "'" . $db->escape( serialize($allowed_users) ) . "'";
$blog_name = $db->escape($blog_name);
$blog_desc = $db->escape($blog_desc);
if ( $initted )
{
$sql = 'UPDATE ' . table_prefix . "blogs SET blog_name = '$blog_name', blog_subtitle = '$blog_desc', blog_type = '$blog_access', allowed_users = $allowed_users;";
}
else
{
$sql = 'INSERT INTO ' . table_prefix . 'blogs(blog_name, blog_subtitle, blog_type, allowed_users, user_id)' .
"\n VALUES ( '$blog_name', '$blog_desc', '$blog_access', $allowed_users, {$session->user_id} );";
}
if ( $db->sql_query($sql) )
{
echo '<div class="info-box" style="margin: 0 0 10px 0;">' .
( $initted ? 'Your changes have been saved.' : 'Your blog has been created; you can now
<a href="' . makeUrlNS('Special', 'Preferences/Blog/Write', false, true) . '">start writing some posts</a> and
then <a href="' . makeUrlNS('Blog', $session->username, false, true) . '">view your blog</a>.' )
. '</div>';
}
else
{
$db->_die('Nuggie user CP saving settings');
}
// Re-select the blog data
$db->free_result($q);
$q = $db->sql_query('SELECT blog_id, blog_name, blog_subtitle, blog_type, allowed_users FROM ' . table_prefix . "blogs WHERE user_id = {$session->user_id};");
if ( !$q )
$db->_die('Nuggie User CP selecting blog info');
list(, $blog_name, $blog_desc, $blog_type, $allowed_users) = $db->fetchrow_num($q);
}
$initted = true;
}
if ( !$initted )
{
echo '<div class="error-box" style="margin: 0 0 10px 0;">
<b>It looks like your blog isn\'t set up yet.</b><br />
You\'ll need to set up your blog by entering some basic information here before you can write any posts.
</div>';
$blog_name = htmlspecialchars($session->username) . "'s blog";
$blog_desc = '';
}
else
{
$blog_name = htmlspecialchars(strtr($blog_name, array('"' => '"')));
$blog_desc = htmlspecialchars(strtr($blog_desc, array('"' => '"')));
}
if ( !isset($blog_type) )
$blog_type = 'public';
if ( !isset($allowed_users) )
$allowed_users = serialize(array());
$form_action = makeUrlNS('Special', 'Preferences/Blog/Settings', false, true);
echo "<form action=\"$form_action\" method=\"post\" enctype=\"multipart/form-data\">";
?>
<div class="tblholder">
<table border="0" cellspacing="1" cellpadding="4">
<tr>
<th colspan="2">
<?php echo ( $initted ) ? 'Manage blog settings' : 'Create blog'; ?>
</th>
</tr>
<tr>
<td class="row2">
Blog name:
</td>
<td class="row1">
<input type="text" name="blog_name" size="60" value="<?php echo $blog_name; ?>" tabindex="1" />
</td>
</tr>
<tr>
<td class="row2">
Blog description:<br />
<small>You're best off keeping this short and sweet.</small>
</td>
<td class="row1">
<input type="text" name="blog_desc" size="60" value="<?php echo $blog_desc; ?>" tabindex="2" />
</td>
</tr>
<tr>
<td class="row2">
Blog access:
</td>
<td class="row1">
<label><input onclick="$('nuggie_allowed_users').object.style.display='none';" tabindex="3" type="radio" name="blog_access" value="public"<?php echo ( $blog_type == 'public' ) ? ' checked="checked"' : ''; ?> /> Let everyone read my blog</label><br />
<label><input onclick="$('nuggie_allowed_users').object.style.display='block';" tabindex="4" type="radio" name="blog_access" value="private"<?php echo ( $blog_type == 'private' ) ? ' checked="checked"' : ''; ?> /> Only allow the users I list below</label><br />
<small style="margin-left: 33px;">Administrators can always read all blogs, including private ones.</small>
<div id="nuggie_allowed_users"<?php echo ( $blog_type == 'public' ) ? ' style="display: none;"' : ''; ?>>
<?php
if ( $initted )
{
$allowed_users = unserialize($allowed_users);
foreach ( $allowed_users as $user )
{
echo '<input type="text" name="allowed_users[]" tabindex="5" value="' . $user . '" size="25" style="margin-bottom: 5px;" onkeyup="new AutofillUsername(this);" /><br />';
}
echo '<input type="text" name="allowed_users[]" tabindex="5" value="" size="25" style="margin-bottom: 5px;" onkeyup="new AutofillUsername(this);" /><br />';
}
else
{
?>
<input type="text" name="allowed_users[]" tabindex="5" value="" size="25" style="margin-bottom: 5px;" onkeyup="new AutofillUsername(this);" /><br />
<input type="text" name="allowed_users[]" tabindex="5" value="" size="25" style="margin-bottom: 5px;" onkeyup="new AutofillUsername(this);" /><br />
<input type="text" name="allowed_users[]" tabindex="5" value="" size="25" style="margin-bottom: 5px;" onkeyup="new AutofillUsername(this);" /><br />
<input type="text" name="allowed_users[]" tabindex="5" value="" size="25" style="margin-bottom: 5px;" onkeyup="new AutofillUsername(this);" /><br />
<input type="text" name="allowed_users[]" tabindex="5" value="" size="25" style="margin-bottom: 5px;" onkeyup="new AutofillUsername(this);" /><br />
<?php
}
?>
<input type="button" tabindex="6" onclick="var x = document.createElement('input'); x.tabindex = '5'; x.onkeyup = function() { new AutofillUsername(this); }; x.size='25'; x.style.marginBottom='5px'; x.type='text'; x.name='allowed_users[]'; $('nuggie_allowed_users').object.insertBefore(x, this); $('nuggie_allowed_users').object.insertBefore(document.createElement('br'), this); x.focus();" value="+ Add another" />
</div>
</td>
</tr>
<tr>
<th class="subhead" colspan="2">
<input tabindex="7" type="submit" name="do_save" value="<?php echo ( $initted ) ? 'Save changes' : 'Create my blog »' ?>" />
</th>
</tr>
</table>
</div>
<?php
echo '</form>';
break;
case 'Posts':
echo 'module Posts';
break;
case 'Write':
$post_text = '';
$post_title = 'Post title';
$post_id = $paths->getParam(2);
if ( isset($_POST['post_id']) )
{
$post_id = $_POST['post_id'];
}
if ( $post_id )
{
/*
* FIXME: Validate blog public/private status before sending text
* FIXME: Avoid ambiguous post_title_cleans through appending numbers when needed
*/
$post_id = intval($post_id);
$q = $db->sql_query('SELECT p.post_id, p.post_title, p.post_title_clean, p.post_author, p.post_text, p.post_timestamp, u.username '
. 'FROM ' . table_prefix . 'blog_posts AS p'
. ' LEFT JOIN ' . table_prefix . 'users AS u'
. ' ON ( p.post_author = u.user_id )'
. ' WHERE post_id = ' . $post_id . ';');
if ( !$q )
$db->_die('Nuggie user CP obtaining post info');
if ( $db->numrows() > 0 )
{
$row = $db->fetchrow();
if ( $session->user_id != $row['post_author'] )
{
// We have a possible security issue on our hands - the user is trying
// to edit someone else's post. Verify read and write permissions.
$post_page_id = "{$row['post_timestamp']}_{$row['post_id']}";
$perms = $session->fetch_page_acl($post_page_id, 'Blog');
if ( !$perms->get_permissions('read') || !$perms->get_permissions('nuggie_edit_other') )
{
echo '<h3>Post editing error</h3>';
echo '<p>You do not have permission to edit this blog post.</p>';
unset($row);
unset($row);
$db->free_result();
// Break out of this entire user CP module
return true;
}
}
else
{
$post_page_id = "{$row['post_timestamp']}_{$row['post_id']}";
$perms = $session->fetch_page_acl($post_page_id, 'Blog');
if ( !$perms->get_permissions('nuggie_edit_own') || !$perms->get_permissions('read') )
{
echo '<h3>Post editing error</h3>';
echo '<p>You do not have permission to edit this blog post.</p>';
unset($row);
unset($row);
$db->free_result();
// Break out of this entire user CP module
return true;
}
}
// We have permission - load post
$post_title = $row['post_title'];
$post_text = $row['post_text'];
}
}
if ( isset($_POST['submit']) )
{
switch($_POST['submit'])
{
case 'save_publish':
$publish = '1';
case 'save_draft':
if ( !isset($publish) )
$publish = '0';
$save_post_text = $_POST['post_text'];
$save_post_title = $db->escape($_POST['post_title']);
$save_post_title_clean = $db->escape(nuggie_sanitize_title($_POST['post_title']));
$save_post_text = RenderMan::preprocess_text($save_post_text, true, true);
if ( $post_id )
{
$sql = 'UPDATE ' . table_prefix . "blog_posts SET post_title = '$save_post_title', post_title_clean = '$save_post_title_clean', post_text = '$save_post_text', post_published = $publish WHERE post_id = $post_id;";
}
else
{
$time = time();
$sql = 'INSERT INTO ' . table_prefix . 'blog_posts ( post_title, post_title_clean, post_text, post_author, post_timestamp, post_published ) '
. "VALUES ( '$save_post_title', '$save_post_title_clean', '$save_post_text', {$session->user_id}, $time, $publish );";
}
if ( $db->sql_query($sql) )
{
echo '<div class="info-box" style="margin: 0 0 10px 0;">
' . ( $publish == '1' ? 'Your post has been published.' : 'Your post has been saved.' ) . '
</div>';
}
else
{
$db->_die('Nuggie user CP running post-save query');
}
if ( !$post_id )
{
$post_id = $db->insert_id();
}
$post_title = $_POST['post_title'];
$post_text = $_POST['post_text'];
break;
case 'preview':
$preview_text = $_POST['post_text'];
$preview_text = RenderMan::preprocess_text($preview_text, true, false);
$preview_text = RenderMan::render($preview_text);
/*
* FIXME: Use the real post renderer (when it's ready)
*/
echo '<div style="border: 1px solid #406080; background-color: #F0F0F0; margin: 0 0 10px 0; padding: 10px;
overflow: auto; max-height: 500px; clip: rect(0px, auto, auto, 0px);">';
echo '<h2>Post preview</h2>';
echo '<p style="color: red;">FIXME: This does not use the real post-display API, which is not yet implemented. Eventually this should look just like a real post.</p>';
echo '<h3>' . htmlspecialchars($_POST['post_title']) . '</h3>';
echo $preview_text;
echo '</div>';
$post_title = $_POST['post_title'];
$post_text = $_POST['post_text'];
break;
}
}
$q = $db->sql_query('SELECT post_id, post_title FROM ' . table_prefix . "blog_posts WHERE post_published = 0 AND post_author = {$session->user_id};");
if ( !$q )
$db->_die('Nuggie user CP selecting draft posts');
if ( $db->numrows() > 0 )
{
echo '<div class="mdg-infobox" style="margin: 0 0 10px 0;"><b>Your drafts:</b> ';
$posts = array();
while ( $row = $db->fetchrow() )
{
$posts[] = '<a href="' . makeUrlNS('Special', "Preferences/Blog/Write/{$row['post_id']}") . '">' . htmlspecialchars($row['post_title']) . '</a>';
}
echo implode(', ', $posts);
echo '</div>';
}
echo '<form action="' . makeUrlNS('Special', 'Preferences/Blog/Write', false, true) . '" method="post">';
$post_text = htmlspecialchars($post_text);
$post_title = strtr(htmlspecialchars($post_title), array('"' => '"'));
echo '<input type="text" name="post_title" value="' . $post_title . '" style="font-size: 16pt; margin-bottom: 10px; width: 100%;' . ( $post_title == 'Post title' ? ' color: #808080;' : '' ) . '" onfocus="if ( this.value == \'Post title\' ) { this.value = \'\'; this.style.color = null; }" onblur="if ( this.value == \'\' ) { this.value = \'Post title\'; this.style.color = \'#808080\'; } else { this.style.color = null; }" />';
echo $template->tinymce_textarea('post_text', $post_text);
// Buttons!
echo '<div style="margin-top: 10px;">';
echo '<button name="submit" value="save_draft">Save draft</button> ';
echo '<button name="submit" value="preview">Show preview</button> ';
echo '<button name="submit" value="save_publish">Publish to blog</button> ';
echo '</div>';
if ( $post_id )
{
echo '<input type="hidden" name="post_id" value="' . $post_id . '" />';
}
echo '</form>';
break;
case 'Planets':
echo 'module Planets';
break;
default:
return false;
}
return true;
}
$plugins->attachHook("userprefs_jbox", "
userprefs_menu_add('My blog', 'Manage blog settings', makeUrlNS('Special', 'Preferences/Blog/Settings'));
userprefs_menu_add('My blog', 'Manage posts', makeUrlNS('Special', 'Preferences/Blog/Posts'));
userprefs_menu_add('My blog', 'Write new post', makeUrlNS('Special', 'Preferences/Blog/Write'));
userprefs_menu_add('My blog', 'Manage my planets', makeUrlNS('Special', 'Preferences/Blog/Planets'));
\$userprefs_menu_links['My blog'] = makeUrlNS('Blog', \$session->username);
");
$plugins->attachHook("userprefs_body", "return nuggie_user_cp(\$section);");