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