Mercurial > p > roundup > code
annotate roundup/actions.py @ 8185:e84d4585b16d
fix(web): issue2551356. Add etag header for not-modified (304) request.
When a 304 is returned to a conditional request for a static file,
print an ETag for the response.
ETag was always sent with a 200 response.
This also adds initial support for if-none-match conditional requests
for static files.
Changes:
Refactors the if-modified-since code out to a method.
It moves a file stat call from serve_static_file to _serve_file
so that an etag can be generated by both serve_static_file and
serve_file which call _serve_file.
Tests added. This does not test the codepath where serve_file pulls
content from the database rather than from a local file on disk.
Test mocking _serve_file changed to account for 5th argument to serve_file
BREAKING CHANGE:
function signature for client.py-Client::_serve_file() now has 5 not 4
parameters (added etag param). Since this is a "hidden" method I am
not too worried about it.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Tue, 10 Dec 2024 16:06:13 -0500 |
| parents | 1287b0c3d261 |
| children |
| rev | line source |
|---|---|
| 4083 | 1 # |
| 2 # Copyright (C) 2009 Stefan Seefeld | |
| 3 # All rights reserved. | |
| 4 # For license terms see the file COPYING.txt. | |
| 5604 | 5 # Actions used in REST and XMLRPC APIs |
| 4083 | 6 # |
| 7 | |
| 7764 | 8 from roundup import hyperdb |
|
5071
a7541077cf12
Remove 'import *' statement from actions.py
John Kristensen <john@jerrykan.com>
parents:
4357
diff
changeset
|
9 from roundup.exceptions import Unauthorised |
| 6003 | 10 |
| 4083 | 11 |
| 12 class Action: | |
| 13 def __init__(self, db, translator): | |
| 14 self.db = db | |
| 15 self.translator = translator | |
| 16 | |
| 17 def handle(self, *args): | |
| 18 """Action handler procedure""" | |
| 19 raise NotImplementedError | |
| 20 | |
| 21 def execute(self, *args): | |
| 22 """Execute the action specified by this object.""" | |
| 23 | |
| 24 self.permission(*args) | |
| 25 return self.handle(*args) | |
| 26 | |
| 27 def permission(self, *args): | |
| 28 """Check whether the user has permission to execute this action. | |
| 29 | |
| 30 If not, raise Unauthorised.""" | |
| 31 | |
| 32 pass | |
| 33 | |
| 34 def gettext(self, msgid): | |
| 35 """Return the localized translation of msgid""" | |
| 36 return self.translator.gettext(msgid) | |
| 37 | |
| 38 _ = gettext | |
| 39 | |
| 40 | |
| 5604 | 41 class PermCheck(Action): |
| 42 def permission(self, designator): | |
| 43 | |
| 44 classname, itemid = hyperdb.splitDesignator(designator) | |
| 45 perm = self.db.security.hasPermission | |
| 46 | |
| 6003 | 47 if not perm('Retire', self.db.getuid(), classname=classname, |
| 48 itemid=itemid): | |
| 5604 | 49 raise Unauthorised(self._('You do not have permission to retire ' |
| 50 'or restore the %(classname)s class.') | |
| 6003 | 51 % locals()) |
| 52 | |
| 5604 | 53 |
| 54 class Retire(PermCheck): | |
| 4083 | 55 |
| 56 def handle(self, designator): | |
| 57 | |
| 58 classname, itemid = hyperdb.splitDesignator(designator) | |
| 59 | |
| 60 # make sure we don't try to retire admin or anonymous | |
| 61 if (classname == 'user' and | |
|
7176
4c9acc580769
chore: flake8 whitespace fixes
John Rouillard <rouilj@ieee.org>
parents:
6003
diff
changeset
|
62 self.db.user.get(itemid, 'username') in ('admin', 'anonymous')): |
|
4c9acc580769
chore: flake8 whitespace fixes
John Rouillard <rouilj@ieee.org>
parents:
6003
diff
changeset
|
63 |
|
4357
13b3155869e0
Beginnings of a big code cleanup / modernisation to make 2to3 happy
Richard Jones <richard@users.sourceforge.net>
parents:
4125
diff
changeset
|
64 raise ValueError(self._( |
|
13b3155869e0
Beginnings of a big code cleanup / modernisation to make 2to3 happy
Richard Jones <richard@users.sourceforge.net>
parents:
4125
diff
changeset
|
65 'You may not retire the admin or anonymous user')) |
| 4083 | 66 |
| 67 # do the retire | |
| 68 self.db.getclass(classname).retire(itemid) | |
| 69 self.db.commit() | |
| 70 | |
| 71 | |
| 5604 | 72 class Restore(PermCheck): |
| 73 | |
| 74 def handle(self, designator): | |
| 4083 | 75 |
| 76 classname, itemid = hyperdb.splitDesignator(designator) | |
| 77 | |
| 5604 | 78 # do the restore |
| 79 self.db.getclass(classname).restore(itemid) | |
| 80 self.db.commit() |
