renamed directory
This commit is contained in:
commit
830b64f0e1
6 changed files with 269 additions and 0 deletions
3
.htaccess
Normal file
3
.htaccess
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
SetHandler wsgi-script
|
||||||
|
Options ExecCGI
|
||||||
|
|
14
README.txt
Normal file
14
README.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
= tycker - a web-based ticker input form =
|
||||||
|
|
||||||
|
tycker offers a very simple interface to be used for entering ticker information.
|
||||||
|
Each entry consists of the current time, a title and content.
|
||||||
|
The content may be written in wikicreole syntax:
|
||||||
|
http://www.wikicreole.org/imageServlet?page=CheatSheet%2Fcreole_cheat_sheet.png
|
||||||
|
|
||||||
|
The data items are stored in an sqlite database by default. Other options
|
||||||
|
(mysql/postgres) are easily configurable, as well.
|
||||||
|
|
||||||
|
The result is processed via the template "display.html". Adjust this file to
|
||||||
|
generate the desired layout.
|
||||||
|
Generated html files are stored in the parent directory of tycker's base directory.
|
||||||
|
|
42
templates/admin_show_entries.html
Normal file
42
templates/admin_show_entries.html
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:py="http://genshi.edgewall.org/"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
<xi:include href="layout.html" />
|
||||||
|
<head>
|
||||||
|
<title>Admin Ticker</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<?python
|
||||||
|
import datetime
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
?>
|
||||||
|
|
||||||
|
<p><form action="generate" method="GET">
|
||||||
|
<input type="submit" value="Generate" />
|
||||||
|
<i><a href="../../${static_url}" title="static website">static website</a></i>
|
||||||
|
</form></p>
|
||||||
|
|
||||||
|
<table border="1">
|
||||||
|
<tr><th>Timestamp</th><th>Title</th><th>Content</th></tr>
|
||||||
|
<tr><form action="submit" method="GET">
|
||||||
|
<td><input type="text" size="15" name="date" value="${now.strftime(date_format)}" /></td>
|
||||||
|
<td><input type="text" size="25" name="title" value="" autofocus="autofocus" /></td>
|
||||||
|
<td><textarea name="content" rows="8" cols="80" /></td>
|
||||||
|
<td><input type="submit" value="Create" /></td>
|
||||||
|
</form></tr>
|
||||||
|
<tr py:for="entry in entries"><form action="submit" method="GET">
|
||||||
|
<td><input type="text" size="15" name="date" value="${entry['timestamp'].strftime(date_format)}" /></td>
|
||||||
|
<td><input type="text" size="25" name="title" value="${entry['title']}" /></td>
|
||||||
|
<td><textarea name="content" rows="8" cols="80">${entry['content']}</textarea></td>
|
||||||
|
<td><input type="hidden" name="entry_id" value="${entry.id}" /><input type="submit" value="Update" /></td>
|
||||||
|
</form>
|
||||||
|
<td><form action="delete" method="GET">
|
||||||
|
<input type="hidden" name="entry_id" value="${entry.id}" />
|
||||||
|
<input type="submit" value="Delete" />
|
||||||
|
</form></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
23
templates/display.html
Normal file
23
templates/display.html
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:py="http://genshi.edgewall.org/"
|
||||||
|
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
<xi:include href="layout.html" />
|
||||||
|
<head>
|
||||||
|
<title>Ticker</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
${nav_links()}
|
||||||
|
<ul>
|
||||||
|
<li py:for="entry in entries">
|
||||||
|
<span class="timestamp">${show_timestamp(entry['timestamp'])}</span><br/>
|
||||||
|
<span class="title">${entry['title']}:</span>
|
||||||
|
<span class="content">${formatter(entry['content'])}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
${nav_links()}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
54
templates/layout.html
Normal file
54
templates/layout.html
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:py="http://genshi.edgewall.org/" py:strip="">
|
||||||
|
|
||||||
|
<py:match path="head" once="true">
|
||||||
|
<head py:attrs="select('@*')">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||||
|
${select('*|text()')}
|
||||||
|
</head>
|
||||||
|
</py:match>
|
||||||
|
|
||||||
|
<?python
|
||||||
|
import creoleparser
|
||||||
|
import genshi
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
def formatter(text):
|
||||||
|
if not text:
|
||||||
|
return u""
|
||||||
|
text = text.replace("\\", "\\\\")
|
||||||
|
html = creoleparser.text2html(text, encoding=None).strip()
|
||||||
|
if html.startswith("<p>") and html.endswith("</p>"):
|
||||||
|
html = html[3:-4]
|
||||||
|
return genshi.Markup(html)
|
||||||
|
|
||||||
|
|
||||||
|
TODAY_FORMAT = "%H:%M"
|
||||||
|
FULL_FORMAT = "%d.%m.%y %H:%M"
|
||||||
|
last_day = datetime.datetime.today() - datetime.timedelta(days=1)
|
||||||
|
def show_timestamp(date):
|
||||||
|
if date <= last_day:
|
||||||
|
template = TODAY_FORMAT
|
||||||
|
else:
|
||||||
|
template = FULL_FORMAT
|
||||||
|
return date.strftime(template)
|
||||||
|
|
||||||
|
def nav_links():
|
||||||
|
result = []
|
||||||
|
if prev_link:
|
||||||
|
result.append('<a href="%s" title="zeige neuere Einträge">aktuellere</a>' % prev_link)
|
||||||
|
if next_link:
|
||||||
|
result.append('<a href="%s" title="zeige ältere Einträge">ältere</a>' % next_link)
|
||||||
|
return genshi.Markup(" | ".join(result))
|
||||||
|
?>
|
||||||
|
|
||||||
|
<py:match path="body" once="true">
|
||||||
|
<body py:attrs="select('@*')">
|
||||||
|
|
||||||
|
${select('*|text()')}
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</py:match>
|
||||||
|
</html>
|
||||||
|
|
133
tycker.py
Normal file
133
tycker.py
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import os
|
||||||
|
# the basedir is the parent dir of the location of this script
|
||||||
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
|
# Somehow "/usr/lib/python2.X/dist-packages" is missing from sys.path - thus bobo is not found.
|
||||||
|
# This applies to libapache2-mod-wsgi (3.3-2).
|
||||||
|
import sys
|
||||||
|
for path in list(sys.path):
|
||||||
|
options = []
|
||||||
|
parent_dir, last_dir = os.path.split(path)
|
||||||
|
options.append(os.path.join(path, "dist-packages"))
|
||||||
|
options.append(os.path.join(parent_dir, "pymodules", last_dir))
|
||||||
|
for option in options:
|
||||||
|
if os.path.isdir(option):
|
||||||
|
sys.path.append(option)
|
||||||
|
|
||||||
|
DATE_FORMAT = "%H:%M %d.%m.%Y"
|
||||||
|
PAGE_SIZE = 4
|
||||||
|
FILENAME_TEMPLATE = "ticker%d.html"
|
||||||
|
FULL_PATH_FILENAME_TEMPLATE = os.path.join(BASE_DIR, os.path.pardir, FILENAME_TEMPLATE)
|
||||||
|
BASE_URL = "./"
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import bobo
|
||||||
|
import sqlobject
|
||||||
|
import genshi.template
|
||||||
|
|
||||||
|
|
||||||
|
db_uri = "sqlite:///%s/tycker.sqlite" % BASE_DIR
|
||||||
|
sqlobject.sqlhub.processConnection = sqlobject.connectionForURI(db_uri)
|
||||||
|
|
||||||
|
loader = genshi.template.TemplateLoader(os.path.join(BASE_DIR, 'templates'), auto_reload=True)
|
||||||
|
|
||||||
|
|
||||||
|
class Entry(sqlobject.SQLObject):
|
||||||
|
timestamp = sqlobject.DateTimeCol()
|
||||||
|
title = sqlobject.UnicodeCol()
|
||||||
|
content = sqlobject.UnicodeCol()
|
||||||
|
|
||||||
|
|
||||||
|
def render(filename, **values):
|
||||||
|
stream = loader.load(filename).generate(**values)
|
||||||
|
return stream.render("html", doctype="html")
|
||||||
|
|
||||||
|
def get_filename(index):
|
||||||
|
return FULL_PATH_FILENAME_TEMPLATE % index
|
||||||
|
|
||||||
|
def get_link(index):
|
||||||
|
return FILENAME_TEMPLATE % index
|
||||||
|
|
||||||
|
def update_static_html():
|
||||||
|
entries = list(Entry.select().orderBy("-timestamp"))
|
||||||
|
file_index = 1
|
||||||
|
while entries:
|
||||||
|
current = entries[:PAGE_SIZE]
|
||||||
|
entries = entries[PAGE_SIZE:]
|
||||||
|
current_filename = get_filename(file_index)
|
||||||
|
if file_index > 1:
|
||||||
|
previous_link = get_link(file_index - 1)
|
||||||
|
else:
|
||||||
|
previous_link = None
|
||||||
|
if entries:
|
||||||
|
next_link = get_link(file_index + 1)
|
||||||
|
else:
|
||||||
|
next_link = None
|
||||||
|
values = { "entries": current,
|
||||||
|
"prev_link": previous_link,
|
||||||
|
"next_link": next_link,
|
||||||
|
}
|
||||||
|
rendered = render("display.html", **values)
|
||||||
|
open(current_filename, "w").write(rendered)
|
||||||
|
file_index += 1
|
||||||
|
|
||||||
|
@bobo.query('/submit')
|
||||||
|
def submit_entry(entry_id=None, title=None, content=None, date=None):
|
||||||
|
title = title.strip()
|
||||||
|
content = content.strip()
|
||||||
|
if not all((title, content, date)):
|
||||||
|
return bobo.redirect(BASE_URL)
|
||||||
|
try:
|
||||||
|
date = datetime.datetime.strptime(date, DATE_FORMAT)
|
||||||
|
except ValueError:
|
||||||
|
bobo.redirect(BASE_URL)
|
||||||
|
if entry_id is None:
|
||||||
|
Entry(title=title, content=content, timestamp=date)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
entry = Entry.get(entry_id)
|
||||||
|
except sqlobject.SQLObjectNotFound:
|
||||||
|
bobo.redirect(BASE_URL)
|
||||||
|
entry.title = title
|
||||||
|
entry.content = content
|
||||||
|
entry.date = date
|
||||||
|
update_static_html()
|
||||||
|
return bobo.redirect(BASE_URL)
|
||||||
|
|
||||||
|
@bobo.query('/delete')
|
||||||
|
def delete_entry(entry_id):
|
||||||
|
try:
|
||||||
|
Entry.delete(entry_id)
|
||||||
|
except sqlobject.SQLObjectNotFound:
|
||||||
|
bobo.redirect(BASE_URL)
|
||||||
|
update_static_html()
|
||||||
|
return bobo.redirect(BASE_URL)
|
||||||
|
|
||||||
|
@bobo.query('/generate')
|
||||||
|
def generate_static():
|
||||||
|
update_static_html()
|
||||||
|
return bobo.redirect(BASE_URL)
|
||||||
|
|
||||||
|
@bobo.query('/')
|
||||||
|
def show_entries():
|
||||||
|
values = {}
|
||||||
|
values["entries"] = Entry.select().orderBy("-timestamp")
|
||||||
|
values["date_format"] = DATE_FORMAT
|
||||||
|
values["static_url"] = get_link(1)
|
||||||
|
return render("admin_show_entries.html", **values)
|
||||||
|
|
||||||
|
@bobo.query('')
|
||||||
|
def redirect_base():
|
||||||
|
return bobo.redirect(os.path.split(__file__)[1] + "/")
|
||||||
|
|
||||||
|
|
||||||
|
for table in (Entry, ):
|
||||||
|
#table.dropTable()
|
||||||
|
if not table.tableExists():
|
||||||
|
table.createTable()
|
||||||
|
|
||||||
|
application = bobo.Application(bobo_resources=__name__)
|
||||||
|
|
Loading…
Reference in a new issue