admin interface can delete comments :>
This commit is contained in:
parent
15ead12683
commit
6bb7b8c8d9
@ -31,4 +31,5 @@ def index(app, environ, request):
|
||||
except (SignatureExpired, BadSignature):
|
||||
return redirect('/')
|
||||
|
||||
return Response(render('admin.mako'), content_type='text/html')
|
||||
ctx = {'app': app, 'request': request}
|
||||
return Response(render('admin.mako', **ctx), content_type='text/html')
|
||||
|
@ -65,13 +65,13 @@ def modify(app, environ, request, path, id):
|
||||
try:
|
||||
rv = app.unsign(request.cookies.get('session-%s-%s' % (urllib.quote(path, ''), id), ''))
|
||||
except (SignatureExpired, BadSignature):
|
||||
return abort(403)
|
||||
try:
|
||||
rv = app.unsign(request.cookies.get('session-admin', ''))
|
||||
except (SignatureExpired, BadSignature):
|
||||
return abort(403)
|
||||
|
||||
# verify checksum, mallory might skip cookie deletion when he deletes a comment
|
||||
if app.db.get(path, id).md5 != rv[2]:
|
||||
abort(403)
|
||||
|
||||
if not (rv[0] == '*' or rv[0:2] == [path, id]):
|
||||
if not (rv == '*' or rv[0:2] == [path, id] or app.db.get(path, id).md5 != rv[2]):
|
||||
abort(403)
|
||||
|
||||
if request.method == 'PUT':
|
||||
|
@ -44,7 +44,7 @@ class Abstract:
|
||||
by another valid comment's parent attribute or stand-a-lone. In this
|
||||
case the comment can't be removed without losing depending comments.
|
||||
Hence, delete removes all visible data such as text, author, email,
|
||||
website sets the mode field to 2.
|
||||
website sets the mode field to 4.
|
||||
|
||||
In the second case this comment can be safely removed without any side
|
||||
effects."""
|
||||
@ -145,7 +145,7 @@ class SQLite(Abstract):
|
||||
|
||||
def delete(self, path, id):
|
||||
with sqlite3.connect(self.dbpath) as con:
|
||||
refs = con.execute('SELECT * FROM comments WHERE parent=?', (id, )).fetchone()
|
||||
refs = con.execute('SELECT * FROM comments WHERE path=? AND parent=?', (path, id)).fetchone()
|
||||
|
||||
if refs is None:
|
||||
con.execute('DELETE FROM comments WHERE path=? AND id=?', (path, id))
|
||||
|
52
isso/templates/admin.js
Normal file
52
isso/templates/admin.js
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
function remove(path, id, func) {
|
||||
$.ajax({
|
||||
url: '/1.0/' + encodeURIComponent(path) + '/' + id,
|
||||
method: 'DELETE',
|
||||
type: 'json',
|
||||
error: function(resp) {
|
||||
alert('Mööp.');
|
||||
},
|
||||
success: function(resp) {
|
||||
func();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// function approve(path, id, func) {
|
||||
// $.ajax({
|
||||
// url: ''
|
||||
// })
|
||||
// }
|
||||
|
||||
|
||||
function initialize() {
|
||||
|
||||
$('article > footer > a').forEach(function(item) {
|
||||
|
||||
var node = $(item).parent().parent()[0]
|
||||
var path = node.getAttribute("data-path");
|
||||
var id = node.getAttribute("data-id");
|
||||
|
||||
if (item.text == 'Approve') {
|
||||
$(item).on('click', function(event) {
|
||||
event.stop();
|
||||
});
|
||||
} else {
|
||||
$(item).on('click', function(event) {
|
||||
if (confirm("RLY?") == true) {
|
||||
remove(path, id, function() {
|
||||
$(node).remove()
|
||||
});
|
||||
};
|
||||
event.stop();
|
||||
});
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$.domReady(function() {
|
||||
initialize();
|
||||
});
|
@ -1,17 +1,84 @@
|
||||
<%inherit file="base.mako"/>
|
||||
|
||||
<%block name="js">
|
||||
<%include file="admin.js"/>
|
||||
</%block>
|
||||
|
||||
<%
|
||||
from time import strftime, gmtime
|
||||
|
||||
from urllib import quote, urlencode
|
||||
from urlparse import parse_qsl
|
||||
|
||||
def query(**kw):
|
||||
qs = dict(parse_qsl(request.query_string))
|
||||
qs.update(kw)
|
||||
return urlencode(qs)
|
||||
|
||||
def get(name, convert):
|
||||
limit = request.args.get(name)
|
||||
return convert(limit) if limit is not None else None
|
||||
%>
|
||||
|
||||
<%block name="title">
|
||||
Isso – Dashboard
|
||||
</%block>
|
||||
|
||||
|
||||
<%def name="make(comment)">
|
||||
|
||||
<article data-path="${quote(comment.path)}" data-id="${comment.id}">
|
||||
<header>
|
||||
<h1><a href="${comment.path}">${comment.path}</a></h1>
|
||||
<span class="created">${strftime('%a %d %B %Y', gmtime(comment.created))}</span>
|
||||
<span class="author">
|
||||
% if comment.website:
|
||||
<a href="${comment.website}">${comment.author}</a>
|
||||
% else:
|
||||
${comment.author}
|
||||
% endif
|
||||
</span>
|
||||
<span class="email">${comment.email}</span>
|
||||
</header>
|
||||
|
||||
<div class="text">
|
||||
${app.markup.convert(comment.text)}
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
% if comment.pending:
|
||||
<a href="#">Approve</a> |
|
||||
% endif
|
||||
<a href="#">Delete</a>
|
||||
</footer>
|
||||
</article>
|
||||
</%def>
|
||||
|
||||
<h1>Dashboard</h1>
|
||||
|
||||
<div>
|
||||
<h2>Pending</h2>
|
||||
<span class="limit">
|
||||
[ <a href="?${query(pendinglimit=10)}">10</a>
|
||||
| <a href="?${query(pendinglimit=20)}">20</a>
|
||||
| <a href="?${query(pendinglimit=0)}">All</a> ]
|
||||
</span>
|
||||
|
||||
% for comment in app.db.recent(limit=get('pendinglimit', int), mode=2):
|
||||
${make(comment)}
|
||||
% endfor
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2>Recent</h2>
|
||||
<span class="limit">
|
||||
[<a href="?${query(recentlimit=10)}">10</a>
|
||||
| <a href="?${query(recentlimit=20)}">20</a>
|
||||
| <a href="?${query(recentlimit=0)}">All</a>]
|
||||
</span>
|
||||
|
||||
% for comment in app.db.recent(limit=get('recentlimit', int), mode=5):
|
||||
${make(comment)}
|
||||
% endfor
|
||||
|
||||
</div>
|
||||
|
@ -2,6 +2,10 @@
|
||||
<head>
|
||||
<title><%block name="title" /></title>
|
||||
<meta charset="utf-8" />
|
||||
<script type="text/javascript" src="/static/ender.js"></script>
|
||||
<script type="text/javascript">
|
||||
<%block name="js" />
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user