from django import forms
-class DocumentEntryRequest(forms.Form):
- revision = forms.RegexField(regex='latest|[0-9a-f]{40}')
+
+class MergeRequestForm(forms.Form):
+ # should the target document revision be updated or shared
+ type = forms.ChoiceField(choices=('update', 'share'))
+
+ # which revision to update/share
+ target_revision = forms.RegexField('[0-9a-f]{40}')
+
+ # any additional comments that user wants to add to the change
+ comment = forms.CharField(required=False)
class DocumentUploadForm(forms.Form):
ocr_file = forms.FileField(label='Source OCR file', required=False)
from librarian import dcparser
import api.response as response
-from api.response import validate_form
+from api.utils import validate_form, hglibrary
#
# Document List Handlers
class BasicLibraryHandler(AnonymousBaseHandler):
allowed_methods = ('GET',)
- def read(self, request):
- """Return the list of documents."""
- lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
-
+ @hglibrary
+ def read(self, request, lib):
+ """Return the list of documents."""
document_list = [{
'url': reverse('document_view', args=[docid]),
'name': docid } for docid in lib.documents() ]
allowed_methods = ('GET', 'POST')
anonymous = BasicLibraryHandler
- def read(self, request):
+ @hglibrary
+ def read(self, request, lib):
"""Return the list of documents."""
- lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
document_list = [{
'url': reverse('document_view', args=[docid]),
return {'documents' : document_list }
@validate_form(forms.DocumentUploadForm, 'POST')
- def create(self, request, form):
- """Create a new document."""
- lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
+ @hglibrary
+ def create(self, request, form, lib):
+ """Create a new document."""
if form.cleaned_data['ocr_data']:
data = form.cleaned_data['ocr_data'].encode('utf-8')
else:
- data = request.FILES['ocr'].read().decode('utf-8')
+ data = request.FILES['ocr_file'].read().decode('utf-8')
if form.cleaned_data['generate_dc']:
data = librarian.wrap_text(data, unicode(date.today()))
docid = form.cleaned_data['bookname']
try:
doc = lib.document_create(docid)
- doc.quickwrite('xml', data, '$AUTO$ XML data uploaded.',
+ doc = doc.quickwrite('xml', data, '$AUTO$ XML data uploaded.',
user=request.user.username)
url = reverse('document_view', args=[doc.id])
-
return response.EntityCreated().django_response(\
body = {
'url': url,
class BasicDocumentHandler(AnonymousBaseHandler):
allowed_methods = ('GET',)
- def read(self, request, docid):
- try:
- lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
+ @hglibrary
+ def read(self, request, docid, lib):
+ try:
doc = lib.document(docid)
except RevisionNotFound:
return rc.NOT_FOUND
result = {
'name': doc.id,
- 'text_url': reverse('doctext_view', args=[doc.id]),
- 'dc_url': reverse('docdc_view', docid=doc.id),
+ 'text_url': reverse('doctext_view', args=[doc.id,doc.revision]),
+ 'dc_url': reverse('docdc_view', args=[doc.id,doc.revision]),
'public_revision': doc.revision,
}
allowed_methods = ('GET', 'PUT')
anonymous = BasicDocumentHandler
- def read(self, request, docid):
- """Read document's meta data"""
- lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
-
+ @hglibrary
+ def read(self, request, docid, lib):
+ """Read document's meta data"""
try:
doc = lib.document(docid)
udoc = doc.take(request.user.username)
result = {
'name': udoc.id,
- 'text_url': reverse('doctext_view', args=[udoc.id]),
- 'dc_url': reverse('docdc_view', args=[udoc.id]),
- 'parts_url': reverse('docparts_view', args=[udoc.id]),
+ 'text_url': reverse('doctext_view', args=[doc.id,doc.revision]),
+ 'dc_url': reverse('docdc_view', args=[doc.id,doc.revision]),
'user_revision': udoc.revision,
'public_revision': doc.revision,
}
return result
- def update(self, request, docid):
+ @hglibrary
+ def update(self, request, docid, lib):
"""Update information about the document, like display not"""
return
class DocumentTextHandler(BaseHandler):
allowed_methods = ('GET', 'PUT')
- @validate_form(forms.DocumentEntryRequest)
- def read(self, request, form, docid):
- """Read document as raw text"""
- lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
-
+ @hglibrary
+ def read(self, request, docid, revision, lib):
+ """Read document as raw text"""
try:
- if request.GET['revision'] == 'latest':
+ if revision == 'latest':
document = lib.document(docid)
else:
- document = lib.document_for_rev(request.GET['revision'])
+ document = lib.document_for_rev(revision)
# TODO: some finer-grained access control
return document.data('xml')
except RevisionNotFound:
return response.EntityNotFound().django_response()
- def update(self, request, docid):
- lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
+ @hglibrary
+ def update(self, request, docid, revision, lib):
try:
- data = request.PUT['contents']
- prev = request.PUT['revision']
+ data = request.PUT['contents']
if request.PUT.has_key('message'):
msg = u"$USER$ " + request.PUT['message']
msg = u"$AUTO$ XML content update."
current = lib.document(docid, request.user.username)
- orig = lib.document_for_rev(prev)
+ orig = lib.document_for_rev(revision)
if current != orig:
return response.EntityConflict().django_response({
class DocumentDublinCoreHandler(BaseHandler):
allowed_methods = ('GET', 'PUT')
- @validate_form(forms.DocumentEntryRequest)
- def read(self, request, docid):
- """Read document as raw text"""
- lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
+ @hglibrary
+ def read(self, request, docid, revision, lib):
+ """Read document as raw text"""
try:
- if request.GET['revision'] == 'latest':
+ if revision == 'latest':
document = lib.document(docid)
else:
- document = lib.document_for_rev(request.GET['revision'])
+ document = lib.document_for_rev(revision)
bookinfo = dcparser.BookInfo.from_string(doc.data('xml'))
return bookinfo.serialize()
except RevisionNotFound:
return response.EntityNotFound().django_response()
- def update(self, request, docid):
- lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
+ @hglibrary
+ def update(self, request, docid, revision, lib):
try:
- bi_json = request.PUT['contents']
- prev = request.PUT['revision']
+ bi_json = request.PUT['contents']
if request.PUT.has_key('message'):
msg = u"$USER$ " + request.PUT['message']
else:
msg = u"$AUTO$ Dublin core update."
current = lib.document(docid, request.user.username)
- orig = lib.document_for_rev(prev)
+ orig = lib.document_for_rev(revision)
if current != orig:
return response.EntityConflict().django_response({
}
except (RevisionNotFound, KeyError):
return response.EntityNotFound().django_response()
+
+
+class MergeHandler(BaseHandler):
+ allowed_methods = ('POST',)
+
+ @validate_form(forms.MergeRequestForm)
+ @hglibrary
+ def create(self, request, form, docid, lib):
+ """Create a new document revision from the information provided by user"""
+
+ pass
+
+
+
+
document_resource = Resource(dh.DocumentHandler, **authdata)
document_text_resource = Resource(dh.DocumentTextHandler, **authdata)
document_dc_resource = Resource(dh.DocumentDublinCoreHandler, **authdata)
+document_merge = Resource(dh.MergeHandler, **authdata)
#
# Toolbar resources
'document_resource',
'document_text_resource',
'document_dc_resource',
+ 'document_merge',
'toolbar_buttons',
'scriptlets'
]
\ No newline at end of file
class NotImplemented(ResponseObject):
def __init__(self, **kwargs):
- ResponseObject.__init__(self, 501, **kwargs)
-
-def validate_form(formclass, source='GET'):
- from functools import wraps
-
- def decorator(func):
- @wraps(func)
- def decorated(self, request, *args, **kwargs):
- form = formclass(getattr(request, source), request.FILES)
-
- if not form.is_valid():
- errorlist = [{'field': k, 'errors': e} for k,e in form.errors]
- return BadRequest().django_response(errorlist)
-
- return func(self, request, form, *args, **kwargs)
- return decorated
- return decorator
-
-
-
-
+ ResponseObject.__init__(self, 501, **kwargs)
self.assert_json_response({
u'documents': [],
})
-
- @temprepo('clean')
- def test_documents_post(self):
- self.assertTrue(self.client.login(username='admin', password='admin'))
-
- infile = tempfile.NamedTemporaryFile("w+")
- infile.write('0123456789')
- infile.flush()
- infile.seek(0)
-
- self.response = self.client.post( reverse("document_list_view"),
- data = {
- 'bookname': 'testbook',
- 'ocr': infile,
- 'generate_dc': False,
- })
-
- infile.close()
-
- self.assert_json_response({
- 'url': reverse('document_view', args=['testbook']),
- 'name': 'testbook',
- # 'size': 10,
- # can't test revision number, 'cause it's random
- },)
-
+
@temprepo('clean')
def test_document_creation(self):
self.assertTrue(self.client.login(username='admin', password='admin'))
self.response = self.client.post( reverse("document_list_view"),
data = {
'bookname': 'testbook',
- 'ocr': infile,
+ 'ocr_file': infile,
'generate_dc': False,
})
- r = self.assert_json_response({
+ r = self.assert_json_response( {
'url': reverse('document_view', args=['testbook']),
'name': 'testbook',
# can't test revision number, 'cause it's random
- })
+ }, code=201)
created_rev = r['revision']
-
- self.response = self.client.get( \
- reverse("document_view", args=["testbook"]) )
-
+ self.response = self.client.get(r['url'])
+
result = self.assert_json_response({
- u'latest_shared_rev': created_rev,
+ u'public_revision': created_rev,
# u'size': 15,
})
self.response = self.client.get( reverse("document_list_view") )
self.assert_json_response({
# u'latest_rev': u'f94a263812dbe46a3a13d5209bb119988d0078d5',
- u'documents': [{u'url': u'/api/documents/sample', u'name': u'sample'},
- {u'url': u'/api/documents/sample_pl', u'name': u'sample_pl'}],
+ u'documents': [
+ {u'url': u'/api/documents/sample', u'name': u'sample'},
+ {u'url': u'/api/documents/sample_pl', u'name': u'sample_pl'}
+ ],
})
self.response = self.client.get( \
self.assert_json_response({
#u'latest_shared_rev': u'f94a263812dbe46a3a13d5209bb119988d0078d5',
- u'text_url': reverse("doctext_view", args=[u'sample']),
- u'dc_url': reverse("docdc_view", args=[u'sample']),
+ #u'text_url': reverse("doctext_view", args=[u'sample']),
+ #u'dc_url': reverse("docdc_view", args=[u'sample']),
# u'parts_url': reverse("docparts_view", args=[u'sample']),
u'name': u'sample',
# u'size': 20,
resp = self.assert_json_response({
#u'latest_shared_rev': u'f94a263812dbe46a3a13d5209bb119988d0078d5',
- u'text_url': reverse("doctext_view", args=[u'sample']),
- u'dc_url': reverse("docdc_view", args=[u'sample']),
+ #u'text_url': reverse("doctext_view", args=[u'sample']),
+ #u'dc_url': reverse("docdc_view", args=[u'sample']),
# u'parts_url': reverse("docparts_view", args=[u'sample']),
u'name': u'sample',
# u'size': 20,
# self.assertEqual(self.response.status_code, 200)
# self.assertEqual(self.response.content, TEXT)
- def assert_json_response(self, must_have={}, exclude=[]):
- self.assertEqual(self.response.status_code, 200)
+ def assert_json_response(self, must_have={}, exclude=[], code=200):
+ self.assertEqual(self.response.status_code, code)
result = json.loads(self.response.content)
for (k,v) in must_have.items():
from api.resources import *
-FORMAT_EXT = r"\.(?P<emitter_format>xml|json|yaml)$"
+FORMAT = r"\.(?P<emitter_format>xml|json|yaml)"
+DOC = r'(?P<docid>[^/]+)'
+REVISION = r'(?P<revision>latest|[0-9a-f]{40})'
+
+def urlpath(*args, **kwargs):
+ format = kwargs.get('format', True)
+ return r'^' + (r'/'.join(args)) + (FORMAT if format else '') + '$'
urlpatterns = patterns('',
# url(r'^hello$', hello_resource, {'emitter_format': 'json'}),
url(r'^documents$', library_resource,
{'emitter_format': 'json'}, name="document_list_view"),
- url(r'^documents'+FORMAT_EXT, library_resource,
+ url(urlpath(r'documents'), library_resource,
name="document_list_view_withformat"),
- url(r'^documents/(?P<docid>[^/]+)'+FORMAT_EXT,
+ url(urlpath(r'documents', DOC),
document_resource, name="document_view_withformat"),
- url(r'^documents/(?P<docid>[^/]+)$',
+ url(urlpath(r'documents', DOC, format=False),
document_resource, {'emitter_format': 'json'},
name="document_view"),
- url(r'^documents/(?P<docid>[^/]+)/text$',
+ url(urlpath(r'documents', DOC, 'text', REVISION, format=False),
document_text_resource, {'emitter_format': 'rawxml'},
name="doctext_view"),
- url(r'^documents/(?P<docid>[^/]+)/dc' + FORMAT_EXT,
+ url(urlpath(r'documents', DOC, 'dc', REVISION),
document_dc_resource,
name="docdc_view_withformat"),
- url(r'^documents/(?P<docid>[^/]+)/dc$',
+ url(urlpath(r'documents', DOC, 'dc', REVISION, format=False),
document_dc_resource, {'emitter_format': 'json'},
name="docdc_view"),
- url(r'^documents/(?P<docid>[^/]+)/parts$',
- document_resource, {'emitter_format': 'json'},
- name="docparts_view"),
+ url(urlpath(r'documents', DOC, 'revision'),
+ document_merge, {'emitter_format': 'json'}, name="docmerge_view")
+
+# url(r'^documents/(?P<docid>[^/]+)/parts$',
+# document_resource, {'emitter_format': 'json'},
+# name="docparts_view"),
# url(r'^posts/(?P<post_slug>[^/]+)/$', blogpost_resource),
# url(r'^other/(?P<username>[^/]+)/(?P<data>.+)/$', arbitrary_resource),
# -*- encoding: utf-8 -*-
-__author__= "Łukasz Rekucki"
+__author__ = "Łukasz Rekucki"
__date__ = "$2009-09-20 21:48:03$"
__doc__ = "Module documentation."
+from functools import wraps
from piston.emitters import Emitter
from piston.utils import rc
+import api.response
+
+from wlrepo import MercurialLibrary
+import settings
+
class TextEmitter(Emitter):
def render(self, request):
return unicode(self.construct())
return request.user.is_authenticated()
def challenge(self):
- return rc.FORBIDDEN
\ No newline at end of file
+ return rc.FORBIDDEN
+
+
+def validate_form(formclass, source='GET'):
+
+ def decorator(func):
+ @wraps(func)
+ def decorated(self, request, * args, ** kwargs):
+ form = formclass(getattr(request, source), request.FILES)
+
+ if not form.is_valid():
+ errorlist = [{'field': k, 'errors': e} for k, e in form.errors.items()]
+ return api.response.BadRequest().django_response(errorlist)
+
+ kwargs['form'] = form
+ return func(self, request, * args, ** kwargs)
+ return decorated
+ return decorator
+
+def hglibrary(func):
+ @wraps(func)
+ def decorated(self, *args, **kwargs):
+ l = MercurialLibrary(settings.REPOSITORY_PATH)
+ kwargs['lib'] = l
+ return func(self, *args, **kwargs)
+ return decorated
+
+
+
+
from django.forms.util import ErrorList
+import wlrepo
+
#
# Some useful decorators
def with_repo(view):
"""Open a repository for this view"""
def view_with_repo(request, *args, **kwargs):
- kwargs['repo'] = hg.Repository(settings.REPOSITORY_PATH)
+ kwargs['repo'] = wlrepo.MercurialLibrary(settings.REPOSITORY_PATH)
return view(request, *args, **kwargs)
return view_with_repo
# View all files
#
@with_repo
-def file_list(request, repo):
- #
- latest_default = repo.get_branch_tip('default')
-
- fl = []
- for file in repo.repo[latest_default]:
- m = re.match(u'^pub_([^/]+).xml$', file.decode('utf-8'), re.UNICODE)
- if m is not None:
- fl.append(m.group(1))
-
- bookform = forms.BookUploadForm()
-
+def file_list(request, repo):
+ import api.forms
+ bookform = api.forms.DocumentUploadForm()
return direct_to_template(request, 'explorer/file_list.html', extra_context={
- 'files': fl, 'bookform': bookform,
+ 'files': repo.documents(), 'bookform': bookform,
})
@permission_required('explorer.can_add_files')
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:p="http://platforma.wolnelektury.pl/">
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <title>Platforma Redakcyjna</title>
+
+ </head>
+ <body id="base">
+ <h2>Przepraszamy,</h2>
+ <p>Platfroma Redakcyjna jest tymczasowo niedostępna
+ z powodu prac administracyjnych.</p>
+
+ <p>Prosimy o wyrozumiałość i ponowne odwiedziny :)</p>
+ </body>
+</html>
{% if perms.explorer.can_add_files %}
<div class="upload-file-widget">
<h2>Dodaj nowy utwór</h2>
-<form action="{% url file_upload %}" method="POST" enctype="multipart/form-data">
- <p><label>{{bookform.file.label}}: {{ bookform.file }}</label></p>
- <p><label>{{bookform.bookname.label}}: {{bookform.bookname}}</label></p>
- <p><label>{{bookform.autoxml}} {{bookform.autoxml.label}}</label></p>
+<form action="/api/documents" method="POST" enctype="multipart/form-data">
+ {{ bookform }}
<p><button type="submit">Dodaj książkę</button></p>
</form>
</div>