2012-10-16 17:11:59 +00:00
|
|
|
|
|
|
|
import abc
|
2012-10-16 19:04:20 +00:00
|
|
|
import time
|
2012-10-16 17:11:59 +00:00
|
|
|
import sqlite3
|
|
|
|
|
|
|
|
from os.path import join
|
|
|
|
|
2012-10-16 19:07:29 +00:00
|
|
|
from isso.models import Comment
|
2012-10-16 17:11:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Abstract:
|
|
|
|
|
|
|
|
__metaclass__ = abc.ABCMeta
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def initialize(self, conf):
|
|
|
|
return
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def shutdown(self):
|
|
|
|
return
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
|
def add(path, comment):
|
|
|
|
return
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2012-10-16 18:20:29 +00:00
|
|
|
def update(self, path, id, comment):
|
2012-10-16 17:11:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2012-10-16 18:20:29 +00:00
|
|
|
def delete(self, path):
|
2012-10-16 17:11:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
@abc.abstractmethod
|
2012-10-16 18:20:29 +00:00
|
|
|
def retrieve(self, path, limit):
|
2012-10-16 17:11:59 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class SQLite(Abstract):
|
2012-10-16 17:32:55 +00:00
|
|
|
"""A basic :class:`Abstract` implementation using SQLite3. All comments
|
|
|
|
share a single database. The tuple (id, path) acts as unique identifier
|
|
|
|
for a comment. Multiple comments per path (= that is the URI to your blog
|
|
|
|
post) are ordered by that id."""
|
2012-10-16 17:11:59 +00:00
|
|
|
|
|
|
|
fields = [
|
2012-10-16 18:20:29 +00:00
|
|
|
'id', 'path', 'created', 'modified',
|
2012-10-16 17:42:51 +00:00
|
|
|
'text', 'author', 'email', 'website', 'parent', 'mode'
|
2012-10-16 17:11:59 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
def initialize(self, conf):
|
2012-10-16 17:42:51 +00:00
|
|
|
|
2012-10-16 17:32:55 +00:00
|
|
|
self.dbpath = conf['SQLITE']
|
2012-10-16 17:42:51 +00:00
|
|
|
self.mode = 1 if conf.get('MODERATION') else 0
|
2012-10-16 17:11:59 +00:00
|
|
|
|
|
|
|
with sqlite3.connect(self.dbpath) as con:
|
|
|
|
sql = ('main.comments (id INTEGER NOT NULL, path VARCHAR(255) NOT NULL,'
|
2012-10-16 18:20:29 +00:00
|
|
|
'created FLOAT NOT NULL, modified FLOAT, text VARCHAR,'
|
|
|
|
'author VARCHAR(64), email VARCHAR(64), website VARCHAR(64),'
|
|
|
|
'parent INTEGER, mode INTEGER, PRIMARY KEY (id, path))')
|
2012-10-16 17:11:59 +00:00
|
|
|
con.execute("CREATE TABLE IF NOT EXISTS %s;" % sql)
|
|
|
|
|
|
|
|
# increment id if (id, path) is no longer unique
|
|
|
|
con.execute("""\
|
|
|
|
CREATE TRIGGER IF NOT EXISTS increment AFTER INSERT ON comments
|
|
|
|
BEGIN
|
|
|
|
UPDATE comments SET
|
|
|
|
id=(SELECT MAX(id)+1 FROM comments WHERE path=NEW.path)
|
|
|
|
WHERE rowid=NEW.rowid;
|
|
|
|
END;""")
|
|
|
|
|
|
|
|
def shutdown(self):
|
|
|
|
return
|
|
|
|
|
|
|
|
def query2comment(self, query):
|
|
|
|
return Comment(
|
2012-10-16 18:20:29 +00:00
|
|
|
text=query[4], author=query[5], email=query[6], website=query[7],
|
|
|
|
parent=query[8], mode=query[9], id=query[0], created=query[2], modified=query[3]
|
2012-10-16 17:11:59 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def add(self, path, c):
|
|
|
|
with sqlite3.connect(self.dbpath) as con:
|
|
|
|
keys = ','.join(self.fields)
|
|
|
|
values = ','.join('?'*len(self.fields))
|
2012-10-16 19:00:10 +00:00
|
|
|
x = con.execute('INSERT INTO comments (%s) VALUES (%s);' % (keys, values), (
|
2012-10-16 18:20:29 +00:00
|
|
|
0, path, c.created, c.modified, c.text, c.author, c.email, c.website,
|
2012-10-16 17:42:51 +00:00
|
|
|
c.parent, self.mode)
|
|
|
|
)
|
2012-10-16 17:11:59 +00:00
|
|
|
|
2012-10-16 19:00:10 +00:00
|
|
|
with sqlite3.connect(self.dbpath) as con:
|
|
|
|
return con.execute('SELECT path, MAX(id) FROM comments;').fetchone()
|
|
|
|
|
2012-10-16 18:20:29 +00:00
|
|
|
def update(self, path, id, comment):
|
|
|
|
with sqlite3.connect(self.dbpath) as con:
|
|
|
|
for field, value in comment.iteritems():
|
2012-10-16 19:00:10 +00:00
|
|
|
con.execute('UPDATE comments SET %s=? WHERE path=? AND id=?;' % field,
|
|
|
|
(value, id, path))
|
2012-10-16 19:04:20 +00:00
|
|
|
|
|
|
|
with sqlite3.connect(self.dbpath) as con:
|
|
|
|
con.execute('UPDATE comments SET modified=? WHERE path=? AND id=?',
|
|
|
|
(time.time(), path, id))
|
2012-10-16 19:00:10 +00:00
|
|
|
return path, id
|
|
|
|
|
|
|
|
def get(self, path, id):
|
|
|
|
with sqlite3.connect(self.dbpath) as con:
|
|
|
|
return self.query2comment(con.execute(
|
|
|
|
'SELECT * FROM comments WHERE path=? AND id=?;', (path, id)).fetchone())
|
2012-10-16 17:11:59 +00:00
|
|
|
|
2012-10-16 18:20:29 +00:00
|
|
|
def delete(self, path, id):
|
2012-10-16 19:00:10 +00:00
|
|
|
with sqlite3.connect(self.dbpath) as con:
|
|
|
|
con.execute('UPDATE comments SET text=? WHERE path=? AND id=?', ('', path, id))
|
|
|
|
for field in Comment.fields:
|
|
|
|
if field == 'text': continue
|
|
|
|
con.execute('UPDATE comments SET %s=? WHERE path=? AND id=?' % field,
|
|
|
|
(None, path, id))
|
|
|
|
return path, id
|
2012-10-16 17:11:59 +00:00
|
|
|
|
|
|
|
def retrieve(self, path, limit=20):
|
|
|
|
with sqlite3.connect(self.dbpath) as con:
|
2012-10-16 17:32:55 +00:00
|
|
|
rv = con.execute("SELECT * FROM comments WHERE path = ?" \
|
2012-10-16 19:00:10 +00:00
|
|
|
+ " ORDER BY id DESC LIMIT ?;", (path, limit)).fetchall()
|
2012-10-16 17:11:59 +00:00
|
|
|
|
|
|
|
for item in rv:
|
|
|
|
yield self.query2comment(item)
|