From: zuber Date: Sat, 26 Sep 2009 11:30:35 +0000 (+0200) Subject: Merge branch 'master' into view-refactor X-Git-Url: https://git.mdrn.pl/redakcja.git/commitdiff_plain/dba809feb44cd1c4d155f3e3254a1cca5323f95f?hp=392251a9a79eb96a0fd51438c64606d70ade3395 Merge branch 'master' into view-refactor Conflicts: project/static/css/master.css --- diff --git a/apps/api/forms.py b/apps/api/forms.py index 2b09e178..7c6f2c22 100644 --- a/apps/api/forms.py +++ b/apps/api/forms.py @@ -7,14 +7,28 @@ __doc__ = "Micro-forms for the API." from django import forms -class DocumentGetForm(forms.Form): - autocabinet = forms.BooleanField(required=False) - +class DocumentEntryRequest(forms.Form): + revision = forms.RegexField(regex='latest|[0-9a-f]{40}') class DocumentUploadForm(forms.Form): - ocr = forms.FileField(label='Source OCR file') + ocr_file = forms.FileField(label='Source OCR file', required=False) + ocr_data = forms.CharField(widget=forms.HiddenInput(), required=False) + bookname = forms.RegexField(regex=r'[0-9\.\w_-]+', \ label='Publication name', help_text='Example: slowacki-beniowski') - generate_dc = forms.BooleanField(required=False, initial=True, label=u"Generate DublinCore template") + generate_dc = forms.BooleanField(required=False, \ + initial=True, label=u"Generate DublinCore template") + + + def clean(self): + clean_data = self.cleaned_data + + ocr_file = clean_data['ocr_file'] + ocr_data = clean_data['ocr_data'] + + if not ocr_file and not ocr_data: + raise forms.ValidationError( + "You must either provide file descriptor or raw data." ) + return clean_data \ No newline at end of file diff --git a/apps/api/handlers.py b/apps/api/handlers.py deleted file mode 100644 index 352e35e4..00000000 --- a/apps/api/handlers.py +++ /dev/null @@ -1,157 +0,0 @@ -from piston.handler import BaseHandler, AnonymousBaseHandler -from piston.utils import rc, validate - -import settings -import librarian -import api.forms as forms -from datetime import date - -from django.core.urlresolvers import reverse -from wlrepo import MercurialLibrary, CabinetNotFound - -# -# Document List Handlers -# -class BasicLibraryHandler(AnonymousBaseHandler): - allowed_methods = ('GET',) - - def read(self, request): - """Return the list of documents.""" - lib = MercurialLibrary(path=settings.REPOSITORY_PATH) - cab = lib.main_cabinet - - document_list = [{ - 'url': reverse('document_view', args=[docid]), - 'name': docid } for docid in cab.documents() ] - - return { - 'cabinet': cab.name, - 'latest_rev': cab.shelf(), - 'documents' : document_list } - -class LibraryHandler(BaseHandler): - allowed_methods = ('GET', 'POST') - anonymous = BasicLibraryHandler - - def read(self, request): - """Return the list of documents.""" - lib = MercurialLibrary(path=settings.REPOSITORY_PATH) - cab = lib.main_cabinet - - document_list = [{ - 'url': reverse('document_view', args=[docid]), - 'name': docid } for docid in cab.documents() ] - - return { - 'cabinet': cab.name, - 'latest_rev': cab.shelf(), - 'documents' : document_list } - - def create(self, request): - """Create a new document.""" - lib = MercurialLibrary(path=settings.REPOSITORY_PATH) - cab = lib.main_cabinet - - form = forms.DocumentUploadForm(request.POST, request.FILES) - if not form.is_valid(): - return rc.BAD_REQUEST - - f = request.FILES['ocr'] - data = f.read().decode('utf-8') - - if form.cleaned_data['generate_dc']: - data = librarian.wrap_text(data, unicode(date.today())) - - doc = cab.create(form.cleaned_data['bookname'], initial_data=data) - - return { - 'url': reverse('document_view', args=[doc.name]), - 'name': doc.name, - 'size': doc.size, - 'revision': doc.shelf() } - -# -# Document Handlers -# -class BasicDocumentHandler(AnonymousBaseHandler): - allowed_methods = ('GET',) - - def read(self, request, docid): - lib = MercurialLibrary(path=settings.REPOSITORY_PATH) - - opts = forms.DocumentGetForm(request.GET) - if not opts.is_valid(): - return rc.BAD_REQUEST - - document = lib.main_cabinet.retrieve(docid) - - result = { - 'name': document.name, - 'size': document.size, - 'text_url': reverse('doctext_view', args=[docid]), - #'dc_url': reverse('docdc_view', docid=document.name), - #'parts_url': reverse('docparts_view', docid=document.name), - 'latest_rev': document.shelf(), - } - - if request.GET.get('with_part', 'no') == 'yes': - result['parts'] = document.parts() - - return result - -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) - - opts = forms.DocumentGetForm(request.GET) - if not opts.is_valid(): - return rc.BAD_REQUEST - - document = lib.cabinet(docid, request.user.username, \ - create=opts.cleaned_data['autocabinet'] ).retrieve() - - shared = lib.main_cabinet.retrieve(docid) - - result = { - 'name': document.name, - 'size': document.size, - 'text_url': reverse('doctext_view', args=[docid]), - 'dc_url': reverse('docdc_view', args=[docid]), - 'parts_url': reverse('docparts_view', args=[docid]), - 'latest_rev': document.shelf(), - 'latest_shared_rev': shared.shelf(), - #'shared': lib.isparentof(document, shared), - #'up_to_date': lib.isparentof(shared, document), - } - - if request.GET.get('with_part', 'no') == 'yes': - result['parts'] = document.parts() - - return result - -# -# Document Text View -# -class DocumentTextHandler(BaseHandler): - allowed_methods = ('GET', 'PUT') - - def read(self, request, docid): - """Read document as raw text""" - lib = MercurialLibrary(path=settings.REPOSITORY_PATH) - try: - return lib.document(docid, request.user.username).read() - except CabinetNotFound: - return rc.NOT_HERE - - def update(self, request, docid): - lib = MercurialLibrary(path=settings.REPOSITORY_PATH) - try: - data = request.PUT['contents'] - lib.document(docid, request.user.username).write(data) - return rc.ALL_OK - except (CabinetNotFound, KeyError): - return rc.NOT_HERE \ No newline at end of file diff --git a/apps/api/handlers/__init__.py b/apps/api/handlers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/api/handlers/library_handlers.py b/apps/api/handlers/library_handlers.py new file mode 100644 index 00000000..18dd3e81 --- /dev/null +++ b/apps/api/handlers/library_handlers.py @@ -0,0 +1,257 @@ +# -*- encoding: utf-8 -*- + +__author__= "Łukasz Rekucki" +__date__ = "$2009-09-25 15:49:50$" +__doc__ = "Module documentation." + +from piston.handler import BaseHandler, AnonymousBaseHandler + + +import settings +import librarian +import api.forms as forms +from datetime import date + +from django.core.urlresolvers import reverse + +from wlrepo import MercurialLibrary, RevisionNotFound, DocumentAlreadyExists +from librarian import dcparser + +import api.response as response +from api.response import validate_form + +# +# Document List Handlers +# +class BasicLibraryHandler(AnonymousBaseHandler): + allowed_methods = ('GET',) + + def read(self, request): + """Return the list of documents.""" + lib = MercurialLibrary(path=settings.REPOSITORY_PATH) + + document_list = [{ + 'url': reverse('document_view', args=[docid]), + 'name': docid } for docid in lib.documents() ] + + return {'documents' : document_list} + + +class LibraryHandler(BaseHandler): + allowed_methods = ('GET', 'POST') + anonymous = BasicLibraryHandler + + def read(self, request): + """Return the list of documents.""" + lib = MercurialLibrary(path=settings.REPOSITORY_PATH) + + document_list = [{ + 'url': reverse('document_view', args=[docid]), + 'name': docid } for docid in lib.documents() ] + + return {'documents' : document_list } + + @validate_form(forms.DocumentUploadForm, 'POST') + def create(self, request, form): + """Create a new document.""" + lib = MercurialLibrary(path=settings.REPOSITORY_PATH) + + if form.cleaned_data['ocr_data']: + data = form.cleaned_data['ocr_data'].encode('utf-8') + else: + data = request.FILES['ocr'].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.', + user=request.user.username) + + url = reverse('document_view', args=[doc.id]) + + + return response.EntityCreated().django_response(\ + body = { + 'url': url, + 'name': doc.id, + 'revision': doc.revision }, + url = url ) + + except DocumentAlreadyExists: + # Document is already there + return response.EntityConflict().django_response(\ + {"reason": "Document %s already exists." % docid}) + +# +# Document Handlers +# +class BasicDocumentHandler(AnonymousBaseHandler): + allowed_methods = ('GET',) + + def read(self, request, docid): + try: + lib = MercurialLibrary(path=settings.REPOSITORY_PATH) + 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), + 'public_revision': doc.revision, + } + + return result + +# +# Document Meta Data +# +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) + + try: + doc = lib.document(docid) + udoc = doc.take(request.user.username) + except RevisionNotFound: + return request.EnityNotFound().django_response() + + # is_shared = udoc.ancestorof(doc) + # is_uptodate = is_shared or shared.ancestorof(document) + + 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]), + 'user_revision': udoc.revision, + 'public_revision': doc.revision, + } + + return result + + def update(self, request, docid): + """Update information about the document, like display not""" + return + +# +# Document Text View +# +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) + + try: + if request.GET['revision'] == 'latest': + document = lib.document(docid) + else: + document = lib.document_for_rev(request.GET['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) + try: + data = request.PUT['contents'] + prev = request.PUT['revision'] + + if request.PUT.has_key('message'): + msg = u"$USER$ " + request.PUT['message'] + else: + msg = u"$AUTO$ XML content update." + + current = lib.document(docid, request.user.username) + orig = lib.document_for_rev(prev) + + if current != orig: + return response.EntityConflict().django_response({ + "reason": "out-of-date", + "provided_revision": orig.revision, + "latest_revision": current.revision }) + + ndoc = doc.quickwrite('xml', data, msg) + + # return the new revision number + return { + "document": ndoc.id, + "subview": "xml", + "previous_revision": prev, + "updated_revision": ndoc.revision + } + + except (RevisionNotFound, KeyError): + return response.EntityNotFound().django_response() + +# +# Dublin Core handlers +# +# @requires librarian +# +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) + try: + if request.GET['revision'] == 'latest': + document = lib.document(docid) + else: + document = lib.document_for_rev(request.GET['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) + try: + bi_json = request.PUT['contents'] + prev = request.PUT['revision'] + 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) + + if current != orig: + return response.EntityConflict().django_response({ + "reason": "out-of-date", + "provided": orig.revision, + "latest": current.revision }) + + xmldoc = parser.WLDocument.from_string(current.data('xml')) + document.book_info = dcparser.BookInfo.from_json(bi_json) + + # zapisz + ndoc = current.quickwrite('xml', \ + document.serialize().encode('utf-8'),\ + message=msg, user=request.user.username) + + return { + "document": ndoc.id, + "subview": "xml", + "previous_revision": prev, + "updated_revision": ndoc.revision + } + except (RevisionNotFound, KeyError): + return response.EntityNotFound().django_response() diff --git a/apps/api/handlers/toolbar_handlers.py b/apps/api/handlers/toolbar_handlers.py new file mode 100644 index 00000000..be773590 --- /dev/null +++ b/apps/api/handlers/toolbar_handlers.py @@ -0,0 +1,32 @@ +# -*- encoding: utf-8 -*- + +__author__= "Łukasz Rekucki" +__date__ = "$2009-09-25 15:55:33$" +__doc__ = "Module documentation." + +from django.views.generic.simple import direct_to_template +from piston.handler import BaseHandler +from piston.utils import rc + +import settings + +import toolbar.models + +class ToolbarHandler(BaseHandler): + allowed_methods = ('GET',) + + def read(self, request): + groups = toolbar.models.ButtonGroup.objects.all() + return [ {'name': g.name, 'position': g.position,\ + 'buttons': g.button_set.all()} for g in groups ] + + +class ScriptletsHandler(BaseHandler): + allowed_methods = ('GET',) + + def read(self, request): + scriptlets = toolbar.models.Scriptlet.objects.all() + + return direct_to_template(request, 'toolbar_api/scriptlets.js', + extra_context = {'scriptlets': scriptlets }, + mimetype='text/javascript' ) \ No newline at end of file diff --git a/apps/api/resources.py b/apps/api/resources.py new file mode 100644 index 00000000..d45fa1d7 --- /dev/null +++ b/apps/api/resources.py @@ -0,0 +1,39 @@ +# -*- encoding: utf-8 -*- + +__author__= "Łukasz Rekucki" +__date__ = "$2009-09-25 15:53:00$" +__doc__ = "Module documentation." + +from piston.resource import Resource +from api.utils import DjangoAuth + + + + +authdata = {'authentication': DjangoAuth()} + +# +# Library resources +# + +import api.handlers.library_handlers as dh +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) + +# +# Toolbar resources +# +import api.handlers.toolbar_handlers as th +toolbar_buttons = Resource(th.ToolbarHandler, **authdata) +scriptlets = Resource(th.ScriptletsHandler, **authdata) + +__all__ = [ + 'library_resource', + 'document_resource', + 'document_text_resource', + 'document_dc_resource', + 'toolbar_buttons', + 'scriptlets' +] \ No newline at end of file diff --git a/apps/api/response.py b/apps/api/response.py new file mode 100644 index 00000000..6b685624 --- /dev/null +++ b/apps/api/response.py @@ -0,0 +1,126 @@ +# -*- encoding: utf-8 -*- + +__author__= "Łukasz Rekucki" +__date__ = "$2009-09-26 00:32:18$" +__doc__ = "Extensible HTTP Responses." + +from django.http import HttpResponse +from django.utils import simplejson as json + +MIME_PLAIN = 'text/plain' +MIME_JSON = 'application/json' + +class ResponseObject(object): + + def __init__(self, code, mimetype=MIME_JSON): + self._code = code + self._mime = mimetype + + def django_response(self, body=None): + if body is None: + data = '' + elif self._mime == MIME_JSON: + data = json.dumps(body, default=lambda o: repr(o) ) + else: + data = u"%s\n%s" % (self.MESSAGE, unicode(body)) + data = data.encode('utf-8') + + return HttpResponse(content=data, status=self._code, \ + content_type=self._mime+'; charset=utf-8' ) + +class SuccessAllOk(ResponseObject): + def __init__(self, **kwargs): + ResponseObject.__init__(self, 200, **kwargs) + +class EntityCreated(ResponseObject): + + def __init__(self, **kwargs): + ResponseObject.__init__(self, 201, **kwargs) + + def django_response(self, url, body): + response = ResponseObject.django_response(self, body) + response['Location'] = url + return response + +class RequestAccepted(ResponseObject): + + def __init__(self, **kwargs): + ResponseObject.__init__(self, 202, **kwargs) + + def django_response(self, ticket_status, ticket_uri): + return ResponseObject.django_response(self, { + 'status': ticket_status, + 'refer_to': ticket_uri }) + +class SuccessNoContent(ResponseObject): + + def __init__(self, **kwargs): + ResponseObject.__init__(self, 204, **kwargs) + + def django_response(self): + return ResponseObject.django_response(self, body=None) + +# +# Client errors +# + +class BadRequest(ResponseObject): + + def __init__(self, **kwargs): + ResponseObject.__init__(self, 400, **kwargs) + +class AccessDenied(ResponseObject): + + def __init__(self, **kwargs): + ResponseObject.__init__(self, 403, **kwargs) + + def django_response(self, reason): + return ResponseObject.django_response(self, \ + body={'reason': reason}) + +class EntityNotFound(ResponseObject): + + def __init__(self, **kwargs): + ResponseObject.__init__(self, 404, **kwargs) + +class EntityGone(ResponseObject): + + def __init__(self, **kwargs): + ResponseObject.__init__(self, 410, **kwargs) + + +class EntityConflict(ResponseObject): + + def __init__(self, **kwargs): + ResponseObject.__init__(self, 409, **kwargs) + + +# +# Server side errors +# +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 + + + + + + diff --git a/apps/api/tests/__init__.py b/apps/api/tests/__init__.py index 671978a1..2292e7dd 100644 --- a/apps/api/tests/__init__.py +++ b/apps/api/tests/__init__.py @@ -1,10 +1,3 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". - -Replace these with more appropriate tests for your application. -""" - from django.test import TestCase from django.test.client import Client from django.core.urlresolvers import reverse @@ -22,11 +15,15 @@ import tempfile REPO_TEMPLATES = join(dirname(__file__), 'data') def temprepo(name): - def decorator(func): + from functools import wraps + + def decorator(func): + + @wraps(func) def decorated(self, *args, **kwargs): clean = False try: - temp = tempfile.mkdtemp("", "testdir_" ) + temp = tempfile.mkdtemp("-test", func.__name__) shutil.copytree(join(REPO_TEMPLATES, name), join(temp, 'repo'), False) settings.REPOSITORY_PATH = join(temp, 'repo') func(self, *args, **kwargs) @@ -37,9 +34,9 @@ def temprepo(name): print self.response print "<<<" - shutil.rmtree(temp, True) + # shutil.rmtree(temp, True) settings.REPOSITORY_PATH = '' - + return decorated return decorator @@ -51,27 +48,23 @@ class SimpleTest(TestCase): u = User.objects.create_user('admin', 'test@localhost', 'admin') u.save() - @temprepo('empty') + @temprepo('clean') def test_documents_get_anonymous(self): self.response = self.client.get( reverse("document_list_view") ) - self.assert_json_response({ - u'latest_rev': u'e56b2a7e06a97d7c3697fc4295974e0f20a66190', - u'documents': [], - u'cabinet': u'default', - }, exclude=['latest_shared_rev']) + self.assert_json_response({ + u'documents': [], + }) - @temprepo('empty') + @temprepo('clean') def test_documents_get_with_login(self): self.assertTrue(self.client.login(username='admin', password='admin')) self.response = self.client.get( reverse("document_list_view") ) - self.assert_json_response({ - u'latest_rev': u'e56b2a7e06a97d7c3697fc4295974e0f20a66190', - u'documents': [], - u'cabinet': u'default', + self.assert_json_response({ + u'documents': [], }) - @temprepo('empty') + @temprepo('clean') def test_documents_post(self): self.assertTrue(self.client.login(username='admin', password='admin')) @@ -79,8 +72,8 @@ class SimpleTest(TestCase): infile.write('0123456789') infile.flush() infile.seek(0) - - self.response = self.client.post( reverse("document_list_view"), + + self.response = self.client.post( reverse("document_list_view"), data = { 'bookname': 'testbook', 'ocr': infile, @@ -88,15 +81,15 @@ class SimpleTest(TestCase): }) infile.close() - - result = self.assert_json_response({ + + self.assert_json_response({ 'url': reverse('document_view', args=['testbook']), 'name': 'testbook', - 'size': 10, + # 'size': 10, # can't test revision number, 'cause it's random },) - @temprepo('empty') + @temprepo('clean') def test_document_creation(self): self.assertTrue(self.client.login(username='admin', password='admin')) @@ -111,73 +104,82 @@ class SimpleTest(TestCase): 'ocr': infile, 'generate_dc': False, }) - + r = self.assert_json_response({ 'url': reverse('document_view', args=['testbook']), - 'name': 'testbook', - 'size': 15, + 'name': 'testbook', # can't test revision number, 'cause it's random }) created_rev = r['revision'] self.response = self.client.get( \ - reverse("document_view", args=["testbook"])+'?autocabinet=true' ) + reverse("document_view", args=["testbook"]) ) result = self.assert_json_response({ u'latest_shared_rev': created_rev, - u'size': 15, + # u'size': 15, }) - @temprepo('testone') + @temprepo('simple') def test_document_meta_get_with_login(self): self.assertTrue(self.client.login(username='admin', password='admin')) 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/testfile', u'name': u'testfile'}], - u'cabinet': u'default', + # 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'}], }) self.response = self.client.get( \ - reverse("document_view", args=['testfile'])+'?autocabinet=true' ) + reverse("document_view", args=['sample']) ) self.assert_json_response({ - u'latest_shared_rev': u'f94a263812dbe46a3a13d5209bb119988d0078d5', - u'text_url': reverse("doctext_view", args=[u'testfile']), - u'dc_url': reverse("docdc_view", args=[u'testfile']), - u'parts_url': reverse("docparts_view", args=[u'testfile']), - u'name': u'testfile', - u'size': 20, + #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'parts_url': reverse("docparts_view", args=[u'sample']), + u'name': u'sample', + # u'size': 20, }) - - - @temprepo('test2') - def test_document_text_with_login(self): - self.assertTrue(self.client.login(username='admin', password='admin')) - - self.response = self.client.get( \ - reverse("doctext_view", args=['testfile']) ) - - self.assertEqual(self.response.status_code, 200) - self.assertEqual(self.response.content, "Test file contents.\n") - @temprepo('test2') - def test_document_text_update(self): + @temprepo('simple') + def test_document_text_with_login(self): self.assertTrue(self.client.login(username='admin', password='admin')) - TEXT = u"Ala ma kota i psa" - - self.response = self.client.put( \ - reverse("doctext_view", args=['testfile']), {'contents': TEXT }) - self.assertEqual(self.response.status_code, 200) self.response = self.client.get( \ - reverse("doctext_view", args=['testfile']) ) + reverse("document_view", args=['sample']) ) + + 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'parts_url': reverse("docparts_view", args=[u'sample']), + u'name': u'sample', + # u'size': 20, + }) + + self.response = self.client.get(resp['text_url']) self.assertEqual(self.response.status_code, 200) - self.assertEqual(self.response.content, TEXT) + self.assertEqual(self.response.content, "Ala ma kota\n") +# +# +# @temprepo('simple') +# def test_document_text_update(self): +# self.assertTrue(self.client.login(username='admin', password='admin')) +# TEXT = u"Ala ma kota i psa" +# +# self.response = self.client.put( \ +# reverse("doctext_view", args=['testfile']), {'contents': TEXT }) +# self.assertEqual(self.response.status_code, 200) +# +# self.response = self.client.get( \ +# reverse("doctext_view", args=['testfile']) ) +# 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) diff --git a/apps/api/tests/data/clean/$meta b/apps/api/tests/data/clean/$meta new file mode 100644 index 00000000..e69de29b diff --git a/apps/api/tests/data/clean/.hg/00changelog.i b/apps/api/tests/data/clean/.hg/00changelog.i new file mode 100644 index 00000000..d3a83110 Binary files /dev/null and b/apps/api/tests/data/clean/.hg/00changelog.i differ diff --git a/apps/api/tests/data/clean/.hg/dirstate b/apps/api/tests/data/clean/.hg/dirstate new file mode 100644 index 00000000..417cb6ba Binary files /dev/null and b/apps/api/tests/data/clean/.hg/dirstate differ diff --git a/apps/api/tests/data/clean/.hg/requires b/apps/api/tests/data/clean/.hg/requires new file mode 100644 index 00000000..5175383b --- /dev/null +++ b/apps/api/tests/data/clean/.hg/requires @@ -0,0 +1,3 @@ +revlogv1 +store +fncache diff --git a/apps/api/tests/data/clean/.hg/store/00changelog.i b/apps/api/tests/data/clean/.hg/store/00changelog.i new file mode 100644 index 00000000..671cfac1 Binary files /dev/null and b/apps/api/tests/data/clean/.hg/store/00changelog.i differ diff --git a/apps/api/tests/data/clean/.hg/store/00manifest.i b/apps/api/tests/data/clean/.hg/store/00manifest.i new file mode 100644 index 00000000..6f5dfeb7 Binary files /dev/null and b/apps/api/tests/data/clean/.hg/store/00manifest.i differ diff --git a/apps/api/tests/data/clean/.hg/store/data/$meta.i b/apps/api/tests/data/clean/.hg/store/data/$meta.i new file mode 100644 index 00000000..2431023a Binary files /dev/null and b/apps/api/tests/data/clean/.hg/store/data/$meta.i differ diff --git a/apps/api/tests/data/clean/.hg/store/data/.hgignore.i b/apps/api/tests/data/clean/.hg/store/data/.hgignore.i new file mode 100644 index 00000000..2431023a Binary files /dev/null and b/apps/api/tests/data/clean/.hg/store/data/.hgignore.i differ diff --git a/apps/api/tests/data/clean/.hg/store/data/.hgtags.i b/apps/api/tests/data/clean/.hg/store/data/.hgtags.i new file mode 100644 index 00000000..74da2382 Binary files /dev/null and b/apps/api/tests/data/clean/.hg/store/data/.hgtags.i differ diff --git a/apps/api/tests/data/clean/.hg/store/fncache b/apps/api/tests/data/clean/.hg/store/fncache new file mode 100644 index 00000000..3a7e3204 --- /dev/null +++ b/apps/api/tests/data/clean/.hg/store/fncache @@ -0,0 +1,3 @@ +data/$meta.i +data/.hgignore.i +data/.hgtags.i diff --git a/apps/api/tests/data/clean/.hg/store/undo b/apps/api/tests/data/clean/.hg/store/undo new file mode 100644 index 00000000..c86109fd Binary files /dev/null and b/apps/api/tests/data/clean/.hg/store/undo differ diff --git a/apps/api/tests/data/clean/.hg/undo.branch b/apps/api/tests/data/clean/.hg/undo.branch new file mode 100644 index 00000000..331d858c --- /dev/null +++ b/apps/api/tests/data/clean/.hg/undo.branch @@ -0,0 +1 @@ +default \ No newline at end of file diff --git a/apps/api/tests/data/clean/.hg/undo.dirstate b/apps/api/tests/data/clean/.hg/undo.dirstate new file mode 100644 index 00000000..f2fcbe22 Binary files /dev/null and b/apps/api/tests/data/clean/.hg/undo.dirstate differ diff --git a/apps/api/tests/data/clean/.hgignore b/apps/api/tests/data/clean/.hgignore new file mode 100644 index 00000000..e69de29b diff --git a/apps/api/tests/data/clean/.hgtags b/apps/api/tests/data/clean/.hgtags new file mode 100644 index 00000000..0b061138 --- /dev/null +++ b/apps/api/tests/data/clean/.hgtags @@ -0,0 +1 @@ +d5e516ebd357bca24c6afb737e97db3b3d4f111a $branchbase diff --git a/apps/api/tests/data/empty/.hg/00changelog.i b/apps/api/tests/data/empty/.hg/00changelog.i deleted file mode 100644 index d3a83110..00000000 Binary files a/apps/api/tests/data/empty/.hg/00changelog.i and /dev/null differ diff --git a/apps/api/tests/data/empty/.hg/branchheads.cache b/apps/api/tests/data/empty/.hg/branchheads.cache deleted file mode 100644 index 022ec463..00000000 --- a/apps/api/tests/data/empty/.hg/branchheads.cache +++ /dev/null @@ -1,2 +0,0 @@ -e56b2a7e06a97d7c3697fc4295974e0f20a66190 0 -e56b2a7e06a97d7c3697fc4295974e0f20a66190 default diff --git a/apps/api/tests/data/empty/.hg/dirstate b/apps/api/tests/data/empty/.hg/dirstate deleted file mode 100644 index 3996f893..00000000 Binary files a/apps/api/tests/data/empty/.hg/dirstate and /dev/null differ diff --git a/apps/api/tests/data/empty/.hg/requires b/apps/api/tests/data/empty/.hg/requires deleted file mode 100644 index 5175383b..00000000 --- a/apps/api/tests/data/empty/.hg/requires +++ /dev/null @@ -1,3 +0,0 @@ -revlogv1 -store -fncache diff --git a/apps/api/tests/data/empty/.hg/store/00changelog.i b/apps/api/tests/data/empty/.hg/store/00changelog.i deleted file mode 100644 index f6361419..00000000 Binary files a/apps/api/tests/data/empty/.hg/store/00changelog.i and /dev/null differ diff --git a/apps/api/tests/data/empty/.hg/store/00manifest.i b/apps/api/tests/data/empty/.hg/store/00manifest.i deleted file mode 100644 index 267c71ad..00000000 Binary files a/apps/api/tests/data/empty/.hg/store/00manifest.i and /dev/null differ diff --git a/apps/api/tests/data/empty/.hg/store/data/.library.i b/apps/api/tests/data/empty/.hg/store/data/.library.i deleted file mode 100644 index 2431023a..00000000 Binary files a/apps/api/tests/data/empty/.hg/store/data/.library.i and /dev/null differ diff --git a/apps/api/tests/data/empty/.hg/store/fncache b/apps/api/tests/data/empty/.hg/store/fncache deleted file mode 100644 index d4a556ec..00000000 --- a/apps/api/tests/data/empty/.hg/store/fncache +++ /dev/null @@ -1 +0,0 @@ -data/.library.i diff --git a/apps/api/tests/data/empty/.hg/store/undo b/apps/api/tests/data/empty/.hg/store/undo deleted file mode 100644 index 33dec7fc..00000000 Binary files a/apps/api/tests/data/empty/.hg/store/undo and /dev/null differ diff --git a/apps/api/tests/data/empty/.hg/undo.branch b/apps/api/tests/data/empty/.hg/undo.branch deleted file mode 100644 index 331d858c..00000000 --- a/apps/api/tests/data/empty/.hg/undo.branch +++ /dev/null @@ -1 +0,0 @@ -default \ No newline at end of file diff --git a/apps/api/tests/data/empty/.hg/undo.dirstate b/apps/api/tests/data/empty/.hg/undo.dirstate deleted file mode 100644 index ebf59c66..00000000 Binary files a/apps/api/tests/data/empty/.hg/undo.dirstate and /dev/null differ diff --git a/apps/api/tests/data/empty/.library b/apps/api/tests/data/empty/.library deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/api/tests/data/simple/$meta b/apps/api/tests/data/simple/$meta new file mode 100644 index 00000000..e69de29b diff --git a/apps/api/tests/data/simple/.hg/00changelog.i b/apps/api/tests/data/simple/.hg/00changelog.i new file mode 100644 index 00000000..d3a83110 Binary files /dev/null and b/apps/api/tests/data/simple/.hg/00changelog.i differ diff --git a/apps/api/tests/data/simple/.hg/branch b/apps/api/tests/data/simple/.hg/branch new file mode 100644 index 00000000..4ad96d51 --- /dev/null +++ b/apps/api/tests/data/simple/.hg/branch @@ -0,0 +1 @@ +default diff --git a/apps/api/tests/data/simple/.hg/branchheads.cache b/apps/api/tests/data/simple/.hg/branchheads.cache new file mode 100644 index 00000000..713758bd --- /dev/null +++ b/apps/api/tests/data/simple/.hg/branchheads.cache @@ -0,0 +1,4 @@ +65046aefea667e38c7a01d7ca62412d7e81f68bc 2 +d5e516ebd357bca24c6afb737e97db3b3d4f111a default +00e4aa6f4f53f31020e4d3e0579cb3c0fa0bd056 $doc:sample +65046aefea667e38c7a01d7ca62412d7e81f68bc $doc:sample_pl diff --git a/apps/api/tests/data/simple/.hg/dirstate b/apps/api/tests/data/simple/.hg/dirstate new file mode 100644 index 00000000..46fefcaa Binary files /dev/null and b/apps/api/tests/data/simple/.hg/dirstate differ diff --git a/apps/api/tests/data/simple/.hg/requires b/apps/api/tests/data/simple/.hg/requires new file mode 100644 index 00000000..5175383b --- /dev/null +++ b/apps/api/tests/data/simple/.hg/requires @@ -0,0 +1,3 @@ +revlogv1 +store +fncache diff --git a/apps/api/tests/data/simple/.hg/store/00changelog.i b/apps/api/tests/data/simple/.hg/store/00changelog.i new file mode 100644 index 00000000..f2451544 Binary files /dev/null and b/apps/api/tests/data/simple/.hg/store/00changelog.i differ diff --git a/apps/api/tests/data/simple/.hg/store/00manifest.i b/apps/api/tests/data/simple/.hg/store/00manifest.i new file mode 100644 index 00000000..fd65f619 Binary files /dev/null and b/apps/api/tests/data/simple/.hg/store/00manifest.i differ diff --git a/apps/api/tests/data/simple/.hg/store/data/$meta.i b/apps/api/tests/data/simple/.hg/store/data/$meta.i new file mode 100644 index 00000000..2431023a Binary files /dev/null and b/apps/api/tests/data/simple/.hg/store/data/$meta.i differ diff --git a/apps/api/tests/data/simple/.hg/store/data/.hgignore.i b/apps/api/tests/data/simple/.hg/store/data/.hgignore.i new file mode 100644 index 00000000..2431023a Binary files /dev/null and b/apps/api/tests/data/simple/.hg/store/data/.hgignore.i differ diff --git a/apps/api/tests/data/simple/.hg/store/data/.hgtags.i b/apps/api/tests/data/simple/.hg/store/data/.hgtags.i new file mode 100644 index 00000000..6c3fcf23 Binary files /dev/null and b/apps/api/tests/data/simple/.hg/store/data/.hgtags.i differ diff --git a/apps/api/tests/data/simple/.hg/store/data/sample.parts.i b/apps/api/tests/data/simple/.hg/store/data/sample.parts.i new file mode 100644 index 00000000..a6bdf46f Binary files /dev/null and b/apps/api/tests/data/simple/.hg/store/data/sample.parts.i differ diff --git a/apps/api/tests/data/simple/.hg/store/data/sample.xml.i b/apps/api/tests/data/simple/.hg/store/data/sample.xml.i new file mode 100644 index 00000000..b115f4d6 Binary files /dev/null and b/apps/api/tests/data/simple/.hg/store/data/sample.xml.i differ diff --git a/apps/api/tests/data/simple/.hg/store/data/sample__pl.xml.i b/apps/api/tests/data/simple/.hg/store/data/sample__pl.xml.i new file mode 100644 index 00000000..920c5742 Binary files /dev/null and b/apps/api/tests/data/simple/.hg/store/data/sample__pl.xml.i differ diff --git a/apps/api/tests/data/simple/.hg/store/fncache b/apps/api/tests/data/simple/.hg/store/fncache new file mode 100644 index 00000000..c228181f --- /dev/null +++ b/apps/api/tests/data/simple/.hg/store/fncache @@ -0,0 +1,6 @@ +data/$meta.i +data/.hgignore.i +data/sample.parts.i +data/sample.xml.i +data/sample_pl.xml.i +data/.hgtags.i diff --git a/apps/api/tests/data/simple/.hg/store/undo b/apps/api/tests/data/simple/.hg/store/undo new file mode 100644 index 00000000..3ad8b327 Binary files /dev/null and b/apps/api/tests/data/simple/.hg/store/undo differ diff --git a/apps/api/tests/data/simple/.hg/strip-backup/26716f931d95-backup b/apps/api/tests/data/simple/.hg/strip-backup/26716f931d95-backup new file mode 100644 index 00000000..424de921 Binary files /dev/null and b/apps/api/tests/data/simple/.hg/strip-backup/26716f931d95-backup differ diff --git a/apps/api/tests/data/simple/.hg/undo.branch b/apps/api/tests/data/simple/.hg/undo.branch new file mode 100644 index 00000000..331d858c --- /dev/null +++ b/apps/api/tests/data/simple/.hg/undo.branch @@ -0,0 +1 @@ +default \ No newline at end of file diff --git a/apps/api/tests/data/simple/.hg/undo.dirstate b/apps/api/tests/data/simple/.hg/undo.dirstate new file mode 100644 index 00000000..310d9416 Binary files /dev/null and b/apps/api/tests/data/simple/.hg/undo.dirstate differ diff --git a/apps/api/tests/data/simple/.hgignore b/apps/api/tests/data/simple/.hgignore new file mode 100644 index 00000000..e69de29b diff --git a/apps/api/tests/data/simple/.hgtags b/apps/api/tests/data/simple/.hgtags new file mode 100644 index 00000000..0b061138 --- /dev/null +++ b/apps/api/tests/data/simple/.hgtags @@ -0,0 +1 @@ +d5e516ebd357bca24c6afb737e97db3b3d4f111a $branchbase diff --git a/apps/api/tests/data/test2/.hg/00changelog.i b/apps/api/tests/data/test2/.hg/00changelog.i deleted file mode 100644 index d3a83110..00000000 Binary files a/apps/api/tests/data/test2/.hg/00changelog.i and /dev/null differ diff --git a/apps/api/tests/data/test2/.hg/branch b/apps/api/tests/data/test2/.hg/branch deleted file mode 100644 index 4ad96d51..00000000 --- a/apps/api/tests/data/test2/.hg/branch +++ /dev/null @@ -1 +0,0 @@ -default diff --git a/apps/api/tests/data/test2/.hg/branchheads.cache b/apps/api/tests/data/test2/.hg/branchheads.cache deleted file mode 100644 index 650c9b01..00000000 --- a/apps/api/tests/data/test2/.hg/branchheads.cache +++ /dev/null @@ -1,3 +0,0 @@ -93618f13c33aab5a3d049e0860cd3d21a457cd7d 2 -f94a263812dbe46a3a13d5209bb119988d0078d5 default -93618f13c33aab5a3d049e0860cd3d21a457cd7d personal_admin_file_testfile diff --git a/apps/api/tests/data/test2/.hg/dirstate b/apps/api/tests/data/test2/.hg/dirstate deleted file mode 100644 index cc53c86d..00000000 Binary files a/apps/api/tests/data/test2/.hg/dirstate and /dev/null differ diff --git a/apps/api/tests/data/test2/.hg/requires b/apps/api/tests/data/test2/.hg/requires deleted file mode 100644 index 5175383b..00000000 --- a/apps/api/tests/data/test2/.hg/requires +++ /dev/null @@ -1,3 +0,0 @@ -revlogv1 -store -fncache diff --git a/apps/api/tests/data/test2/.hg/store/00changelog.i b/apps/api/tests/data/test2/.hg/store/00changelog.i deleted file mode 100644 index 4d3d86a3..00000000 Binary files a/apps/api/tests/data/test2/.hg/store/00changelog.i and /dev/null differ diff --git a/apps/api/tests/data/test2/.hg/store/00manifest.i b/apps/api/tests/data/test2/.hg/store/00manifest.i deleted file mode 100644 index de399682..00000000 Binary files a/apps/api/tests/data/test2/.hg/store/00manifest.i and /dev/null differ diff --git a/apps/api/tests/data/test2/.hg/store/data/.library.i b/apps/api/tests/data/test2/.hg/store/data/.library.i deleted file mode 100644 index 2431023a..00000000 Binary files a/apps/api/tests/data/test2/.hg/store/data/.library.i and /dev/null differ diff --git a/apps/api/tests/data/test2/.hg/store/data/pub__testfile.xml.i b/apps/api/tests/data/test2/.hg/store/data/pub__testfile.xml.i deleted file mode 100644 index ca417810..00000000 Binary files a/apps/api/tests/data/test2/.hg/store/data/pub__testfile.xml.i and /dev/null differ diff --git a/apps/api/tests/data/test2/.hg/store/fncache b/apps/api/tests/data/test2/.hg/store/fncache deleted file mode 100644 index d55636d5..00000000 --- a/apps/api/tests/data/test2/.hg/store/fncache +++ /dev/null @@ -1,2 +0,0 @@ -data/.library.i -data/pub_testfile.xml.i diff --git a/apps/api/tests/data/test2/.hg/store/undo b/apps/api/tests/data/test2/.hg/store/undo deleted file mode 100644 index 33e82075..00000000 Binary files a/apps/api/tests/data/test2/.hg/store/undo and /dev/null differ diff --git a/apps/api/tests/data/test2/.hg/undo.branch b/apps/api/tests/data/test2/.hg/undo.branch deleted file mode 100644 index 998eac45..00000000 --- a/apps/api/tests/data/test2/.hg/undo.branch +++ /dev/null @@ -1 +0,0 @@ -personal_admin_file_testfile \ No newline at end of file diff --git a/apps/api/tests/data/test2/.hg/undo.dirstate b/apps/api/tests/data/test2/.hg/undo.dirstate deleted file mode 100644 index 431d58a8..00000000 Binary files a/apps/api/tests/data/test2/.hg/undo.dirstate and /dev/null differ diff --git a/apps/api/tests/data/test2/.library b/apps/api/tests/data/test2/.library deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/api/tests/data/test2/pub_testfile.xml b/apps/api/tests/data/test2/pub_testfile.xml deleted file mode 100644 index 57873f23..00000000 --- a/apps/api/tests/data/test2/pub_testfile.xml +++ /dev/null @@ -1 +0,0 @@ -Test file contents. diff --git a/apps/api/tests/data/testone/.hg/00changelog.i b/apps/api/tests/data/testone/.hg/00changelog.i deleted file mode 100644 index d3a83110..00000000 Binary files a/apps/api/tests/data/testone/.hg/00changelog.i and /dev/null differ diff --git a/apps/api/tests/data/testone/.hg/branchheads.cache b/apps/api/tests/data/testone/.hg/branchheads.cache deleted file mode 100644 index 6087023a..00000000 --- a/apps/api/tests/data/testone/.hg/branchheads.cache +++ /dev/null @@ -1,2 +0,0 @@ -f94a263812dbe46a3a13d5209bb119988d0078d5 1 -f94a263812dbe46a3a13d5209bb119988d0078d5 default diff --git a/apps/api/tests/data/testone/.hg/dirstate b/apps/api/tests/data/testone/.hg/dirstate deleted file mode 100644 index 121c2712..00000000 Binary files a/apps/api/tests/data/testone/.hg/dirstate and /dev/null differ diff --git a/apps/api/tests/data/testone/.hg/requires b/apps/api/tests/data/testone/.hg/requires deleted file mode 100644 index 5175383b..00000000 --- a/apps/api/tests/data/testone/.hg/requires +++ /dev/null @@ -1,3 +0,0 @@ -revlogv1 -store -fncache diff --git a/apps/api/tests/data/testone/.hg/store/00changelog.i b/apps/api/tests/data/testone/.hg/store/00changelog.i deleted file mode 100644 index c466ccb5..00000000 Binary files a/apps/api/tests/data/testone/.hg/store/00changelog.i and /dev/null differ diff --git a/apps/api/tests/data/testone/.hg/store/00manifest.i b/apps/api/tests/data/testone/.hg/store/00manifest.i deleted file mode 100644 index 0239a8f7..00000000 Binary files a/apps/api/tests/data/testone/.hg/store/00manifest.i and /dev/null differ diff --git a/apps/api/tests/data/testone/.hg/store/data/.library.i b/apps/api/tests/data/testone/.hg/store/data/.library.i deleted file mode 100644 index 2431023a..00000000 Binary files a/apps/api/tests/data/testone/.hg/store/data/.library.i and /dev/null differ diff --git a/apps/api/tests/data/testone/.hg/store/data/pub__testfile.xml.i b/apps/api/tests/data/testone/.hg/store/data/pub__testfile.xml.i deleted file mode 100644 index ca417810..00000000 Binary files a/apps/api/tests/data/testone/.hg/store/data/pub__testfile.xml.i and /dev/null differ diff --git a/apps/api/tests/data/testone/.hg/store/fncache b/apps/api/tests/data/testone/.hg/store/fncache deleted file mode 100644 index d55636d5..00000000 --- a/apps/api/tests/data/testone/.hg/store/fncache +++ /dev/null @@ -1,2 +0,0 @@ -data/.library.i -data/pub_testfile.xml.i diff --git a/apps/api/tests/data/testone/.hg/store/undo b/apps/api/tests/data/testone/.hg/store/undo deleted file mode 100644 index 0dbe30a4..00000000 Binary files a/apps/api/tests/data/testone/.hg/store/undo and /dev/null differ diff --git a/apps/api/tests/data/testone/.hg/undo.branch b/apps/api/tests/data/testone/.hg/undo.branch deleted file mode 100644 index 331d858c..00000000 --- a/apps/api/tests/data/testone/.hg/undo.branch +++ /dev/null @@ -1 +0,0 @@ -default \ No newline at end of file diff --git a/apps/api/tests/data/testone/.hg/undo.dirstate b/apps/api/tests/data/testone/.hg/undo.dirstate deleted file mode 100644 index a2fe6838..00000000 Binary files a/apps/api/tests/data/testone/.hg/undo.dirstate and /dev/null differ diff --git a/apps/api/tests/data/testone/.library b/apps/api/tests/data/testone/.library deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/api/tests/data/testone/pub_testfile.xml b/apps/api/tests/data/testone/pub_testfile.xml deleted file mode 100644 index 57873f23..00000000 --- a/apps/api/tests/data/testone/pub_testfile.xml +++ /dev/null @@ -1 +0,0 @@ -Test file contents. diff --git a/apps/api/urls.py b/apps/api/urls.py index ada879c4..de09605d 100644 --- a/apps/api/urls.py +++ b/apps/api/urls.py @@ -2,27 +2,28 @@ __author__="lreqc" __date__ ="$2009-09-17 16:16:54$" from django.conf.urls.defaults import * -from piston.resource import Resource -from api.handlers import * -from api.utils import TextEmitter, DjangoAuth +from api.resources import * -authdata = {'authentication': DjangoAuth()} - -FORMAT_EXT = r"\.(?Pxml|json|yaml|django)$" - -library_resource = Resource(LibraryHandler, **authdata) -document_resource = Resource(DocumentHandler, **authdata) -document_text_resource = Resource(DocumentTextHandler, **authdata) +FORMAT_EXT = r"\.(?Pxml|json|yaml)$" urlpatterns = patterns('', # url(r'^hello$', hello_resource, {'emitter_format': 'json'}), # url(r'^hello\.(?P.+)$', hello_resource), + # Toolbar + url(r'^toolbar/buttons$', toolbar_buttons, {'emitter_format': 'json'}), + + # Toolbar + url(r'^toolbar/scriptlets$', scriptlets, {'emitter_format': 'json'}), + # Documents - url(r'^documents$', library_resource, {'emitter_format': 'json'}, - name="document_list_view"), + url(r'^documents$', library_resource, + {'emitter_format': 'json'}, name="document_list_view"), + url(r'^documents'+FORMAT_EXT, library_resource, + name="document_list_view_withformat"), + url(r'^documents/(?P[^/]+)'+FORMAT_EXT, document_resource, name="document_view_withformat"), @@ -34,8 +35,12 @@ urlpatterns = patterns('', document_text_resource, {'emitter_format': 'rawxml'}, name="doctext_view"), + url(r'^documents/(?P[^/]+)/dc' + FORMAT_EXT, + document_dc_resource, + name="docdc_view_withformat"), + url(r'^documents/(?P[^/]+)/dc$', - document_resource, {'emitter_format': 'json'}, + document_dc_resource, {'emitter_format': 'json'}, name="docdc_view"), url(r'^documents/(?P[^/]+)/parts$', diff --git a/apps/api/utils.py b/apps/api/utils.py index 67e8ea5a..4b004ee9 100644 --- a/apps/api/utils.py +++ b/apps/api/utils.py @@ -13,8 +13,7 @@ class TextEmitter(Emitter): return unicode(self.construct()) Emitter.register('text', TextEmitter, 'text/plain; charset=utf-8') -Emitter.register('rawxml', TextEmitter, 'application/xml; charset=utf-8') - +Emitter.register('rawxml', TextEmitter, 'application/xml; charset=UTF-8') class DjangoAuth(object): diff --git a/apps/maintenancemode/._middleware.py b/apps/maintenancemode/._middleware.py new file mode 100644 index 00000000..d25f019d Binary files /dev/null and b/apps/maintenancemode/._middleware.py differ diff --git a/apps/maintenancemode/__init__.py b/apps/maintenancemode/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/maintenancemode/conf/._settings.py b/apps/maintenancemode/conf/._settings.py new file mode 100644 index 00000000..a8981627 Binary files /dev/null and b/apps/maintenancemode/conf/._settings.py differ diff --git a/apps/maintenancemode/conf/__init__.py b/apps/maintenancemode/conf/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/maintenancemode/conf/settings.py b/apps/maintenancemode/conf/settings.py new file mode 100644 index 00000000..4d0b1a51 --- /dev/null +++ b/apps/maintenancemode/conf/settings.py @@ -0,0 +1,3 @@ +from django.conf import settings + +MAINTENANCE_MODE = getattr(settings, 'MAINTENANCE_MODE', False) \ No newline at end of file diff --git a/apps/maintenancemode/conf/urls/__init__.py b/apps/maintenancemode/conf/urls/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/maintenancemode/conf/urls/defaults.py b/apps/maintenancemode/conf/urls/defaults.py new file mode 100644 index 00000000..20029db5 --- /dev/null +++ b/apps/maintenancemode/conf/urls/defaults.py @@ -0,0 +1,3 @@ +__all__ = ['handler503'] + +handler503 = 'maintenancemode.views.defaults.temporary_unavailable' \ No newline at end of file diff --git a/apps/maintenancemode/http.py b/apps/maintenancemode/http.py new file mode 100644 index 00000000..4b3023b6 --- /dev/null +++ b/apps/maintenancemode/http.py @@ -0,0 +1,4 @@ +from django.http import HttpResponse + +class HttpResponseTemporaryUnavailable(HttpResponse): + status_code = 503 diff --git a/apps/maintenancemode/middleware.py b/apps/maintenancemode/middleware.py new file mode 100644 index 00000000..404b1a05 --- /dev/null +++ b/apps/maintenancemode/middleware.py @@ -0,0 +1,31 @@ +from django.conf import settings +from django.core import urlresolvers + +# This is django-maintancemode v. 0.9.2 + +from django.conf.urls import defaults +defaults.handler503 = 'maintenancemode.views.defaults.temporary_unavailable' +defaults.__all__.append('handler503') + +from maintenancemode.conf.settings import MAINTENANCE_MODE + +class MaintenanceModeMiddleware(object): + def process_request(self, request): + # Allow access if middleware is not activated + if not MAINTENANCE_MODE: + return None + + # Allow access if remote ip is in INTERNAL_IPS + if request.META.get('REMOTE_ADDR') in settings.INTERNAL_IPS: + return None + + # Allow acess if the user doing the request is logged in and a + # staff member. + if hasattr(request, 'user') and request.user.is_staff: + return None + + # Otherwise show the user the 503 page + resolver = urlresolvers.get_resolver(None) + + callback, param_dict = resolver._resolve_special('503') + return callback(request, **param_dict) \ No newline at end of file diff --git a/apps/maintenancemode/views/__init__.py b/apps/maintenancemode/views/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/maintenancemode/views/defaults.py b/apps/maintenancemode/views/defaults.py new file mode 100644 index 00000000..f0bf48fe --- /dev/null +++ b/apps/maintenancemode/views/defaults.py @@ -0,0 +1,16 @@ +from django.template import Context, loader + +from maintenancemode import http + +def temporary_unavailable(request, template_name='503.html'): + """ + Default 503 handler, which looks for the requested URL in the redirects + table, redirects if found, and displays 404 page if not redirected. + + Templates: `503.html` + Context: + request_path + The path of the requested URL (e.g., '/app/pages/bad_page/') + """ + t = loader.get_template(template_name) # You need to create a 503.html template. + return http.HttpResponseTemporaryUnavailable(t.render(Context({}))) \ No newline at end of file diff --git a/apps/toolbar/models.py b/apps/toolbar/models.py index d1f4952c..04146223 100644 --- a/apps/toolbar/models.py +++ b/apps/toolbar/models.py @@ -14,6 +14,26 @@ class ButtonGroup(models.Model): def __unicode__(self): return self.name + +#class ButtonGroupManager(models.Manager): +# +# def with_buttons(self): +# from django.db import connection +# cursor = connection.cursor() +# cursor.execute(""" +# SELECT g.name, g.slug, CONCAT(b.slug), +# FROM toolbar_buttongroup as g LEFT JOIN toolbar_button as b +# +# WHERE p.id = r.poll_id +# GROUP BY 1, 2, 3 +# ORDER BY 3 DESC""") +# result_list = [] +# for row in cursor.fetchall(): +# p = self.model(id=row[0], question=row[1], poll_date=row[2]) +# p.num_responses = row[3] +# result_list.append(p) +# return result_list + class Button(models.Model): label = models.CharField(max_length=32) slug = models.SlugField(unique=True) #unused diff --git a/apps/toolbar/templates/toolbar/toolbar.html b/apps/toolbar/templates/toolbar/toolbar.html index b0ee028f..c4fcdcbb 100644 --- a/apps/toolbar/templates/toolbar/toolbar.html +++ b/apps/toolbar/templates/toolbar/toolbar.html @@ -8,7 +8,7 @@ {% endfor %} -
+

