Revision 2e507162
Added by dsorber about 11 years ago
| software/bookmark_library/bmklib/lib/tag.py | ||
|---|---|---|
|
SQL_SELECT_TAG_BY_ID = "SELECT * FROM tags WHERE id=?"
|
||
|
SQL_SELECT_TAG_BY_VALUE = "SELECT * FROM tags WHERE value=?"
|
||
|
SQL_INSERT_TAG = "INSERT INTO tags VALUES (?,?)"
|
||
|
SQL_GET_CATEGORY_BMKS = "SELECT bookmark_id FROM category_tags WHERE tag_id=?"
|
||
|
SQL_GET_DESCRIPTION_BMKS = "SELECT bookmark_id FROM description_tags WHERE tag_id=?"
|
||
|
|
||
|
class TagNotFoundError(Exception):
|
||
|
|
||
| ... | ... | |
|
# Data attributes
|
||
|
self.id = id
|
||
|
self.value = value
|
||
|
self.category_bmks = []
|
||
|
self.description_bmks = []
|
||
|
|
||
|
if self.id is not None:
|
||
|
# If an ID was passed in then the tag's value must match the ID
|
||
| ... | ... | |
|
row = db.fetchone()
|
||
|
if not row:
|
||
|
raise TagNotFoundError(self.id)
|
||
|
self.value = row[1]
|
||
|
self.value = row[1]
|
||
|
|
||
|
# Get category bookmark IDs
|
||
|
db.execute(SQL_GET_CATEGORY_BMKS, (self.id,))
|
||
|
self.category_bmks = [int(row[0]) for row in db.fetchall()]
|
||
|
|
||
|
# Get description bookmark IDs
|
||
|
db.execute(SQL_GET_DESCRIPTION_BMKS, (self.id,))
|
||
|
self.description_bmks = [int(row[0]) for row in db.fetchall()]
|
||
|
|
||
|
elif self.value:
|
||
|
# If a value was passed in, check to see if it already exists in
|
||
| software/bookmark_library/bmklib/web/bmklib.wsgi | ||
|---|---|---|
|
import re
|
||
|
|
||
|
from bmklib.web.controllers.all_bookmarks import AllBookmarksPageController
|
||
|
from bmklib.web.controllers.all_tags import AllTagsPageController
|
||
|
from bmklib.web.controllers.bookmark import BookmarkPageController
|
||
|
from bmklib.web.controllers.main import MainPageController
|
||
|
from bmklib.web.controllers.tagged import TaggedPageController
|
||
|
from bmklib.web.controllers.update_bookmark import UpdateBookmarkController
|
||
|
|
||
|
# It accepts two arguments:
|
||
| ... | ... | |
|
elif re.search('^/update_bookmark$', path) or re.search('^/update_bookmark/$', path):
|
||
|
# Update bookmark
|
||
|
controller = UpdateBookmarkController(environ)
|
||
|
response_headers, response_body = controller.generate_response()
|
||
|
response_headers, response_body = controller.generate_response()
|
||
|
|
||
|
elif re.search('^/tags$', path) or re.search('^/tags/', path):
|
||
|
# All tags page
|
||
|
controller = AllTagsPageController(environ)
|
||
|
response_headers, response_body = controller.generate_response()
|
||
|
|
||
|
elif re.search('^/tagged/', path):
|
||
|
# All bookmarks tagged with tag page
|
||
|
controller = TaggedPageController(environ)
|
||
|
response_headers, response_body = controller.generate_response()
|
||
|
|
||
|
else:
|
||
|
# User supplied an invalid URL
|
||
| software/bookmark_library/bmklib/web/controllers/all_bookmarks.py | ||
|---|---|---|
|
|
||
|
class AllBookmarksPageController(BaseHTMLController):
|
||
|
|
||
|
def __init__(self, environ, template_name='all_bookmarks.html'):
|
||
|
def __init__(self, environ, template_name='bookmark_list.html'):
|
||
|
super(AllBookmarksPageController, self).__init__(environ, template_name)
|
||
|
|
||
|
def build_content(self):
|
||
|
|
||
|
self.content['page_title'] = 'All Bookmarks'
|
||
|
|
||
|
# Split the path so we can parse it below
|
||
|
path = self.environ['PATH_INFO'][1:]
|
||
|
path_parts = path.split('/')
|
||
| software/bookmark_library/bmklib/web/controllers/all_tags.py | ||
|---|---|---|
|
import math
|
||
|
import os.path
|
||
|
|
||
|
import sqlite3
|
||
|
|
||
|
from bmklib.lib.tag import Tag
|
||
|
from bmklib.web.base_controller import BaseHTMLController, DB_PATH, MAX_PER_PAGE
|
||
|
|
||
|
class AllTagsPageController(BaseHTMLController):
|
||
|
|
||
|
def __init__(self, environ, template_name='tag_list.html'):
|
||
|
super(AllTagsPageController, self).__init__(environ, template_name)
|
||
|
|
||
|
def build_content(self):
|
||
|
|
||
|
self.content['page_title'] = 'All Tags'
|
||
|
|
||
|
# Split the path so we can parse it below
|
||
|
path = self.environ['PATH_INFO'][1:]
|
||
|
path_parts = path.split('/')
|
||
|
|
||
|
conn = sqlite3.connect(DB_PATH)
|
||
|
db = conn.cursor()
|
||
|
|
||
|
# Grab the total number of tags
|
||
|
db = conn.cursor()
|
||
|
db.execute("SELECT COUNT(*) FROM tags")
|
||
|
total_tags = int(db.fetchone()[0])
|
||
|
self.content['total_num_tags'] = total_tags
|
||
|
self.content['max_page_idx'] = math.ceil(float(total_tags) / MAX_PER_PAGE)
|
||
|
|
||
|
# Start pagination at 1 (instead of 0)
|
||
|
page_idx = 1
|
||
|
|
||
|
# Parse the path and modify the query as needed
|
||
|
if len(path_parts) == 2:
|
||
|
if path_parts[1] == 'all':
|
||
|
db.execute("SELECT id FROM tags")
|
||
|
else:
|
||
|
# Attempt to grab a new query index from the URL
|
||
|
try:
|
||
|
page_idx = int(path_parts[1])
|
||
|
except ValueError:
|
||
|
pass
|
||
|
|
||
|
if page_idx < 1:
|
||
|
page_idx = 1
|
||
|
|
||
|
query = "SELECT id FROM tags LIMIT {:d} OFFSET {:d}".format(
|
||
|
MAX_PER_PAGE, (page_idx - 1) * MAX_PER_PAGE)
|
||
|
db.execute(query)
|
||
|
else:
|
||
|
db.execute("SELECT id FROM tags LIMIT {:d}".format(MAX_PER_PAGE))
|
||
|
|
||
|
self.content['page_idx'] = page_idx
|
||
|
|
||
|
# Build Tag objects for all of the returned results
|
||
|
tags = [Tag(conn, id=row[0]) for row in db.fetchall()]
|
||
|
|
||
|
self.content['tags'] = tags
|
||
|
self.content['path_parts'] = len(path_parts)
|
||
|
|
||
|
# Calculate the URL "offset" for the update bookmark link
|
||
|
update_link = ['..'] * (len(path_parts) - 1)
|
||
|
update_link.extend(['tag'])
|
||
|
self.content['update_link'] = os.path.join(*update_link)
|
||
|
|
||
|
# Set previous link to control pagination in the template
|
||
|
if page_idx == 1:
|
||
|
self.content['previous'] = None
|
||
|
else:
|
||
|
prev_idx = page_idx - 1
|
||
|
prev_path = ['..'] * (len(path_parts) - 1)
|
||
|
prev_path.extend(['tags', str(prev_idx)])
|
||
|
self.content['previous'] = os.path.join(*prev_path)
|
||
|
|
||
|
# Set the next link to control pagination in the template
|
||
|
next_idx = page_idx + 1
|
||
|
if next_idx > self.content['max_page_idx']:
|
||
|
self.content['next'] = None
|
||
|
else:
|
||
|
next_path = ['..'] * (len(path_parts) - 1)
|
||
|
next_path.extend(['tags', str(next_idx)])
|
||
|
self.content['next'] = os.path.join(*next_path)
|
||
| software/bookmark_library/bmklib/web/controllers/tagged.py | ||
|---|---|---|
|
import math
|
||
|
import os.path
|
||
|
|
||
|
import sqlite3
|
||
|
|
||
|
from bmklib.lib.bookmark import Bookmark
|
||
|
from bmklib.lib.tag import Tag
|
||
|
from bmklib.web.base_controller import BaseHTMLController, DB_PATH, MAX_PER_PAGE
|
||
|
|
||
|
class TaggedPageController(BaseHTMLController):
|
||
|
|
||
|
def __init__(self, environ, template_name='bookmark_list.html'):
|
||
|
super(TaggedPageController, self).__init__(environ, template_name)
|
||
|
|
||
|
def build_content(self):
|
||
|
|
||
|
# Split the path so we can parse it below
|
||
|
path = self.environ['PATH_INFO'][1:]
|
||
|
path_parts = path.split('/')
|
||
|
|
||
|
if len(path_parts) != 2:
|
||
|
# TODO: this is an errar
|
||
|
pass
|
||
|
|
||
|
conn = sqlite3.connect(DB_PATH)
|
||
|
db = conn.cursor()
|
||
|
|
||
|
tag_id = int(path_parts[1])
|
||
|
tag = Tag(conn, tag_id)
|
||
|
|
||
|
self.content['page_title'] = 'Tagged: {:s}'.format(tag.value)
|
||
|
|
||
|
self.content['total_num_bmks'] = len(tag.category_bmks)
|
||
|
self.content['max_page_idx'] = math.ceil(float(len(tag.category_bmks)) / MAX_PER_PAGE)
|
||
|
|
||
|
# Start pagination at 1 (instead of 0)
|
||
|
page_idx = 1
|
||
|
self.content['page_idx'] = page_idx
|
||
|
|
||
|
# Build Bookmark objects for all of the returned results
|
||
|
bookmarks = [Bookmark(conn, id=bmk_id) for bmk_id in tag.category_bmks]
|
||
|
|
||
|
self.content['bookmarks'] = bookmarks
|
||
|
self.content['path_parts'] = len(path_parts)
|
||
|
|
||
|
# Calculate the URL "offset" for the update bookmark link
|
||
|
update_link = ['..'] * (len(path_parts) - 1)
|
||
|
update_link.extend(['bookmark'])
|
||
|
self.content['update_link'] = os.path.join(*update_link)
|
||
|
|
||
|
# Set previous link to control pagination in the template
|
||
|
if page_idx == 1:
|
||
|
self.content['previous'] = None
|
||
|
else:
|
||
|
prev_idx = page_idx - 1
|
||
|
prev_path = ['..'] * (len(path_parts) - 1)
|
||
|
prev_path.extend(['tagged', str(prev_idx)])
|
||
|
self.content['previous'] = os.path.join(*prev_path)
|
||
|
|
||
|
# Set the next link to control pagination in the template
|
||
|
next_idx = page_idx + 1
|
||
|
if next_idx > self.content['max_page_idx']:
|
||
|
self.content['next'] = None
|
||
|
else:
|
||
|
next_path = ['..'] * (len(path_parts) - 1)
|
||
|
next_path.extend(['tagged', str(next_idx)])
|
||
|
self.content['next'] = os.path.join(*next_path)
|
||
| software/bookmark_library/bmklib/web/htdocs/css/bmk_list.css | ||
|---|---|---|
|
}
|
||
|
|
||
|
.tag {
|
||
|
font-family: arial;
|
||
|
font-size: 7pt;
|
||
|
font-weight: bold;
|
||
|
background-color: #003399;
|
||
| software/bookmark_library/bmklib/web/templates/all_bookmarks.html | ||
|---|---|---|
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||
|
xmlns:py="http://genshi.edgewall.org/">
|
||
|
<xi:include href="layout.html" />
|
||
|
<head>
|
||
|
<title>Bookmark Library</title>
|
||
|
<link rel="stylesheet" type="text/css" href="/htdocs/css/bmk_list.css"></link>
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
<h3>All Bookmarks</h3>
|
||
|
<p>${page_idx} of ${max_page_idx}</p>
|
||
|
|
||
|
<div id="pagination_nav_top">
|
||
|
<py:if test="previous is not None"><div id="previous"><a href="${previous}">Previous</a></div></py:if>
|
||
|
<py:if test="next is not None"><div id="next"><a href="${next}">Next</a></div></py:if>
|
||
|
</div>
|
||
|
|
||
|
<div id="bmk_list">
|
||
|
<div py:for="idx, bookmark in enumerate(bookmarks)" id="${idx == 0 and 'first' or ''}" class="${idx % 2 == 1 and 'odd' or 'even'} row">
|
||
|
<span class="bmk_index"><a href="${update_link}/${bookmark.id}">${idx + ((page_idx - 1) * len(bookmarks)) + 1}</a></span>
|
||
|
<span><a href="${bookmark.url}">${bookmark.title and bookmark.title or 'no title'}</a><py:for each="tag in bookmark.category_tags"><span class="tag">${tag.value}</span></py:for></span>
|
||
|
|
||
|
<!--
|
||
|
<td><py:for each="tag in bookmark.description_tags"><span class="tag">${tag.value}</span></py:for></td>
|
||
|
-->
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<div id="pagination_nav_bottom">
|
||
|
<py:if test="previous is not None"><div id="previous"><a href="${previous}">Previous</a></div></py:if>
|
||
|
<py:if test="next is not None"><div id="next"><a href="${next}">Next</a></div></py:if>
|
||
|
</div>
|
||
|
</body>
|
||
|
</html>
|
||
| software/bookmark_library/bmklib/web/templates/bookmark_list.html | ||
|---|---|---|
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||
|
xmlns:py="http://genshi.edgewall.org/">
|
||
|
<xi:include href="layout.html" />
|
||
|
<head>
|
||
|
<title>Bookmark Library</title>
|
||
|
<link rel="stylesheet" type="text/css" href="/htdocs/css/bmk_list.css"></link>
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
<h3>${page_title}</h3>
|
||
|
<p>Page ${page_idx} of ${max_page_idx}</p>
|
||
|
|
||
|
<div id="pagination_nav_top">
|
||
|
<py:if test="previous is not None"><div id="previous"><a href="${previous}">Previous</a></div></py:if>
|
||
|
<py:if test="next is not None"><div id="next"><a href="${next}">Next</a></div></py:if>
|
||
|
</div>
|
||
|
|
||
|
<div id="bmk_list">
|
||
|
<div py:for="idx, bookmark in enumerate(bookmarks)" id="${idx == 0 and 'first' or ''}" class="${idx % 2 == 1 and 'odd' or 'even'} row">
|
||
|
<span class="bmk_index"><a href="${update_link}/${bookmark.id}">${idx + ((page_idx - 1) * len(bookmarks)) + 1}</a></span>
|
||
|
<span><a href="${bookmark.url}">${bookmark.title and bookmark.title or 'no title'}</a><py:for each="tag in bookmark.category_tags"><span class="tag">${tag.value}</span></py:for></span>
|
||
|
|
||
|
<!--
|
||
|
<td><py:for each="tag in bookmark.description_tags"><span class="tag">${tag.value}</span></py:for></td>
|
||
|
-->
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<div id="pagination_nav_bottom">
|
||
|
<py:if test="previous is not None"><div id="previous"><a href="${previous}">Previous</a></div></py:if>
|
||
|
<py:if test="next is not None"><div id="next"><a href="${next}">Next</a></div></py:if>
|
||
|
</div>
|
||
|
</body>
|
||
|
</html>
|
||
| software/bookmark_library/bmklib/web/templates/tag_list.html | ||
|---|---|---|
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||
|
xmlns:xi="http://www.w3.org/2001/XInclude"
|
||
|
xmlns:py="http://genshi.edgewall.org/">
|
||
|
<xi:include href="layout.html" />
|
||
|
<head>
|
||
|
<title>Bookmark Library</title>
|
||
|
<link rel="stylesheet" type="text/css" href="/htdocs/css/bmk_list.css"></link>
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
<h3>${page_title}</h3>
|
||
|
<p>Page ${page_idx} of ${max_page_idx}</p>
|
||
|
|
||
|
<div id="pagination_nav_top">
|
||
|
<py:if test="previous is not None"><div id="previous"><a href="${previous}">Previous</a></div></py:if>
|
||
|
<py:if test="next is not None"><div id="next"><a href="${next}">Next</a></div></py:if>
|
||
|
</div>
|
||
|
|
||
|
<div id="bmk_list">
|
||
|
<div py:for="idx, tag in enumerate(tags)" id="${idx == 0 and 'first' or ''}" class="${idx % 2 == 1 and 'odd' or 'even'} row">
|
||
|
<span class="bmk_index"><a href="${update_link}/${tag.id}">${idx + ((page_idx - 1) * len(tags)) + 1}</a></span>
|
||
|
<span><a href="tagged/${tag.id}">${tag.value}</a></span>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<div id="pagination_nav_bottom">
|
||
|
<py:if test="previous is not None"><div id="previous"><a href="${previous}">Previous</a></div></py:if>
|
||
|
<py:if test="next is not None"><div id="next"><a href="${next}">Next</a></div></py:if>
|
||
|
</div>
|
||
|
</body>
|
||
|
</html>
|
||
Started working on tag list and a "tagged" controller. Need to work on pagination for the tagged controller.