/comment/ -> /1.0/

This commit is contained in:
posativ 2012-10-23 21:09:51 +02:00
parent ac6d88f61e
commit 39899dda81
5 changed files with 52 additions and 52 deletions

View File

@ -38,33 +38,33 @@ please file in a bug report \*including\* your dump.
## API
### fetch comments for /foo-bar/
To fetch all comments for a path, run
$ curl -H "Accept: application/json" http://example.org/comment/foo-bar/
### comment at /foo-bar/
To write a comment, you have to POST a JSON dictionary with the following key-value
pairs. Text is mandatory otherwise you'll get a 400 Bad Request. You'll also get
a 400 when your JSON is invalid.
$ curl -H "Accept: application/json" -X POST -d \
Let's say you want to comment on /foo-bar/
$ curl http://example.org/comment/foo-bar/new -H "Accept: application/json" -X POST -d \
'{
"text": "Lorem ipsum ...",
# optional
"name": "Hans", "email": "foo@bla.org", "website": "http://blog/log/"
}' http://example.org/comment/foo-bar/new
}'
### modify 12. comment at /foo-bar/
This will set a cookie, that expires in a few minutes (15 minutes per default). This
cookie allows you do modify or delete your comment. Don't try to modify that cookie,
it is cryptographically signed. If your cookie is outdated or modified, you'll get
a 403 Forbidden.
$ curl -H "Accept: application/json" -X PUT -d ... http://example.org/comment/foo-bar/12
For each comment you'll post, you get an unique cookie. Let's try to remove your comment:
You can only modify your own comment in a given time range (defaults to 15 minutes).
$ curl -H ... -X DELETE http://example.org/comment/foo-bar/1
### delete 2nd comment at /foo-bar/
$ curl -H ... -X DELETE http://example.org/comment/foo-bar/2
You can only delete your own comment in a given time range (defaults to 15 minutes). If
your comment has been referenced by another comment, your comment will be cleared but not
deleted to maintain depending comments.
If your comment has been referenced by another comment, your comment will be cleared but
not deleted to retain depending comments.
## Alternatives

View File

@ -55,10 +55,10 @@ url_map = Map([
# comment API, note that the client side quotes the URL, but this is
# actually unnecessary. PEP 333 aka WSGI always unquotes PATH_INFO.
url('/comment/<re(".+"):path>/', 'comment.get', ['GET']),
url('/comment/<re(".+"):path>/new', 'comment.create', ['POST']),
url('/comment/<re(".+"):path>/<int:id>', 'comment.get', ['GET']),
url('/comment/<re(".+"):path>/<int:id>', 'comment.modify', ['PUT', 'DELETE']),
url('/1.0/<re(".+"):path>/', 'comment.get', ['GET']),
url('/1.0/<re(".+"):path>/new', 'comment.create', ['POST']),
url('/1.0/<re(".+"):path>/<int:id>', 'comment.get', ['GET']),
url('/1.0/<re(".+"):path>/<int:id>', 'comment.modify', ['PUT', 'DELETE']),
], converters={'re': RegexConverter})

View File

@ -72,7 +72,7 @@ def modify(app, environ, request, path, id):
abort(403)
if not (rv[0] == '*' or rv[0:2] == [path, id]):
abort(401)
abort(403)
if request.method == 'PUT':
try:

View File