{% for group in toolbar_groups %}

{% block maincontent %} {% endblock %}
- {% block extrabody %} {% endblock %} + {% block extrabody %}{% endblock %} diff --git a/project/templates/explorer/panels/xmleditor.html b/project/templates/explorer/panels/xmleditor.html index 4ec75d2a..74a68776 100644 --- a/project/templates/explorer/panels/xmleditor.html +++ b/project/templates/explorer/panels/xmleditor.html @@ -17,8 +17,11 @@ panel_hooks = { var texteditor = CodeMirror.fromTextArea(textareaId, { parserfile: 'parsexml.js', path: "{{STATIC_URL}}js/lib/codemirror/", + width: 'auto', stylesheet: "{{STATIC_URL}}css/xmlcolors.css", parserConfig: {useHTMLKludges: false}, + textWrapping: false, + lineNumbers: true, onChange: function() { self.fireEvent('contentChanged'); }, @@ -33,7 +36,9 @@ panel_hooks = { } }) - $(texteditor.frame).css({width: '100%', height: '100%'}); + $('.CodeMirror-content-wrapper').css({ + width: '100%', height: '100%' }); + this.texteditor = texteditor; self._endload(); }, diff --git a/project/templates/manager/pull_request.html b/project/templates/manager/pull_request.html new file mode 100644 index 00000000..c03caab3 --- /dev/null +++ b/project/templates/manager/pull_request.html @@ -0,0 +1,7 @@ +{% if objects %} + {% for pullreq in objects %} +

