Initial revision
This commit is contained in:
commit
bf921de540
5
Changelog
Normal file
5
Changelog
Normal file
@ -0,0 +1,5 @@
|
||||
10-10-2004
|
||||
* Added kwote_backup table.
|
||||
* Implemented functionality to remove nagative kwotes.
|
||||
|
||||
|
2
html/content-addform-thanks.html
Normal file
2
html/content-addform-thanks.html
Normal file
@ -0,0 +1,2 @@
|
||||
|
||||
Thank you for adding your kwote, here's a link to it: <a href="?action=show&id=${KWOTE_ID}">#${KWOTE_ID}</a>
|
7
html/content-addform.html
Normal file
7
html/content-addform.html
Normal file
@ -0,0 +1,7 @@
|
||||
<div class="search-container">
|
||||
<form action="${SCRIPT_NAME}" method="POST">
|
||||
<input type="hidden" name="action" value="doadd" />
|
||||
<textarea rows="15" cols="60" name="content"></textarea><br />
|
||||
<input type="submit" value="Submit" />
|
||||
</form>
|
||||
</div>
|
40
html/content-default.html
Normal file
40
html/content-default.html
Normal file
@ -0,0 +1,40 @@
|
||||
|
||||
|
||||
<div>
|
||||
<h3>Welcome</h3>
|
||||
We need to add some content here, soon! Anyway, this is kwotes. It's
|
||||
a chat quote database system, with a twist. This chat quote database
|
||||
is publicly moderated... so ALL of your submissions are accepted, and
|
||||
it's up to the general public to determine wether or not it's funny...
|
||||
no stupid moderators who wouldn't know funny if it grabed them by the
|
||||
asshole and ripped them apart. Anyway, this system has some advantages
|
||||
over existing systems, here are a few:
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
You can vote for a quote without it going to a new page and
|
||||
you losing your place in your current view.
|
||||
</li>
|
||||
<li>
|
||||
The system is publicly moderated so that all submissions are
|
||||
accepted, submissions that are less than zero for more than
|
||||
a certain period of time are removed from the system (maybe...)
|
||||
</li>
|
||||
<li>
|
||||
Users may only submit 4 quotes per hour.
|
||||
</li>
|
||||
<li>
|
||||
The system is opensource, you can download the source code
|
||||
using the link at the bottom of the page. Work is being
|
||||
done to setup a CVS repository and such.
|
||||
</li>
|
||||
<li>
|
||||
Slim sleek design... all browsers like us :)
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
We're thinking about creating an egdrop script for auto submiting
|
||||
quotes to the system, we'll see how that goes :)
|
||||
|
||||
</div>
|
||||
|
3
html/content-error.html
Normal file
3
html/content-error.html
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
<h1>${ERROR_MESSAGE}</h1>
|
||||
|
4
html/content-list-navigate-no-back.html
Normal file
4
html/content-list-navigate-no-back.html
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
<div class="kwote-navigation">
|
||||
<a href="?action=list&o=${ORDER}&s=${NEXT_INDEX}&m=${MAX_RETURN}&mr=${MAX_RECORDS}">Next ></a>
|
||||
</div>
|
4
html/content-list-navigate-no-forward.html
Normal file
4
html/content-list-navigate-no-forward.html
Normal file
@ -0,0 +1,4 @@
|
||||
<div class="kwote-navigation">
|
||||
<a href="?action=list&o=${ORDER}&s=${LAST_INDEX}&m=${MAX_RETURN}&mr=${MAX_RECORDS}">< Previous</a>
|
||||
</div>
|
||||
|
6
html/content-list-navigate.html
Normal file
6
html/content-list-navigate.html
Normal file
@ -0,0 +1,6 @@
|
||||
<div class="kwote-navigation">
|
||||
<a href="?action=list&o=${ORDER}&s=${LAST_INDEX}&m=${MAX_RETURN}&mr=${MAX_RECORDS}">< Previous</a>
|
||||
|
|
||||
<a href="?action=list&o=${ORDER}&s=${NEXT_INDEX}&m=${MAX_RETURN}&mr=${MAX_RECORDS}">Next ></a>
|
||||
</div>
|
||||
|
28
html/content-search.html
Normal file
28
html/content-search.html
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
<form action="${SCRIPT_NAME}" method="get">
|
||||
<div class="search-container">
|
||||
<input type="hidden" name="action" value="list" />
|
||||
<input type="hidden" name="s" value="0" />
|
||||
|
||||
<span>Search: </span><input type="text" name="ss" /> <input type="submit" value="Search" />
|
||||
|
||||
|
||||
Kwotes per page:
|
||||
<select name="m">
|
||||
<option value="5">5</option>
|
||||
<option value="20">20</option>
|
||||
<option value="30">30</option>
|
||||
<option value="40">40</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
<option value="200">200</option>
|
||||
</select>
|
||||
|
||||
|
||||
Sort by:
|
||||
<select name="o">
|
||||
<option value="date">Date</option>
|
||||
<option value="rating">Rating</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
13
html/content-show-kwote.html
Normal file
13
html/content-show-kwote.html
Normal file
@ -0,0 +1,13 @@
|
||||
<div class="quote">
|
||||
<div class="quote-header">
|
||||
<span><a href="?action=show&id=${KWOTE_ID}">#${KWOTE_ID}</a></span>
|
||||
<span class="vote-controls">
|
||||
<a href="javascript:vote(${KWOTE_ID},'hate');" id="hate${KWOTE_ID}">-</a>
|
||||
<span id="rating${KWOTE_ID}">${KWOTE_RATING}</span>
|
||||
<a href="javascript:vote(${KWOTE_ID},'love');" id="love${KWOTE_ID}">+</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="quote-content">
|
||||
${KWOTE_TEXT}
|
||||
</div>
|
||||
</div>
|
12
html/footer.html
Normal file
12
html/footer.html
Normal file
@ -0,0 +1,12 @@
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<a href="http://validator.w3.org/check?uri=referer">Valid XHTML 1.0 Strict</a>
|
||||
-
|
||||
<a href="kwotes.tar.gz">download the source</a>
|
||||
-
|
||||
${KWOTE_COUNT} live kwotes, ${KWOTE_BACKUP_COUNT} deleted kwotes
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
59
html/header.html
Normal file
59
html/header.html
Normal file
@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
|
||||
<head>
|
||||
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
<title>${TITLE}</title>
|
||||
<link rel="stylesheet" type="text/css" href="html/quotes.css" />
|
||||
|
||||
<!--[if IE]>
|
||||
<link rel="stylesheet" type="text/css" href="html/quotes-ie.css" />
|
||||
<![endif]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function vote(kid,type) {
|
||||
var img = new Image();
|
||||
img.src = "?action="+escape(type)+unescape("%26")+"kid="+escape(kid);
|
||||
hideElementById("hate"+kid);
|
||||
hideElementById("love"+kid);
|
||||
|
||||
var ratingElem = document.getElementById("rating"+kid);
|
||||
if (ratingElem) {
|
||||
var html = ratingElem.innerHTML;
|
||||
var rating = parseInt(html)+( (type=="love")?1:-1 );
|
||||
ratingElem.innerHTML = rating;
|
||||
}
|
||||
}
|
||||
|
||||
function hideElementById(id) {
|
||||
var elem = document.getElementById(id);
|
||||
if (elem) {
|
||||
elem.style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<span style="font-weight: bold;">Kwotes.org - The publicly moderated chat quote database</span>
|
||||
|
||||
<ul class="tab-list">
|
||||
<li class="tab"><a href="?">Home</a></li>
|
||||
<li class="tab"><a href="?action=add">Add</a></li>
|
||||
<li class="tab"><a href="?action=list&o=date">Latest</a></li>
|
||||
<li class="tab"><a href="?action=list&o=rating&s=0&m=20&mr=50">Top 100</a></li>
|
||||
<li class="tab"><a href="?action=list&o=rating&s=0&m=20&mr=50&so=reverse">Bottom 100</a></li>
|
||||
<li class="tab"><a href="?action=search">Search</a></li>
|
||||
</ul>
|
||||
|
||||
<form action="${SCRIPT_NAME}" method="get">
|
||||
<div class="direct-form">
|
||||
<span>Kwote #</span>
|
||||
<input type="hidden" name="action" value="show" />
|
||||
<input type="text" name="id" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="body-container">
|
11
html/quotes-ie.css
Normal file
11
html/quotes-ie.css
Normal file
@ -0,0 +1,11 @@
|
||||
/* Stupid IE stuff... at least they get to see something hilite */
|
||||
.tab a:active
|
||||
{
|
||||
background-color: #8b8bca;
|
||||
}
|
||||
|
||||
.tab a:hover
|
||||
{
|
||||
background-color: #dfdff0;
|
||||
}
|
||||
/* End stupid IE stuff */
|
122
html/quotes.css
Normal file
122
html/quotes.css
Normal file
@ -0,0 +1,122 @@
|
||||
body
|
||||
{
|
||||
font-family: Trebuchet MS, Tahoma, Arial, Sans-Serif;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
a:link
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:visited
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover, a:active
|
||||
{
|
||||
text-decoration: underlined;
|
||||
}
|
||||
|
||||
/* Begin Containers */
|
||||
.container
|
||||
{
|
||||
width: 700px;
|
||||
position: relative;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: left;
|
||||
padding: 2px 2px 5px 2px;
|
||||
}
|
||||
|
||||
.body-container
|
||||
{
|
||||
position: relative;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
/* End Containers */
|
||||
|
||||
.direct-form
|
||||
{
|
||||
position: absolute;
|
||||
top: 1px;
|
||||
right: 4px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.direct-form input
|
||||
{
|
||||
background-color: #dfdff0;
|
||||
border: 1px solid black;
|
||||
}
|
||||
|
||||
.quote
|
||||
{
|
||||
position: relative;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.quote-header
|
||||
{
|
||||
position: relative;
|
||||
border-bottom: 1px solid black;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.vote-controls
|
||||
{
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.quote-content
|
||||
{
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.footer
|
||||
{
|
||||
font-size: 0.8em;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* Horizontal Menu */
|
||||
.tab-list
|
||||
{
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
position: relative;
|
||||
list-style-type: none;
|
||||
background-color: #bfbfe2;
|
||||
height: 18;
|
||||
}
|
||||
|
||||
/* This is used by older browsers & IE */
|
||||
.tab-list .tab
|
||||
{
|
||||
display: inline;
|
||||
margin: 0px;
|
||||
padding-left: 3px;
|
||||
padding-right: 3px;
|
||||
font-size: 0.7em;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
/* Good browsers use this too */
|
||||
.tab-list .tab
|
||||
{
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.tab:active
|
||||
{
|
||||
background-color: #8b8bca;
|
||||
}
|
||||
|
||||
.tab:hover
|
||||
{
|
||||
background-color: #dfdff0;
|
||||
}
|
326
kwotes-lib.pl
Executable file
326
kwotes-lib.pl
Executable file
@ -0,0 +1,326 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# we use DBI, for it's sexy body
|
||||
use DBI;
|
||||
|
||||
# database connection
|
||||
my $GLOBAL_DBH = undef;
|
||||
|
||||
##
|
||||
# Returns the kwote count
|
||||
sub get_kwote_count {
|
||||
|
||||
# connect
|
||||
my $dbh = get_db_connection();
|
||||
|
||||
# execute
|
||||
my $sth = $dbh->prepare("SELECT COUNT(*) as kwote_count FROM kwote");
|
||||
$sth->execute();
|
||||
|
||||
# return
|
||||
my $row = $sth->fetchrow_hashref();
|
||||
return $row->{"kwote_count"};
|
||||
}
|
||||
|
||||
##
|
||||
# Returns the kwote_backup count
|
||||
sub get_kwote_backup_count {
|
||||
|
||||
# connect
|
||||
my $dbh = get_db_connection();
|
||||
|
||||
# execute
|
||||
my $sth = $dbh->prepare("SELECT COUNT(*) as kwote_count FROM kwote_backup");
|
||||
$sth->execute();
|
||||
|
||||
# return
|
||||
my $row = $sth->fetchrow_hashref();
|
||||
return $row->{"kwote_count"};
|
||||
}
|
||||
|
||||
##
|
||||
# does some minor database cleanup
|
||||
sub cleanup {
|
||||
|
||||
# get a db connection
|
||||
my $dbh = get_db_connection();
|
||||
|
||||
# backup kwotes to be deleted
|
||||
my $sth = $dbh->prepare(
|
||||
"INSERT INTO kwote_backup SELECT * FROM kwote WHERE ".
|
||||
"(now()-submit_dt)>? AND rating<0"
|
||||
);
|
||||
$sth->bind_param(1, NEGATIVE_KWOTE_TTL);
|
||||
$sth->execute() or die "Couldn't backup kwotes";
|
||||
|
||||
# delete kwotes
|
||||
$sth = $dbh->prepare(
|
||||
"DELETE FROM kwote WHERE (now()-submit_dt)>? AND rating<0"
|
||||
);
|
||||
$sth->bind_param(1, NEGATIVE_KWOTE_TTL);
|
||||
$sth->execute() or die "Couldn't delete kwotes";
|
||||
|
||||
# delete the vote log (this doesn't affect kwote rating)
|
||||
$sth = $dbh->prepare(
|
||||
"DELETE FROM vote WHERE (now()-vote_dt)>?"
|
||||
);
|
||||
$sth->bind_param(1, VOTE_TTL);
|
||||
$sth->execute() or die "Couldn't delete votes";
|
||||
|
||||
# let em know we're good
|
||||
print "Kwote Database cleanup complete\n";
|
||||
|
||||
# w00t
|
||||
return 0;
|
||||
}
|
||||
|
||||
##
|
||||
# votes on a kwote
|
||||
sub vote {
|
||||
my ($addr, $kid, $amt) = @_;
|
||||
|
||||
# connect to db
|
||||
my $dbh = get_db_connection();
|
||||
|
||||
# prepare statement
|
||||
my $sth = $dbh->prepare(
|
||||
"SELECT COUNT(*) as vote_count FROM vote WHERE ".
|
||||
"ip_address=? AND kwote_id=?"
|
||||
);
|
||||
$sth->bind_param(1, $addr);
|
||||
$sth->bind_param(2, $kid);
|
||||
|
||||
# execute
|
||||
$sth->execute();
|
||||
|
||||
# get row
|
||||
my $row = $sth->fetchrow_hashref();
|
||||
|
||||
# check if they suck
|
||||
return undef if ($row->{"vote_count"}>=MAX_VOTES_PER_IP);
|
||||
|
||||
# prepare
|
||||
$sth = $dbh->prepare(
|
||||
"UPDATE kwote SET rating=rating+(?) WHERE id=?"
|
||||
);
|
||||
$sth->bind_param(1, $amt);
|
||||
$sth->bind_param(2, $kid);
|
||||
$sth->execute() or return undef;
|
||||
|
||||
# record the vote
|
||||
$sth = $dbh->prepare(
|
||||
"INSERT INTO vote (ip_address, kwote_id, vote_dt) ".
|
||||
"VALUES (?, ?, now())"
|
||||
);
|
||||
$sth->bind_param(1, $addr);
|
||||
$sth->bind_param(2, $kid);
|
||||
$sth->execute() or return undef;
|
||||
|
||||
# we're good
|
||||
return 1;
|
||||
}
|
||||
|
||||
##
|
||||
# adds a kwote to the database
|
||||
sub add_kwote {
|
||||
my ($dbh, $kwote_text, $ip_address) = @_;
|
||||
my ($addr, $kid, $amt) = @_;
|
||||
|
||||
# make sure the kwote is ok
|
||||
return undef if (!defined($kwote_text) || $kwote_text eq "");
|
||||
|
||||
# prepare statement
|
||||
my $sth = $dbh->prepare(
|
||||
"SELECT COUNT(*) as kwote_count FROM kwote WHERE ip_address=? AND (now()-submit_dt)<?"
|
||||
);
|
||||
$sth->bind_param(1, $ip_address);
|
||||
$sth->bind_param(2, SECS_BETWEEN_KWOTES);
|
||||
|
||||
# execute
|
||||
$sth->execute() or return undef;
|
||||
|
||||
# get row
|
||||
my $row = $sth->fetchrow_hashref() or return undef;
|
||||
|
||||
# check if they suck
|
||||
return undef if ($row->{"kwote_count"}>=MAX_KWOTES_PER_IP);
|
||||
|
||||
# prepare statement
|
||||
my $sth = $dbh->prepare(
|
||||
"INSERT INTO kwote (submit_dt, content, rating, ip_address) ".
|
||||
"VALUES (now(), ?, ?, ?)"
|
||||
) or return undef;
|
||||
|
||||
# bind params
|
||||
$sth->bind_param(1, $kwote_text); # this is the kwote text
|
||||
$sth->bind_param(2, 0); # no rating as of yet
|
||||
$sth->bind_param(3, $ip_address); # the ip address
|
||||
|
||||
# execute
|
||||
$sth->execute() or return undef;
|
||||
|
||||
# return the id
|
||||
return $dbh->{insertid};
|
||||
}
|
||||
|
||||
##
|
||||
# adds a kwote to the database
|
||||
sub get_kwote {
|
||||
my ($dbh, $kid) = @_;
|
||||
|
||||
# prepare statement
|
||||
my $sth = $dbh->prepare(
|
||||
"SELECT * FROM kwote WHERE id=?"
|
||||
) or return undef;
|
||||
|
||||
# bind params
|
||||
$sth->bind_param(1, $kid);
|
||||
|
||||
# execute
|
||||
$sth->execute() or return undef;
|
||||
|
||||
# get the row
|
||||
my $row = $sth->fetchrow_hashref();
|
||||
|
||||
# return the id
|
||||
return (defined($row)) ? $row : undef;
|
||||
}
|
||||
|
||||
##
|
||||
# Gets a list of kwotes
|
||||
sub list_kwotes {
|
||||
my ($dbh, $sort_by, $order_direction, $return_amt,
|
||||
$start_index, $search_string) = @_;
|
||||
|
||||
# clean up the numbers
|
||||
$return_amt =~ s/[^0-9]//ig;
|
||||
$start_index =~ s/[^0-9]//ig;
|
||||
|
||||
# ensure these numbers are ok
|
||||
if ($start_index eq "" || int($start_index)<=0) {
|
||||
$start_index = 0;
|
||||
}
|
||||
if ($return_amt eq "" || int($return_amt)<=0
|
||||
|| int($return_amt) > 200) {
|
||||
$return_amt = 20;
|
||||
}
|
||||
|
||||
# break out the keywords
|
||||
my @kws = split(/,/,$search_string);
|
||||
|
||||
# build SQL query
|
||||
my $sql = "SELECT * FROM kwote ";
|
||||
|
||||
# search stuff
|
||||
if (defined($search_string)) {
|
||||
$sql .= "WHERE 1=1 ";
|
||||
foreach my $kw (@kws) {
|
||||
$sql.= "AND content LIKE ? ";
|
||||
}
|
||||
}
|
||||
|
||||
# sorting and paging
|
||||
if (defined($sort_by)) {
|
||||
$sql .= "ORDER BY $sort_by $order_direction ";
|
||||
}
|
||||
|
||||
# paging
|
||||
$sql .= "LIMIT $start_index, $return_amt ";
|
||||
|
||||
# prepare
|
||||
my $sth = $dbh->prepare($sql) or return undef;
|
||||
|
||||
# apply the search criteria
|
||||
if (defined($search_string)) {
|
||||
for ($i=0; $i<@kws; $i++) {
|
||||
$sth->bind_param($i+1, "\%".$kws[$i]."\%");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# execute
|
||||
$sth->execute() or return undef;
|
||||
|
||||
# get the rows
|
||||
my @rows;
|
||||
while (my $row = $sth->fetchrow_hashref()) {
|
||||
push(@rows, $row);
|
||||
}
|
||||
|
||||
# return it
|
||||
return @rows;
|
||||
}
|
||||
|
||||
##
|
||||
# Connect to the database
|
||||
sub get_db_connection {
|
||||
if (!$GLOBAL_DBH) {
|
||||
$GLOBAL_DBH = DBI->connect(
|
||||
"dbi:".DB_TYPE.":".DB_NAME.":".DB_HOST,
|
||||
DB_USER,
|
||||
DB_PASS
|
||||
);
|
||||
}
|
||||
return $GLOBAL_DBH;
|
||||
}
|
||||
|
||||
##
|
||||
# Escape html
|
||||
sub html_escape {
|
||||
my ($data) = @_;
|
||||
$data =~ s/</</g;
|
||||
$data =~ s/>/>/g;
|
||||
$data =~ s/\n/<br \/>/g;
|
||||
$data =~ s/"/"/g;
|
||||
return $data;
|
||||
}
|
||||
|
||||
##
|
||||
# Sends the HTML header
|
||||
sub send_html_header {
|
||||
print STDOUT "Content-type: text/html\n\n";
|
||||
}
|
||||
|
||||
##
|
||||
# Renders an HTML template
|
||||
sub wrap_template {
|
||||
my ($template_file, %vars) = @_;
|
||||
open(IN,"$template_file");
|
||||
my $data = join("",<IN>);
|
||||
close(IN);
|
||||
foreach $key (keys %vars) {
|
||||
$data =~ s/\${$key}/$vars{$key}/ig;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
##
|
||||
# Wraps and renders a template
|
||||
sub render_template {
|
||||
my ($template_file, %vars) = @_;
|
||||
my $data = wrap_template($template_file, %vars);
|
||||
print STDOUT $data;
|
||||
}
|
||||
|
||||
##
|
||||
# Parse form data
|
||||
sub parse_form {
|
||||
my (@pairs, $pair, $buffer, %FORM);
|
||||
if ($ENV{'REQUEST_METHOD'} eq 'GET') {
|
||||
@pairs = split(/&/, $ENV{'QUERY_STRING'});
|
||||
} elsif ($ENV{'REQUEST_METHOD'} eq 'POST') {
|
||||
read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});
|
||||
@pairs = split(/&/, $buffer);
|
||||
}
|
||||
foreach $pair (@pairs) {
|
||||
local($name, $value) = split(/=/, $pair);
|
||||
$name =~ tr/+/ /;
|
||||
$name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
|
||||
$value =~ tr/+/ /;
|
||||
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
|
||||
$FORM{$name} = $value;
|
||||
}
|
||||
return %FORM;
|
||||
}
|
||||
|
||||
1;
|
38
kwotes.conf.pl
Executable file
38
kwotes.conf.pl
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use constant {
|
||||
DB_TYPE => "mysql", # dbi database type (only MySQL is
|
||||
# supported currently, due to the
|
||||
# fact that "LIMIT X,X" is used
|
||||
|
||||
DB_NAME => "kwotes", # database name
|
||||
|
||||
DB_HOST => "localhost", # database host
|
||||
|
||||
DB_USER => "kwotes", # database user
|
||||
|
||||
DB_PASS => "kw0tes", # database password
|
||||
|
||||
MAX_VOTES_PER_IP => 4, # maximum votes per ip address per
|
||||
# VOTE_TTL seconds.
|
||||
|
||||
MAX_KWOTES_PER_IP => 5, # maximum kwotes allowed per ip
|
||||
# in SECS_BETWEEN_KWOTES
|
||||
|
||||
SECS_BETWEEN_KWOTES => 60*60, # seconds a user must wait after
|
||||
# submitting MAX_KWOTES_PER_IP
|
||||
# kwotes to the system before they
|
||||
# are allowed to submit another
|
||||
# kwote
|
||||
|
||||
NEGATIVE_KWOTE_TTL => (60*60)*24, # seconds before a negative rated
|
||||
# quote is moved to the kwote
|
||||
# backup table and deleted
|
||||
|
||||
VOTE_TTL => (60*60)*24 # seconds a vot log lasts, the vote
|
||||
# log is the mechanism that keeps
|
||||
# people from voting over and over
|
||||
};
|
||||
|
||||
1;
|
||||
|
208
kwotes.pl
Executable file
208
kwotes.pl
Executable file
@ -0,0 +1,208 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
###################################################
|
||||
# -*- kwotes.pl -*- #
|
||||
###################################################
|
||||
# TOD: Put some interesting shit here, perhaps #
|
||||
# something about kwotes being GPL #
|
||||
###################################################
|
||||
|
||||
# bring in the config
|
||||
require "kwotes.conf.pl";
|
||||
|
||||
# bring in the required libs
|
||||
require "kwotes-lib.pl";
|
||||
|
||||
# is this getting called by the "delete" cronjob?
|
||||
if ($ARGV[0] eq "cleanup") {
|
||||
exit cleanup();
|
||||
}
|
||||
|
||||
# parse the form data
|
||||
my %FORM = parse_form();
|
||||
|
||||
# some vars
|
||||
my $action = $FORM{"action"};
|
||||
my $main_content;
|
||||
my %vars;
|
||||
|
||||
# populate %vars with ENV
|
||||
foreach my $key (keys %ENV) {
|
||||
$vars{$key} = $ENV{$key};
|
||||
}
|
||||
|
||||
# send the HTML header
|
||||
send_html_header();
|
||||
|
||||
# add information that is displayed on every page
|
||||
$vars{KWOTE_COUNT} = get_kwote_count();
|
||||
$vars{KWOTE_BACKUP_COUNT} = get_kwote_backup_count();
|
||||
|
||||
############
|
||||
# action: add (show add form)
|
||||
if ($action eq "add") {
|
||||
$vars{TITLE} = "Add Kwote";
|
||||
$main_content = wrap_template("html/content-addform.html", %vars);
|
||||
|
||||
############
|
||||
# action: doadd (add the kwote to the db)
|
||||
} elsif ($action eq "doadd") {
|
||||
|
||||
if ($FORM{"content"} eq "") {
|
||||
$vars{TITLE} = "An Error Occured";
|
||||
$vars{ERROR_MESSAGE} = "No text entered";
|
||||
$main_content = wrap_template("html/content-error.html",%vars);
|
||||
|
||||
} else {
|
||||
|
||||
# add the kwote
|
||||
my $dbh = get_db_connection();
|
||||
my $kid = add_kwote($dbh, $FORM{"content"}, $ENV{"REMOTE_ADDR"});
|
||||
|
||||
# wtf? errors? in my code? noooo.
|
||||
if (!defined($kid)) {
|
||||
$vars{TITLE} = "An Error Occured";
|
||||
$vars{ERROR_MESSAGE} = "Couldn't add kwote";
|
||||
$main_content = wrap_template("html/content-error.html",%vars);
|
||||
|
||||
# all was good
|
||||
} else {
|
||||
$vars{TITLE} = "Kwote Added";
|
||||
$vars{KWOTE_ID} = $kid;
|
||||
$main_content = wrap_template("html/content-addform-thanks.html", %vars);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
##########
|
||||
# action: show
|
||||
} elsif ($action eq "show") {
|
||||
|
||||
# get the kwote
|
||||
my $dbh = get_db_connection();
|
||||
my $kwote = get_kwote($dbh, $FORM{"id"});
|
||||
|
||||
# wtf? errors? in my code? noooo.
|
||||
if (!defined($kwote)) {
|
||||
$vars{TITLE} = "Kwote Does Not Exist";
|
||||
$vars{ERROR_MESSAGE} = "That kwote does not exist";
|
||||
$main_content = wrap_template("html/content-error.html",%vars);
|
||||
|
||||
# all was good
|
||||
} else {
|
||||
$vars{TITLE} = "Kwote \#$kwote->{'id'}";
|
||||
$vars{KWOTE_ID} = $kwote->{'id'};
|
||||
$vars{KWOTE_TEXT} = html_escape($kwote->{'content'});
|
||||
$vars{KWOTE_RATING} = $kwote->{'rating'};
|
||||
$main_content = wrap_template("html/content-show-kwote.html", %vars);
|
||||
|
||||
}
|
||||
|
||||
##########
|
||||
# action: latest
|
||||
} elsif ($action eq "list") {
|
||||
|
||||
# what are we sorting on
|
||||
my $sort = ($FORM{"o"} eq "date") ?
|
||||
"submit_dt" : ( ($FORM{"o"} eq "rating") ? "rating" : undef);
|
||||
|
||||
# get start index
|
||||
my $start_index = (defined($FORM{"s"})) ? $FORM{"s"} : 0;
|
||||
|
||||
# get max amount
|
||||
my $max_returned = (defined($FORM{"m"})) ? $FORM{"m"} : 20;
|
||||
|
||||
# what is the "max records" we'll consider?
|
||||
my $max_records = (defined($FORM{"mr"})) ? $FORM{"mr"} : 9999999999;
|
||||
|
||||
# what is the "sort order"
|
||||
my $sort_order = ($FORM{"so"} eq "reverse") ? "ASC" : "DESC";
|
||||
|
||||
# search string?
|
||||
my $search_string = $FORM{"ss"};
|
||||
|
||||
# get the kwote
|
||||
my $dbh = get_db_connection();
|
||||
my @rows = list_kwotes($dbh, $sort, $sort_order, $max_returned, $start_index, $search_string);
|
||||
|
||||
# setup these vars
|
||||
$vars{TITLE} = "Kwotes";
|
||||
$vars{ORDER} = $FORM{"o"};
|
||||
$vars{NEXT_INDEX} = $start_index+$max_returned;
|
||||
$vars{MAX_RETURN} = $max_returned;
|
||||
$vars{LAST_INDEX} = $start_index-$max_returned;
|
||||
$vars{MAX_RECORDS} = $max_records;
|
||||
|
||||
# add the search header if it was a search
|
||||
if (defined($search_string)) {
|
||||
$main_content .= wrap_template("html/content-search.html", %vars);
|
||||
}
|
||||
|
||||
# get the navigation template
|
||||
my $navigation_template = undef;
|
||||
|
||||
# forward, no back
|
||||
if ($start_index<=0 && @rows>=$max_returned
|
||||
&& ($start_index+$max_returned)<$max_records) {
|
||||
$navigation_template = "html/content-list-navigate-no-back.html";
|
||||
|
||||
# forward and back
|
||||
} elsif ($start_index>0 && @rows>=$max_returned
|
||||
&& ($start_index+$max_returned)<$max_records ) {
|
||||
$navigation_template = "html/content-list-navigate.html";
|
||||
|
||||
# back only
|
||||
} elsif ($start_index>0 && @rows<$max_returned) {
|
||||
$navigation_template = "html/content-list-navigate-no-forward.html";
|
||||
}
|
||||
|
||||
# wrap the navigation template
|
||||
$main_content .= wrap_template($navigation_template, %vars);
|
||||
|
||||
# loop through the results
|
||||
if (defined(@rows)) {
|
||||
for (my $i=0; $i<@rows && ($i+$start_index)<$max_records; $i++) {
|
||||
my $row = $rows[$i];
|
||||
$vars{KWOTE_ID} = $row->{'id'};
|
||||
$vars{KWOTE_TEXT} = html_escape($row->{'content'});
|
||||
$vars{KWOTE_RATING} = $row->{'rating'};
|
||||
$main_content .= wrap_template("html/content-show-kwote.html", %vars);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
# wrap the navigation template
|
||||
$main_content .= wrap_template($navigation_template, %vars);
|
||||
|
||||
##########
|
||||
# action: search (show the search page)
|
||||
} elsif ($action eq "search") {
|
||||
$vars{TITLE} = "Search";
|
||||
$main_content = wrap_template("html/content-search.html", %vars);
|
||||
|
||||
##########
|
||||
# action: love
|
||||
} elsif ($action eq "love") {
|
||||
vote($ENV{"REMOTE_ADDR"}, $FORM{"kid"}, "1");
|
||||
$vars{TITLE} = "Love";
|
||||
$main_content = "Vote Counted";
|
||||
|
||||
##########
|
||||
# action: hate
|
||||
} elsif ($action eq "hate") {
|
||||
vote($ENV{"REMOTE_ADDR"}, $FORM{"kid"}, "-1");
|
||||
$vars{TITLE} = "Hate";
|
||||
$main_content = "Vote Counted";
|
||||
|
||||
##########
|
||||
# show the homepage
|
||||
} else {
|
||||
$vars{TITLE} = "The Better kwote Database";
|
||||
$main_content = wrap_template("html/content-default.html", %vars);
|
||||
|
||||
}
|
||||
|
||||
# finish the HTML
|
||||
render_template("html/header.html", %vars);
|
||||
print STDOUT $main_content;
|
||||
render_template("html/footer.html", %vars);
|
28
kwotes.sql
Executable file
28
kwotes.sql
Executable file
@ -0,0 +1,28 @@
|
||||
|
||||
CREATE TABLE kwote (
|
||||
id INTEGER AUTO_INCREMENT,
|
||||
submit_dt DATETIME,
|
||||
content TEXT,
|
||||
rating INT,
|
||||
ip_address VARCHAR(15),
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
|
||||
CREATE TABLE kwote_backup (
|
||||
id INTEGER AUTO_INCREMENT,
|
||||
submit_dt DATETIME,
|
||||
content TEXT,
|
||||
rating INT,
|
||||
ip_address VARCHAR(15),
|
||||
PRIMARY KEY(id)
|
||||
);
|
||||
|
||||
CREATE TABLE vote (
|
||||
id INT AUTO_INCREMENT,
|
||||
ip_address VARCHAR(15),
|
||||
kwote_id INT,
|
||||
vote_dt DATETIME,
|
||||
PRIMARY KEY(id),
|
||||
FOREIGN KEY(kwote_id) REFERENCES kwote(id)
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user