@ -67,7 +67,7 @@
}
$.ajax({
url: '/comment/' + encodeURIComponent(window.location.pathname) + '/new',
url: '/1.0/' + encodeURIComponent(window.location.pathname) + '/new',
method: 'POST',
type: 'json',
headers: {
@ -168,7 +168,7 @@
$('#isso_' + post['id'] + ' > footer .delete').on('click', function(event) {
$.ajax({
url: '/comment/' + encodeURIComponent(window.location.pathname) + '/' + post['id'],
url: '/1.0/' + encodeURIComponent(window.location.pathname) + '/' + post['id'],
method: 'DELETE',
error: function(resp) {
alert('Mööp!');
@ -196,7 +196,7 @@
var fetch = function(thread) {
var rv = $.ajax({
url: '/comment/' + encodeURIComponent(window.location.pathname) + '/',
url: '/1.0/' + encodeURIComponent(window.location.pathname) + '/',
method: 'GET',
type: 'json',
headers: {

View File

@ -29,8 +29,8 @@ class TestComments(unittest.TestCase):
def testGet(self):
self.post('/comment/path/new', data=json.dumps(comment(text='Lorem ipsum ...')))
r = self.get('/comment/path/1')
self.post('/1.0/path/new', data=json.dumps(comment(text='Lorem ipsum ...')))
r = self.get('/1.0/path/1')
assert r.status_code == 200
rv = json.loads(r.data)
@ -40,7 +40,7 @@ class TestComments(unittest.TestCase):
def testCreate(self):
rv = self.post('/comment/path/new', data=json.dumps(comment(text='Lorem ipsum ...')))
rv = self.post('/1.0/path/new', data=json.dumps(comment(text='Lorem ipsum ...')))
assert rv.status_code == 201
assert len(filter(lambda header: header[0] == 'Set-Cookie', rv.headers)) == 1
@ -54,9 +54,9 @@ class TestComments(unittest.TestCase):
def testCreateAndGetMultiple(self):
for i in range(20):
self.post('/comment/path/new', data=json.dumps(comment(text='Spam')))
self.post('/1.0/path/new', data=json.dumps(comment(text='Spam')))
r = self.get('/comment/path/')
r = self.get('/1.0/path/')
assert r.status_code == 200
rv = json.loads(r.data)
@ -64,17 +64,17 @@ class TestComments(unittest.TestCase):
def testGetInvalid(self):
assert self.get('/comment/path/123').status_code == 404
assert self.get('/comment/path/spam/123').status_code == 404
assert self.get('/comment/foo/').status_code == 404
assert self.get('/1.0/path/123').status_code == 404
assert self.get('/1.0/path/spam/123').status_code == 404
assert self.get('/1.0/foo/').status_code == 404
def testUpdate(self):
self.post('/comment/path/new', data=json.dumps(comment(text='Lorem ipsum ...')))
self.put('/comment/path/1', data=json.dumps(comment(
self.post('/1.0/path/new', data=json.dumps(comment(text='Lorem ipsum ...')))
self.put('/1.0/path/1', data=json.dumps(comment(
text='Hello World', author='me', website='http://example.com/')))
r = self.get('/comment/path/1')
r = self.get('/1.0/path/1')
assert r.status_code == 200
rv = json.loads(r.data)
@ -85,45 +85,45 @@ class TestComments(unittest.TestCase):
def testDelete(self):
self.post('/comment/path/new', data=json.dumps(comment(text='Lorem ipsum ...')))
r = self.delete('/comment/path/1')
self.post('/1.0/path/new', data=json.dumps(comment(text='Lorem ipsum ...')))
r = self.delete('/1.0/path/1')
assert r.status_code == 200
assert json.loads(r.data) == None
assert self.get('/comment/path/1').status_code == 404
assert self.get('/1.0/path/1').status_code == 404
def testDeleteWithReference(self):
client = Client(self.app, Response)
resp = client.post('/comment/path/new', data=json.dumps(comment(text='First')))
self.post('/comment/path/new', data=json.dumps(comment(text='Second', parent=1)))
resp = client.post('/1.0/path/new', data=json.dumps(comment(text='First')))
self.post('/1.0/path/new', data=json.dumps(comment(text='Second', parent=1)))
r = client.delete('/comment/path/1')
r = client.delete('/1.0/path/1')
assert r.status_code == 200
assert Comment(**json.loads(r.data)).deleted
assert self.get('/comment/path/1').status_code == 200
assert self.get('/comment/path/2').status_code == 200
assert self.get('/1.0/path/1').status_code == 200
assert self.get('/1.0/path/2').status_code == 200
def testPathVariations(self):
paths = ['/sub/path/', '/path.html', '/sub/path.html', '%2Fpath/%2F']
paths = ['/sub/path/', '/path.html', '/sub/path.html', '%2Fpath/%2F', '/']
for path in paths:
assert self.post('/comment/' + path + '/new',
assert self.post('/1.0/' + path + '/new',
data=json.dumps(comment(text='...'))).status_code == 201
for path in paths:
assert self.get('/comment/' + path)
assert self.get('/comment/' + path + '/1')
assert self.get('/1.0/' + path)
assert self.get('/1.0/' + path + '/1')
def testDeleteAndCreateByDifferentUsersButSamePostId(self):
mallory = Client(self.app, Response)
mallory.post('/comment/path/new', data=json.dumps(comment(text='Foo')))
mallory.delete('/comment/path/1')
mallory.post('/1.0/path/new', data=json.dumps(comment(text='Foo')))
mallory.delete('/1.0/path/1')
bob = Client(self.app, Response)
bob.post('/comment/path/new', data=json.dumps(comment(text='Bar')))
bob.post('/1.0/path/new', data=json.dumps(comment(text='Bar')))
assert mallory.delete('/comment/path/1').status_code == 403
assert bob.delete('/comment/path/1').status_code == 200
assert mallory.delete('/1.0/path/1').status_code == 403
assert bob.delete('/1.0/path/1').status_code == 200