{{ pullreq }}

+ {% endfor %} +{% else %} +

Brak żądań

+{% endif %} diff --git a/project/templates/toolbar_api/scriptlets.js b/project/templates/toolbar_api/scriptlets.js new file mode 100644 index 00000000..ae7e2df4 --- /dev/null +++ b/project/templates/toolbar_api/scriptlets.js @@ -0,0 +1,15 @@ +function SciptletCenter() { + + this.scriptlets = { + {% for scriptlet in scriptlets %} + "{{scriptlet.name}}": function(context, params) { + {{scriptlet.code|safe}} + }, + {% endfor %} + + _none: null + }; + +} + +scriptletCenter = new ScriptletCenter(); \ No newline at end of file diff --git a/project/templates/wysiwyg.html b/project/templates/wysiwyg.html new file mode 100644 index 00000000..409e4f25 --- /dev/null +++ b/project/templates/wysiwyg.html @@ -0,0 +1,92 @@ +{% extends 'base.html' %} + +{% block extrahead %} + +{% endblock %} + +{% block maincontent %} +

Wysiwyg editor

+
This part is not editable!
+
+ +

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Suspendisse a urna eu enim rutrum elementum nec sed nibh. Quisque sed tortor + nulla, et euismod turpis. Morbi purus nulla, vulputate in vulputate id, gravida + id eros. In interdum est tempor est consequat imperdiet. Vivamus vitae ligula quam. + Proin nibh quam, tincidunt sit amet auctor eget, laoreet sit amet eros. Cras augue + lectus, euismod nec posuere ac, ultricies sed magna. Aliquam a lacinia sapien. + Cras imperdiet urna vel dui accumsan mollis. Suspendisse convallis tincidunt ornare. + Aenean convallis libero in lectus dictum vestibulum interdum ipsum suscipit. + Suspendisse sed justo sapien, eu egestas libero. Sed tincidunt sagittis sollicitudin. + Aliquam erat volutpat. Nullam egestas dolor id massa sagittis at sagittis ipsum + hendrerit. +

