More changes to the REST API.
[redakcja.git] / apps / api / handlers / library_handlers.py
1 # -*- encoding: utf-8 -*-
2
3 __author__= "Ɓukasz Rekucki"
4 __date__ = "$2009-09-25 15:49:50$"
5 __doc__ = "Module documentation."
6
7 from piston.handler import BaseHandler, AnonymousBaseHandler
8
9
10 import settings
11 import librarian
12 import api.forms as forms
13 from datetime import date
14
15 from django.core.urlresolvers import reverse
16
17 from wlrepo import MercurialLibrary, RevisionNotFound, DocumentAlreadyExists
18 from librarian import dcparser
19
20 import api.response as response
21 from api.response import validate_form
22
23 #
24 # Document List Handlers
25 #
26 class BasicLibraryHandler(AnonymousBaseHandler):
27     allowed_methods = ('GET',)
28
29     def read(self, request):
30         """Return the list of documents."""
31         lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
32
33         document_list = [{
34             'url': reverse('document_view', args=[docid]),
35             'name': docid } for docid in lib.documents() ]
36
37         return {'documents' : document_list}
38
39 class LibraryHandler(BaseHandler):
40     allowed_methods = ('GET', 'POST')
41     anonymous = BasicLibraryHandler
42
43     def read(self, request):
44         """Return the list of documents."""
45         lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
46
47         document_list = [{
48             'url': reverse('document_view', args=[docid]),
49             'name': docid } for docid in lib.documents() ]
50
51         return {'documents' : document_list }
52
53     @validate_form(forms.DocumentUploadForm, 'POST')
54     def create(self, request, form):
55         """Create a new document."""
56         lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
57
58         if form.cleaned_data['ocr_data']:
59             data = form.cleaned_data['ocr_data'].encode('utf-8')
60         else:            
61             data = request.FILES['ocr'].read().decode('utf-8')
62
63         if form.cleaned_data['generate_dc']:
64             data = librarian.wrap_text(data, unicode(date.today()))
65
66         docid = form.cleaned_data['bookname']
67         try:
68             doc = lib.document_create(docid)
69             doc.quickwrite('xml', data, '$AUTO$ XML data uploaded.',
70                 user=request.user.username)
71
72             url = reverse('document_view', args=[doc.id])
73
74
75             return response.EntityCreated().django_response(\
76                 body = {
77                     'url': url,
78                     'name': doc.id,
79                     'revision': doc.revision },
80                 url = url )
81                 
82         except DocumentAlreadyExists:
83             # Document is already there
84             return response.EntityConflict().django_response(\
85                 {"reason": "Document %s already exists." % docid})
86
87 #
88 # Document Handlers
89 #
90 class BasicDocumentHandler(AnonymousBaseHandler):
91     allowed_methods = ('GET',)
92
93     def read(self, request, docid):
94         try:
95             lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
96             doc = lib.document(docid)
97         except RevisionNotFound:
98             return rc.NOT_FOUND
99
100         result = {
101             'name': doc.id,
102             'text_url': reverse('doctext_view', args=[doc.id]),
103             'dc_url': reverse('docdc_view', docid=doc.id),
104             'public_revision': doc.revision,
105         }
106
107         return result
108
109 #
110 # Document Meta Data
111 #
112 class DocumentHandler(BaseHandler):
113     allowed_methods = ('GET', 'PUT')
114     anonymous = BasicDocumentHandler
115
116     def read(self, request, docid):
117         """Read document's meta data"""
118         lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
119         
120         try:
121             doc = lib.document(docid)
122             udoc = doc.take(request.user.username)
123         except RevisionNotFound:
124             return request.EnityNotFound().django_response()
125
126         # is_shared = udoc.ancestorof(doc)
127         # is_uptodate = is_shared or shared.ancestorof(document)
128
129         result = {
130             'name': udoc.id,
131             'text_url': reverse('doctext_view', args=[udoc.id]),
132             'dc_url': reverse('docdc_view', args=[udoc.id]),
133             'parts_url': reverse('docparts_view', args=[udoc.id]),
134             'user_revision': udoc.revision,
135             'public_revision': doc.revision,            
136         }       
137
138         return result
139
140 #
141 # Document Text View
142 #
143 class DocumentTextHandler(BaseHandler):
144     allowed_methods = ('GET', 'PUT')
145
146     @validate_form(forms.DocumentEntryRequest)
147     def read(self, request, form, docid):
148         """Read document as raw text"""        
149         lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
150         
151         try:
152             if request.GET['revision'] == 'latest':
153                 document = lib.document(docid)
154             else:
155                 document = lib.document_for_rev(request.GET['revision'])
156             
157             # TODO: some finer-grained access control
158             return document.data('xml')
159         except RevisionNotFound:
160             return response.EntityNotFound().django_response()
161
162     def update(self, request, docid):
163         lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
164         try:
165             data = request.PUT['contents']
166             prev = request.PUT['revision']
167
168             if request.PUT.has_key('message'):
169                 msg = u"$USER$ " + request.PUT['message']
170             else:
171                 msg = u"$AUTO$ XML content update."
172
173             current = lib.document(docid, request.user.username)
174             orig = lib.document_for_rev(prev)
175
176             if current != orig:
177                 return response.EntityConflict().django_response({
178                         "reason": "out-of-date",
179                         "provided_revision": orig.revision,
180                         "latest_revision": current.revision })
181
182             ndoc = doc.quickwrite('xml', data, msg)
183
184             # return the new revision number
185             return {
186                 "document": ndoc.id,
187                 "subview": "xml",
188                 "previous_revision": prev,
189                 "updated_revision": ndoc.revision
190             }
191         
192         except (RevisionNotFound, KeyError):
193             return response.EntityNotFound().django_response()
194
195 #
196 # Dublin Core handlers
197 #
198 # @requires librarian
199 #
200 class DocumentDublinCoreHandler(BaseHandler):
201     allowed_methods = ('GET', 'PUT')
202
203     @validate_form(forms.DocumentEntryRequest)
204     def read(self, request, docid):
205         """Read document as raw text"""
206         lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
207         try:
208             if request.GET['revision'] == 'latest':
209                 document = lib.document(docid)
210             else:
211                 document = lib.document_for_rev(request.GET['revision'])                
212             
213             bookinfo = dcparser.BookInfo.from_string(doc.data('xml'))
214             return bookinfo.serialize()
215         except RevisionNotFound:
216             return response.EntityNotFound().django_response()
217
218     def update(self, request, docid):
219         lib = MercurialLibrary(path=settings.REPOSITORY_PATH)
220         try:
221             bi_json = request.PUT['contents']
222             prev = request.PUT['revision']
223             if request.PUT.has_key('message'):
224                 msg = u"$USER$ " + request.PUT['message']
225             else:
226                 msg = u"$AUTO$ Dublin core update."
227
228             current = lib.document(docid, request.user.username)
229             orig = lib.document_for_rev(prev)
230
231             if current != orig:
232                 return response.EntityConflict().django_response({
233                         "reason": "out-of-date",
234                         "provided": orig.revision,
235                         "latest": current.revision })
236
237             xmldoc = parser.WLDocument.from_string(current.data('xml'))
238             document.book_info = dcparser.BookInfo.from_json(bi_json)
239
240             # zapisz
241             ndoc = current.quickwrite('xml', \
242                 document.serialize().encode('utf-8'),\
243                 message=msg, user=request.user.username)
244
245             return {
246                 "document": ndoc.id,
247                 "subview": "xml",
248                 "previous_revision": prev,
249                 "updated_revision": ndoc.revision
250             }
251         except (RevisionNotFound, KeyError):
252             return response.EntityNotFound().django_response()