add('name', PLUGIN_KARMA_NAME);
$propbag->add('description', PLUGIN_KARMA_BLAHBLAH);
$propbag->add('stackable', false);
$propbag->add('author', 'Garvin Hicking, Grischa Brockhaus, Judebert, Gregor Voeltz');
$propbag->add('version', '2.10');
$propbag->add('requirements', array(
'serendipity' => '0.8',
'smarty' => '2.6.7',
'php' => '4.1.0'
));
$propbag->add('event_hooks', array(
'external_plugin' => true,
'frontend_footer' => true,
'frontend_configure' => true,
'entry_display' => true,
'css' => true,
'backend_header' => true,
'backend_sidebar_admin_appearance' => true,
'backend_sidebar_entries_event_display_karmalog' => true,
'event_additional_statistics' => true
));
$propbag->add('groups', array('STATISTICS'));
$propbag->add('configuration', array(
// Functionality options
'karma_active',
'karma_active_registered',
'extended_only',
'max_karmatime',
'max_votetime',
'max_entrytime',
'min_disp_votes',
'visits_active',
'track_visits_of_loggedin_users',
'min_disp_visits',
'exits_active',
'logging',
'ajax',
// Appearance options
'alignment',
'rate_with_words',
'textual_msg',
'textual_current',
'textual_visits',
'preview_bg',
'base_image',
// Text/Language options
'rate_msg',
'curr_msg',
'rate_best',
'rate_good',
'rate_okay',
'rate_poor',
'rate_vile',
'text_best',
'text_good',
'text_okay',
'text_poor',
'text_vile',
));
$propbag->add('config_groups', array(
PLUGIN_KARMA_TAB_OPTIONS => array(
'karma_active',
'karma_active_registered',
'extended_only',
'max_karmatime',
'max_votetime',
'max_entrytime',
'min_disp_votes',
'visits_active',
'track_visits_of_loggedin_users',
'min_disp_visits',
'exits_active',
'logging',
'ajax',
),
PLUGIN_KARMA_TAB_APPEARANCE => array(
'alignment',
'rate_with_words',
'textual_msg',
'textual_current',
'textual_visits',
'preview_bg',
'base_image',
),
PLUGIN_KARMA_TAB_TEXT => array(
'rate_msg',
'curr_msg',
'rate_best',
'rate_good',
'rate_okay',
'rate_poor',
'rate_vile',
'text_best',
'text_good',
'text_okay',
'text_poor',
'text_vile',
)
));
}
function introspect_config_item($name, &$propbag)
{
switch($name) {
// Oldest entry age still valid for unrestricted voting
case 'max_entrytime':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_ENTRYTIME);
$propbag->add('description', PLUGIN_KARMA_ENTRYTIME_BLAHBLAH);
$propbag->add('default', 1440);
break;
// Min time between votes
case 'max_votetime':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTINGTIME);
$propbag->add('description', PLUGIN_KARMA_VOTINGTIME_BLAHBLAH);
$propbag->add('default', 5);
break;
// Oldest entry age still valid for karma voting (normal, restricted voting)
case 'max_karmatime':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_MAXKARMA);
$propbag->add('description', PLUGIN_KARMA_MAXKARMA_BLAHBLAH);
$propbag->add('default', 7);
break;
// Is karma voting allowed?
case 'karma_active':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_ACTIVE);
$propbag->add('description', PLUGIN_KARMA_ACTIVE_BLAHBLAH);
$propbag->add('default', 'true');
break;
// Is karma voting allowed only for registered authors?
case 'karma_active_registered':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_ACTIVE_REGISTERED);
$propbag->add('description', '');
$propbag->add('default', 'false');
break;
// Min votes to display
case 'min_disp_votes':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_MIN_DISPLAYABLE_VOTES);
$propbag->add('description', PLUGIN_KARMA_MIN_DISPLAYABLE_VOTES_BLAHBLAH);
$propbag->add('default', '0');
break;
// Is extended article visit tracking allowed?
case 'visits_active':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_VISITS);
$propbag->add('description', PLUGIN_KARMA_VISITS_BLAHBLAH);
$propbag->add('default', 'true');
break;
// Keep or ignore visits for logged in users (like admins/authors)?
case 'track_visits_of_loggedin_users':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_VISITS_LOGGEDIN_USERS);
$propbag->add('description', PLUGIN_KARMA_VISITS_LOGGEDIN_USERS_BLAHBLAH);
$propbag->add('default', 'true');
break;
// Min visits to display
case 'min_disp_visits':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_MIN_DISPLAYABLE_VISITS);
$propbag->add('description', PLUGIN_KARMA_MIN_DISPLAYABLE_VISITS_BLAHBLAH);
$propbag->add('default', '0');
break;
// Are we tracking exits?
case 'exits_active':
$propbag->add('type', 'boolean');
$propbag->add('name', SHOWS_TOP_EXIT);
$propbag->add('description', '');
$propbag->add('default', 'false');
break;
// Show karma voting on article summary, or only extended page?
case 'extended_only':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_EXTENDEDONLY);
$propbag->add('description', PLUGIN_KARMA_EXTENDEDONLY_BLAHBLAH);
$propbag->add('default', 'false');
break;
// Log karma votes?
case 'logging':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_LOGGING);
$propbag->add('description', PLUGIN_KARMA_LOGGING_BLAHBLAH);
$propbag->add('default', 'false');
break;
// Log karma votes?
case 'ajax':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_AJAX);
$propbag->add('description', PLUGIN_KARMA_AJAX_BLAHBLAH);
$propbag->add('default', 'false');
break;
// Alignment to use for rating bars
case 'alignment':
$select = array(
'left' => LEFT,
'center' => CENTER,
'right' => RIGHT);
$propbag->add('type', 'select');
$propbag->add('name', PLUGIN_KARMA_ALIGNMENT);
$propbag->add('description', PLUGIN_KARMA_ALIGNMENT_BLAHBLAH);
$propbag->add('select_values', $select);
$propbag->add('default', 'right');
break;
// Use words for ratings?
case 'rate_with_words':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_WORDRATING);
$propbag->add('description', PLUGIN_KARMA_WORDRATING_BLAHBLAH);
$propbag->add('default', 'false');
break;
case 'textual_msg':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_IMAGE_WITH_MESSAGE);
$propbag->add('description', PLUGIN_KARMA_IMAGE_WITH_MESSAGE_BLAHBLAH);
$propbag->add('default', 'true');
break;
case 'textual_current':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_IMAGE_WITH_CURR);
$propbag->add('description', PLUGIN_KARMA_IMAGE_WITH_CURR_BLAHBLAH);
$propbag->add('default', 'true');
break;
case 'textual_visits':
$propbag->add('type', 'boolean');
$propbag->add('name', PLUGIN_KARMA_IMAGE_WITH_VISITS);
$propbag->add('description', PLUGIN_KARMA_IMAGE_WITH_VISITS_BLAHBLAH);
$propbag->add('default', 'true');
break;
// Background of admin preview table
case 'preview_bg':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_PREVIEW_BG);
$propbag->add('description', PLUGIN_KARMA_PREVIEW_BG_BLAHBLAH);
$propbag->add('default', '');
break;
// Image to use for graphical rating bar
case 'base_image':
$propbag->add('type', 'content');
$propbag->add('default', $this->createRatingSelector());
break;
case 'rate_msg':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTETEXT_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTETEXT_NAME_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTETEXT);
break;
case 'curr_msg':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_CURRENT_NAME);
$propbag->add('description', PLUGIN_KARMA_CURRENT_NAME_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_CURRENT);
break;
case 'rate_best':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTEPOINT_5_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTEPOINT_5_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTEPOINT_5);
break;
case 'rate_good':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTEPOINT_4_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTEPOINT_4_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTEPOINT_4);
break;
case 'rate_okay':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTEPOINT_3_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTEPOINT_3_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTEPOINT_3);
break;
case 'rate_poor':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTEPOINT_2_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTEPOINT_2_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTEPOINT_2);
break;
case 'rate_vile':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTEPOINT_1_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTEPOINT_1_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTEPOINT_1);
break;
case 'text_best':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTETEXT_5_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTETEXT_5_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTETEXT_5);
break;
case 'text_good':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTETEXT_4_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTETEXT_4_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTETEXT_4);
break;
case 'text_okay':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTETEXT_3_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTETEXT_3_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTETEXT_3);
break;
case 'text_poor':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTETEXT_2_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTETEXT_2_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTETEXT_2);
break;
case 'text_vile':
$propbag->add('type', 'string');
$propbag->add('name', PLUGIN_KARMA_VOTETEXT_1_NAME);
$propbag->add('description', PLUGIN_KARMA_VOTETEXT_1_BLAHBLAH);
$propbag->add('default', PLUGIN_KARMA_VOTETEXT_1);
break;
default:
return false;
}
return true;
}
/**
* Updates database schema when upgrading from older versions.
*/
function checkScheme() {
global $serendipity;
$version = $this->get_config('dbversion', '0');
if ($version == "2.1") {
$q = "ALTER TABLE {$serendipity['dbPrefix']}karmalog ADD votetime INT(11) default null";
$sql = serendipity_db_schema_import($q);
$this->set_config('dbversion', PLUGIN_KARMA_DB_VERSION);
} elseif ($version == '2.0') {
$q = "ALTER TABLE {$serendipity['dbPrefix']}karmalog CHANGE COLUMN ip ip VARCHAR(45)";
$sql = serendipity_db_schema_import($q);
$this->set_config('dbversion', PLUGIN_KARMA_DB_VERSION);
} elseif ($version == '1.1') {
$q = "ALTER TABLE {$serendipity['dbPrefix']}karma ADD visits INT(11) default 0";
$sql = serendipity_db_schema_import($q);
$this->set_config('dbversion', PLUGIN_KARMA_DB_VERSION);
} elseif ($version == '1.0') {
$q = "ALTER TABLE {$serendipity['dbPrefix']}karma ADD visits INT(11) default 0";
$sql = serendipity_db_schema_import($q);
$q = "CREATE TABLE {$serendipity['dbPrefix']}karmalog (
entryid int(11) default null,
points int(4) default null,
ip varchar(45),
user_agent varchar(255),
votetime int(11) default null
)";
$sql = serendipity_db_schema_import($q);
$this->set_config('dbversion', PLUGIN_KARMA_DB_VERSION);
} elseif ($version != PLUGIN_KARMA_DB_VERSION) {
$q = "CREATE TABLE {$serendipity['dbPrefix']}karma (
entryid int(11) default null,
points int(4) default null,
votes int(4) default null,
lastvote int(10) {UNSIGNED} NULL,
visits int(11) default null
)";
$sql = serendipity_db_schema_import($q);
$q = "CREATE TABLE {$serendipity['dbPrefix']}karmalog (
entryid int(11) default null,
points int(4) default null,
ip varchar(45),
user_agent varchar(255),
votetime int(11) default null
)";
$sql = serendipity_db_schema_import($q);
$q = "CREATE INDEX kfetch ON {$serendipity['dbPrefix']}karma (entryid, lastvote);";
$sql = serendipity_db_schema_import($q);
$q = "CREATE INDEX kentryid ON {$serendipity['dbPrefix']}karma (entryid);";
$sql = serendipity_db_schema_import($q);
$this->set_config('dbversion', PLUGIN_KARMA_DB_VERSION);
}
return true;
}
/**
* Unused; would create sidebar content.
*/
function generate_content(&$title)
{
$title = $this->title;
}
/**
* Creates an array of entries and their exit counts.
*
* @param array entries The entries to get exit counts for
* @param boolean get optional Whether to return the array (otherwise
* does all the calculations, but returns only true) default:false
*
* @return Boolean true when $get is false; otherwise the array of
* entries with their exit counts.
*/
function prepareExits($entries, $get = false) {
static $exits = null;
global $serendipity;
if ($exits === null) {
$q = 'SELECT entry_id, SUM(count) AS exits
FROM ' . $serendipity['dbPrefix'] . 'exits
WHERE entry_id IN (' . implode(', ', $entries) . ') GROUP BY entry_id';
$sql = serendipity_db_query($q);
$exits = array();
if (is_array($sql)) {
foreach($sql AS $idx => $row) {
$exits[$row['entry_id']] = (int)$row['exits'];
}
}
}
if ($get) {
return $exits[$entries];
}
return true;
}
function getExits($entryid, $get_prepared = false) {
global $serendipity;
static $karma_exits = null;
if ($karma_exits === null) {
$karma_exits = ' | ' . TOP_EXITS . ' (%d)';
}
if ($get_prepared) {
$points = $this->prepareExits($entryid, true);
} else {
$res = serendipity_db_query("SELECT sum(count) AS exits FROM {$serendipity['dbPrefix']}exits WHERE entry_id = " . (int)$entryid . " GROUP BY entry_id", true, 'assoc');
if (is_array($res) && isset($res['exits'])) {
$points = $res['exits'];
} else {
$points = 0;
}
}
return sprintf($karma_exits, $points);
}
function performkarmaVote() {
global $serendipity;
// Make sure the karmaVote cookie is set, even if empty
if (!isset($serendipity['COOKIE']['karmaVote'])) {
serendipity_setCookie('karmaVote', serialize(array()));
}
// If user didn't vote, we're done.
// Do we realy need this?
if (!isset($_POST['karmaId'])) {
if (!isset($serendipity['GET']['karmaId']) || !isset($serendipity['GET']['karmaVote'])) {
return;
}
}
// Get URL vote data
if (isset($_POST['karmaId'])) {
$this->karmaId = (int)$_POST['karmaId'];
$this->karmaVoting = (int)$_POST['karmaVote'];
} else {
$this->karmaId = (int)$serendipity['GET']['karmaId'];
$this->karmaVoting = (int)$serendipity['GET']['karmaVote'];
}
// karmaVote cookie was just set (see name="#1"); this boils down to
// "if check cookie isn't 1, there's no real cookie".
// The check cookie gets set when a rater is displayed,
// so you've got no business voting if you haven't even
// seen the rater yet.
if (!isset($serendipity['COOKIE']['karmaVote']) OR $serendipity['COOKIE']['check'] != '1') {
$this->karmaVote = 'nocookie';
return;
}
// Everything is ready. Get the cookie vote data.
$karma = unserialize($serendipity['COOKIE']['karmaVote']);
// Stop on invalid votes (cookie invalid, or URL data incorrect)
if (!is_array($karma) || !is_numeric($this->karmaVoting) || !is_numeric($this->karmaId) || $this->karmaVoting > 2 || $this->karmaVoting < -2) {
$this->karmaVote = 'invalid1';
return;
}
// Stop if the cookie says we already voted
if (!empty($karma[$this->karmaId])) {
$this->karmaVote = 'alreadyvoted';
return ;
}
// We don't want bots hitting the karma-voting
$agent = $_SERVER['HTTP_USER_AGENT'];
if (stristr($agent, 'google')
|| stristr($agent, 'LinkWalker')
|| stristr($agent, 'zermelo')
|| stristr($agent, 'NimbleCrawler')
|| stristr($agent, 'archive.org_bot')) {
$this->karmaVote = 'invalid1';
return ;
}
// Voting takes place here.
//
// Get voting data from the database (keeps all entries,
// even if no karma match)
$q = 'SELECT *
FROM ' . $serendipity['dbPrefix'] . 'entries AS e
LEFT OUTER JOIN ' . $serendipity['dbPrefix'] . 'karma AS k
ON e.id = k.entryid
WHERE e.id = ' . serendipity_db_escape_string($this->karmaId) . ' LIMIT 1';
$row = serendipity_db_query($q, true);
// If there's no entry with this ID, we're done
//
// --TODO: Modify the plugin to allow arbitrary voting with generated IDs
if (!isset($row) || !is_array($row)) {
$this->karmaVote = 'invalid2';
return;
}
$now = time();
if ($row['votes'] === '0' || $row['votes'] > 0) {
// Votes for this entry already exist. Do some checking.
$max_entrytime = $this->get_config('max_entrytime', 1440) * 60;
$max_votetime = $this->get_config('max_votetime', 5) * 60;
$max_karmatime = $this->get_config('max_karmatime', 7) * 24 * 60 * 60;
// Allow infinite voting when 0 or negative
if ($max_karmatime <= 0) {
$max_karmatime = $now;
}
// If the entry's timestamp is too old for voting,
// we're done.
if ($row['timestamp'] < ($now - $max_karmatime)) {
$this->karmaVote = 'timeout2';
return;
}
// If the entry is in the grace period, or votes
// aren't too close together, record the vote.
if (($row['timestamp'] > ($now - $max_entrytime)) || ($row['lastvote'] + $max_votetime < $now) || $row['lastvote'] == 0) {
// Update votes
$q = sprintf(
"UPDATE {$serendipity['dbPrefix']}karma
SET points = %s,
votes = %s,
lastvote = %s
WHERE entryid = %s",
$row['points'] + $this->karmaVoting,
$row['votes'] + 1,
$now,
$this->karmaId
);
serendipity_db_query($q);
} else {
// Entry was too recently voted upon. Figure out
// how long until voting will be allowed (in minutes).
$this->karmaVote = 'timeout';
$this->karmaTimeOut = abs(ceil(($now - ($row['lastvote'] + $max_votetime)) / 60));
return;
}
} else {
// No row. Use INSERT instead of UPDATE.
$q = sprintf(
"INSERT INTO {$serendipity['dbPrefix']}karma
(entryid, points, votes, lastvote, visits)
VALUES (%s, %s, %s, %s, %s)",
$this->karmaId,
$this->karmaVoting,
1,
$now,
0
);
$sql = serendipity_db_query($q);
}
// Log the vote
if (serendipity_db_bool($this->get_config('logging', false))) {
$q = sprintf(
"INSERT INTO {$serendipity['dbPrefix']}karmalog
(entryid, points, ip, user_agent, votetime)
VALUES (%s, %s, '%s', '%s', %s)",
$this->karmaId,
$this->karmaVoting,
serendipity_db_escape_string($_SERVER['REMOTE_ADDR']),
substr(serendipity_db_escape_string($_SERVER['HTTP_USER_AGENT']), 0, 255),
$now
);
$sql = serendipity_db_query($q);
if (is_string($sql)) {
mail($serendipity['serendipityEmail'] , 'KARMA ERROR', $q . '
' . $sql . '
');
}
}
// Set the cookie that we already voted for this entry
$karma[$this->karmaId] = $this->karmaVoting;
$this->karmaVote = 'voted';
serendipity_setCookie('karmaVote', serialize($karma));
}
function karmaVoted($myvote,$points,$votes) {
$msg = '
\n"); print_r(htmlspecialchars($karma_block)); print("\n\n"); */ // Substitute the % stuff and add it to the footer $eventData[$i]['properties']['myvote'] = $myvote; $eventData[$i]['properties']['points'] = $points; $eventData[$i]['properties']['votes'] = $votes; $eventData[$i]['properties']['visits'] = $visits; $footer .= sprintf($karma_block, $myvote, $points, $votes, $visits, $url); } // foreach key in entries }// End switch on karma voting status return true; break; // Display the Karma Log link on the sidebar case 'backend_sidebar_admin_appearance': ?>
" . PLUGIN_KARMA_STATISTICS_POINTS_NO . " $bar | \n";
$this->select_css .= "
.textbar, .textbar a, .textbar a:hover {
font-size: 100%;
position: relative;
background: none;
}
.serendipityAdminContent span.textbar {
color: black !important;
}
";
// Retrieve all the *valid* images from the image directory
$files = $this->getImageFiles();
// Add an ||
$fname \n" . $this->createRatingBar('', -1, 2, $css_class) . " | \n";
$bar_html = sprintf($bar_html, '', '2.5 of 5', '1');
$this->select_html .= $bar_html;
// Add the necessary CSS to the stylesheet (will be added when css hooks are called)
// Sorry to interrupt your regularly scheduled HTML; I need to
// use the $css_class while it's still here.
$this->select_css .= "
/* Overrides for $css_class */
.$css_class
{
width: ${width}px;
height: ${height}px;
}
.$css_class,
.$css_class a:hover,
.$css_class .serendipity_karmaVoting_current-rating
{
background-image: url({$serendipity['baseURL']}plugins/serendipity_event_karma/img/${fname});
}
.$css_class,
.$css_class a,
.$css_class .serendipity_karmaVoting_current-rating
{
line-height: ${height}px;
height: ${height}px;
}
";
$n++;
} // Go back up for another image
// Check for nothing displayed
if ($n == 0) {
// There were no images!
$this->select_html .= "||
" . PLUGIN_KARMA_NO_IMAGES . " | "; } // End the table, with a config-item bottom-border separator $this->select_html .= "