+ +

Phasellus sed purus non orci eleifend posuere ac eu elit. Etiam orci justo, porta vitae varius in, scelerisque sed metus. Phasellus faucibus lorem at metus scelerisque sit amet sollicitudin dolor dignissim. Aliquam eu justo in diam blandit posuere at a diam. Pellentesque tristique sem eu odio gravida eleifend. Phasellus cursus adipiscing metus, nec pharetra enim pharetra ac. Pellentesque faucibus volutpat lorem nec vulputate. Mauris in faucibus ipsum. Nulla ut urna nulla. Sed at tellus nec diam posuere porttitor. Duis faucibus, libero nec rhoncus facilisis, tortor ligula adipiscing massa, nec varius justo ante et magna. Donec orci mauris, ultrices nec blandit vel, lacinia in ante. Maecenas libero mi, pretium id ultricies eget, fringilla sit amet risus. Integer ut ante sem, et condimentum odio. Nam nec est erat. Etiam ut metus ligula. In vel condimentum orci.

+ +

Suspendisse potenti. Proin in augue nibh. Curabitur in sollicitudin ipsum. In ut leo vel purus volutpat tempus. Proin ut neque at augue euismod ullamcorper nec ac dui. Vestibulum id quam nunc, eu porta augue. Pellentesque interdum neque eu nulla rhoncus vulputate. Sed viverra diam ac sem consectetur semper. Quisque consectetur fringilla quam, in feugiat nisl vulputate quis. Fusce vel ipsum lectus, eu interdum nunc. Donec luctus libero vitae mauris imperdiet at iaculis magna aliquet. Curabitur ullamcorper, diam nec pulvinar venenatis, nibh ante volutpat mauris, nec tristique lectus sem in urna. Aenean eu malesuada metus. Integer auctor nulla sit amet ligula sollicitudin ut accumsan velit ullamcorper. Donec nec auctor augue.

