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):
|
except (SignatureExpired, BadSignature):
|
||||||
return redirect('/')
|
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')
|
||||||
|
@ -64,14 +64,14 @@ def modify(app, environ, request, path, id):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
rv = app.unsign(request.cookies.get('session-%s-%s' % (urllib.quote(path, ''), id), ''))
|
rv = app.unsign(request.cookies.get('session-%s-%s' % (urllib.quote(path, ''), id), ''))
|
||||||
|
except (SignatureExpired, BadSignature):
|
||||||
|
try:
|
||||||
|
rv = app.unsign(request.cookies.get('session-admin', ''))
|
||||||
except (SignatureExpired, BadSignature):
|
except (SignatureExpired, BadSignature):
|
||||||
return abort(403)
|
return abort(403)
|
||||||
|
|
||||||
# verify checksum, mallory might skip cookie deletion when he deletes a comment
|
# verify checksum, mallory might skip cookie deletion when he deletes a comment
|
||||||
if app.db.get(path, id).md5 != rv[2]:
|
if not (rv == '*' or rv[0:2] == [path, id] or app.db.get(path, id).md5 != rv[2]):
|
||||||
abort(403)
|
|
||||||
|
|
||||||
if not (rv[0] == '*' or rv[0:2] == [path, id]):
|
|
||||||
abort(403)
|
abort(403)
|
||||||
|
|
||||||
if request.method == 'PUT':
|
if request.method == 'PUT':
|
||||||
|
@ -44,7 +44,7 @@ class Abstract:
|
|||||||
by another valid comment's parent attribute or stand-a-lone. In this
|
by another valid comment's parent attribute or stand-a-lone. In this
|
||||||
case the comment can't be removed without losing depending comments.
|
case the comment can't be removed without losing depending comments.
|
||||||
Hence, delete removes all visible data such as text, author, email,
|
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
|
In the second case this comment can be safely removed without any side
|
||||||
effects."""
|
effects."""
|
||||||
@ -145,7 +145,7 @@ class SQLite(Abstract):
|
|||||||
|
|
||||||
def delete(self, path, id):
|
def delete(self, path, id):
|
||||||
with sqlite3.connect(self.dbpath) as con:
|
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:
|
if refs is None:
|
||||||
con.execute('DELETE FROM comments WHERE path=? AND id=?', (path, id))
|
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"/>
|
<%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">
|
<%block name="title">
|
||||||
Isso – Dashboard
|
Isso – Dashboard
|
||||||
</%block>
|
</%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>
|
<h1>Dashboard</h1>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2>Pending</h2>
|
<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>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2>Recent</h2>
|
<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>
|
</div>
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
<head>
|
<head>
|
||||||
<title><%block name="title" /></title>
|
<title><%block name="title" /></title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
|
<script type="text/javascript" src="/static/ender.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
<%block name="js" />
|
||||||
|
</script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user