Merge branch 'master' into view-refactor
authorzuber <marek@stepniowski.com>
Sat, 26 Sep 2009 12:16:19 +0000 (14:16 +0200)
committerzuber <marek@stepniowski.com>
Sat, 26 Sep 2009 12:16:19 +0000 (14:16 +0200)
apps/api/forms.py
apps/api/handlers/library_handlers.py
apps/api/resources.py
apps/api/response.py
apps/api/tests/__init__.py
apps/api/urls.py
apps/api/utils.py
apps/explorer/views.py
project/templates/503.html [new file with mode: 0644]
project/templates/explorer/file_list.html

index 7c6f2c2..3c393a8 100644 (file)
@@ -7,8 +7,16 @@ __doc__ = "Micro-forms for the API."
 
 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)
index 18dd3e8..0651352 100644 (file)
@@ -18,7 +18,7 @@ from wlrepo import MercurialLibrary, RevisionNotFound, DocumentAlreadyExists
 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
@@ -26,10 +26,9 @@ from api.response import validate_form
 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() ]
@@ -41,9 +40,9 @@ class LibraryHandler(BaseHandler):
     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]),
@@ -52,14 +51,14 @@ class LibraryHandler(BaseHandler):
         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()))
@@ -67,12 +66,11 @@ class LibraryHandler(BaseHandler):
         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,
@@ -91,17 +89,17 @@ class LibraryHandler(BaseHandler):
 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,
         }
 
@@ -114,10 +112,9 @@ class DocumentHandler(BaseHandler):
     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)
@@ -129,16 +126,16 @@ class DocumentHandler(BaseHandler):
 
         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
 
@@ -148,27 +145,24 @@ class DocumentHandler(BaseHandler):
 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']
@@ -176,7 +170,7 @@ class DocumentTextHandler(BaseHandler):
                 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({
@@ -205,33 +199,31 @@ class DocumentTextHandler(BaseHandler):
 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({
@@ -255,3 +247,18 @@ class DocumentDublinCoreHandler(BaseHandler):
             }
         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
+
+        
+        
+        
index d45fa1d..7681436 100644 (file)
@@ -21,6 +21,7 @@ library_resource = Resource(dh.LibraryHandler, **authdata)
 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
@@ -34,6 +35,7 @@ __all__ = [
     'document_resource',
     'document_text_resource',
     'document_dc_resource',
+    'document_merge',
     'toolbar_buttons',
     'scriptlets'
 ]
\ No newline at end of file
index 6b68562..c140163 100644 (file)
@@ -101,26 +101,6 @@ class EntityConflict(ResponseObject):
 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) 
 
 
index 2292e7d..acf92f5 100644 (file)
@@ -63,32 +63,7 @@ class SimpleTest(TestCase):
         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'))
@@ -101,23 +76,21 @@ class SimpleTest(TestCase):
         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,
         })
 
@@ -129,8 +102,10 @@ class SimpleTest(TestCase):
         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( \
@@ -138,8 +113,8 @@ class SimpleTest(TestCase):
 
         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,
@@ -155,8 +130,8 @@ class SimpleTest(TestCase):
 
         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,
@@ -181,8 +156,8 @@ class SimpleTest(TestCase):
 #        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():
index de09605..8c10158 100644 (file)
@@ -5,7 +5,13 @@ from django.conf.urls.defaults import *
 
 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'}),
@@ -21,31 +27,34 @@ urlpatterns = patterns('',
     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),
index 4b004ee..0e0468a 100644 (file)
@@ -1,13 +1,19 @@
 # -*- 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())
@@ -21,4 +27,33 @@ class DjangoAuth(object):
         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
+    
+            
+        
+
index 889fda5..e3ca63a 100644 (file)
@@ -22,6 +22,8 @@ from toolbar import models as toolbar_models
 
 from django.forms.util import ErrorList
 
+import wlrepo
+
 #
 # Some useful decorators
 
@@ -36,7 +38,7 @@ def file_path(fileid):
 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
 
@@ -55,20 +57,11 @@ def ajax_login_required(view):
 # 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')
diff --git a/project/templates/503.html b/project/templates/503.html
new file mode 100644 (file)
index 0000000..1c2e4d2
--- /dev/null
@@ -0,0 +1,16 @@
+<!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>
index 7612a71..bf6758f 100644 (file)
@@ -81,10 +81,8 @@ $(function() {
 {% 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>