+ +

Maecenas eget lacus vitae velit tincidunt bibendum quis et diam. In ullamcorper condimentum velit, et elementum felis vestibulum facilisis. Donec vitae cursus ipsum. Cras accumsan tincidunt aliquet. Nulla pellentesque mattis magna aliquet hendrerit. Pellentesque pellentesque odio enim. Duis viverra rhoncus tristique. In in risus ligula. Nullam dapibus lacinia facilisis. Ut eu neque neque, tristique laoreet nisl. Aliquam placerat dignissim leo, tristique tempor est vestibulum ut.

+ +

Donec semper tempus ante, eget gravida erat varius et. Suspendisse aliquam rutrum nunc ac pulvinar. Aliquam erat volutpat. Nulla consectetur ultricies imperdiet. Nulla tincidunt est vitae augue porttitor a faucibus odio facilisis. In nec nisl odio. Aliquam et libero tortor, eu tincidunt mi. Vivamus suscipit erat sed mi hendrerit fringilla. Integer iaculis tempus nulla, at egestas velit faucibus ut. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Vestibulum vel massa enim. Aliquam erat volutpat. In ligula tortor, fermentum eu suscipit at, posuere vel nunc. Nullam nibh magna, sollicitudin at semper et, mattis ut quam. Curabitur accumsan semper elit ac posuere. Sed sit amet lorem tortor, vel porttitor justo. Fusce odio metus, bibendum ut bibendum sit amet, luctus a ipsum.

+
+{% endblock %} + +{% block extrabody %} + +{% endblock %} \ No newline at end of file diff --git a/project/urls.py b/project/urls.py index 2c1fab7b..c8896314 100644 --- a/project/urls.py +++ b/project/urls.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + from django.conf.urls.defaults import * from django.contrib import admin from django.conf import settings @@ -42,7 +44,10 @@ urlpatterns = patterns('', url(r'^accounts/login/$', 'django.contrib.auth.views.login', {'redirect_field_name': 'next'}), url(r'^accounts/logout/$', 'django.contrib.auth.views.logout', {'next_page': '/'}), - # Our uber-restful api + # Prototypes + url(r'^wysiwyg-proto/', include('wysiwyg.urls')), + + # Our über-restful api url(r'^api/', include('api.urls') ), ) diff --git a/redmine/redmine_publications/app/controllers/publications_controller.rb b/redmine/redmine_publications/app/controllers/publications_controller.rb index 6c1e7345..ebf735b9 100644 --- a/redmine/redmine_publications/app/controllers/publications_controller.rb +++ b/redmine/redmine_publications/app/controllers/publications_controller.rb @@ -19,28 +19,28 @@ class PublicationsController < ApplicationController Publication.delete_all() repos = Repository.all if repos - repos.each do |repo| - repo_status = [] - if repo.entries - repo.entries.each do |entry| - match = entry.path.match(regexp) - if match - Publication.find_or_create_by_name(:name => match[1], - :source_file => entry.path, :repository_id => repo.id) - repo_status += [{:path => entry.path, :match => match[1], :matched => true}] - else - repo_status += [{:path => entry.path, :match =>nil, :matched => false}] + repos.each do |repo| + repo_status = [] + if repo.entries + repo.entries.each do |entry| + match = entry.path.match(regexp) + if match + Publication.find_or_create_by_name(:name => match[1], + :source_file => entry.path, :repository_id => repo.id) + repo_status += [{:path => entry.path, :match => match[1], :matched => true}] + else + repo_status += [{:path => entry.path, :match =>nil, :matched => false}] + end + end + @match_status += [{:repo => repo, :status => repo_status}] end end - @match_status += [{:repo => repo, :status => repo_status}] - end - end - respond_to do |format| - format.html - format.xml { render :xml => @match_status} - format.json { render :json => @match_status } - end + respond_to do |format| + format.html + format.xml { render :xml => @match_status} + format.json { render :json => @match_status } + end end end @@ -52,7 +52,7 @@ class PublicationsController < ApplicationController @issues = Issue.all(:joins => joins, :conditions => conditions) respond_to do |fmt| - fmt.json { render :json => @issues, :callback => params[:callback] } + fmt.json { render :json => @issues, :callback => params[:callback] } end end diff --git a/redmine/redmine_publications/app/views/issues/_issue_form_pub.html.erb b/redmine/redmine_publications/app/views/issues/_issue_form_pub.html.erb index f0f7a1a0..ebb903c0 100644 --- a/redmine/redmine_publications/app/views/issues/_issue_form_pub.html.erb +++ b/redmine/redmine_publications/app/views/issues/_issue_form_pub.html.erb @@ -1,5 +1,5 @@
-

+

' />

diff --git a/redmine/redmine_publications/app/views/issues/_issue_view_pub.erb b/redmine/redmine_publications/app/views/issues/_issue_view_pub.erb index 26ce997b..a22c78be 100644 --- a/redmine/redmine_publications/app/views/issues/_issue_view_pub.erb +++ b/redmine/redmine_publications/app/views/issues/_issue_view_pub.erb @@ -1,5 +1,5 @@ - Publication(s) + <%= l(:field_publications) %>: <% @issue.publication_names.each do |pub| %> <%= pub %>
diff --git a/redmine/redmine_publications/init.rb b/redmine/redmine_publications/init.rb index 0aa6f07d..4298f606 100644 --- a/redmine/redmine_publications/init.rb +++ b/redmine/redmine_publications/init.rb @@ -11,6 +11,10 @@ Dispatcher.to_prepare :redmine_publications do unless Issue.included_modules.include? RedminePublications::IssuePatch Issue.send(:include, RedminePublications::IssuePatch) end + + unless Change.included_modules.include? RedminePublications::ChangePatch + Change.send(:include, RedminePublications::ChangePatch) + end end require_dependency 'issue_publication_hook' diff --git a/redmine/redmine_publications/lib/redmine_publications/change_patch.rb b/redmine/redmine_publications/lib/redmine_publications/change_patch.rb new file mode 100644 index 00000000..41ea9596 --- /dev/null +++ b/redmine/redmine_publications/lib/redmine_publications/change_patch.rb @@ -0,0 +1,38 @@ +module RedminePublications + # Patches Redmine's Issues dynamically. Adds a +after_save+ filter. + + module ChangePatch + def self.included(base) # :nodoc: + base.extend(ClassMethods) + + base.send(:include, InstanceMethods) + + # Same as typing in the class + base.class_eval do + unloadable # Send unloadable so it will not be unloaded in development + after_save :update_publication + end + + end + + module ClassMethods + end + + module InstanceMethods + + def update_publication + if self.action == 'A' + regexp = Regexp.new(Setting.plugin_redmine_publications[:pattern]) + match = self.path.match(regexp) + Rails.logger.info('[INFO] Adding publication: "' << match[1]) + Publication.find_or_create_by_name(:name => match[1], + :source_file => self.path, :repository_id => self.changeset.repository.id ) + end + end + + end + + end + + +end diff --git a/redmine/redmine_publications/lib/redmine_publications/issue_patch.rb b/redmine/redmine_publications/lib/redmine_publications/issue_patch.rb index c1087999..bd1f73eb 100644 --- a/redmine/redmine_publications/lib/redmine_publications/issue_patch.rb +++ b/redmine/redmine_publications/lib/redmine_publications/issue_patch.rb @@ -11,8 +11,8 @@ module RedminePublications base.class_eval do unloadable # Send unloadable so it will not be unloaded in development - validate :check_relations - after_save :update_relations + validate :check_relations + after_save :update_relations end end @@ -23,55 +23,55 @@ module RedminePublications module InstanceMethods def publication_names - if not @pubnames - self.publications.map { |pub| pub.name } + if not @pubnames + self.publications.map { |pub| pub.name } else - @pubnames - end + @pubnames + end end def publication_names=(value) - @pubnames = value.sort! + @pubnames = value.sort! end def publications Publication.all( - :joins => - "JOIN issue_publications ON (issue_publications.publication_id = publications.id)", - :conditions => - ["issue_publications.issue_id = ? ", self.id] ) + :joins => + "JOIN issue_publications ON (issue_publications.publication_id = publications.id)", + :conditions => + ["issue_publications.issue_id = ? ", self.id] ) end def check_relations - current_names = self.publication_names - non_existant = [] + current_names = self.publication_names + non_existant = [] - pubs = Publication.find_all_by_name(current_names).map {|i| i.name} - missing = current_names.select {|name| not pubs.include?name } + pubs = Publication.find_all_by_name(current_names).map {|i| i.name} + missing = current_names.select {|name| not pubs.include?name } - if not missing.empty? - errors.add("publications", "Missing publication(s): " + missing.join(', ')) - end - end + if not missing.empty? + errors.add("publications", "Missing publication(s): " + missing.join(', ')) + end + end - def update_relations - old = self.publications - current_names = self.publication_names - Rails.logger.info('[INFO] Updating relations: old= ' << old.inspect << ' current=' << current_names.inspect) + def update_relations + old = self.publications + current_names = self.publication_names + Rails.logger.info('[INFO] Updating relations: old= ' << old.inspect << ' current=' << current_names.inspect) - # delete unused relations - deleted = old.select { |v| not (current_names.include?(v.name)) } - deleted.each do |pub| - IssuePublication.delete_all(["issue_publications.issue_id = ? AND issue_publications.publication_id = ?", self.id, pub.id]) - end + # delete unused relations + deleted = old.select { |v| not (current_names.include?(v.name)) } + deleted.each do |pub| + IssuePublication.delete_all(["issue_publications.issue_id = ? AND issue_publications.publication_id = ?", self.id, pub.id]) + end - current_names.each do |name| - pub = Publication.find_by_name(name) - IssuePublication.find_or_create_by_publication_id_and_issue_id(pub.id, self.id) - end + current_names.each do |name| + pub = Publication.find_by_name(name) + IssuePublication.find_or_create_by_publication_id_and_issue_id(pub.id, self.id) + end return true - end + end end end diff --git a/redmine/redmine_publications/locales/en.yml b/redmine/redmine_publications/locales/en.yml new file mode 100644 index 00000000..3932ef20 --- /dev/null +++ b/redmine/redmine_publications/locales/en.yml @@ -0,0 +1,3 @@ +## YAML Template. +en: + field_publications: Publications diff --git a/redmine/redmine_publications/locales/pl.yml b/redmine/redmine_publications/locales/pl.yml new file mode 100644 index 00000000..2bf07833 --- /dev/null +++ b/redmine/redmine_publications/locales/pl.yml @@ -0,0 +1,3 @@ +## YAML Template. +pl: + field_publications: Publikacje