target_revision = forms.RegexField('[0-9a-f]{40}')
# any additional comments that user wants to add to the change
- comment = forms.CharField(required=False)
+ message = forms.CharField(required=False)
class DocumentUploadForm(forms.Form):
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')
+ label='Publication name', help_text='Example: słowacki__beniowski__pieśń_1')
generate_dc = forms.BooleanField(required=False, \
initial=True, label=u"Generate DublinCore template")
+import os.path
# -*- encoding: utf-8 -*-
__author__= "Łukasz Rekucki"
import librarian.html
from librarian import dcparser
-from wlrepo import RevisionNotFound, LibraryException, DocumentAlreadyExists
-from explorer.models import PullRequest
+from wlrepo import *
+from explorer.models import PullRequest, GalleryForDocument
# internal imports
import api.forms as forms
import api.response as response
-from api.utils import validate_form, hglibrary
+from api.utils import validate_form, hglibrary, natural_order
from api.models import PartCache
+#
+import settings
+
#
# Document List Handlers
#
documents = {}
for docid in lib.documents():
+ docid = docid.decode('utf-8')
documents[docid] = {
'url': reverse('document_view', args=[docid]),
'name': docid,
'parts': []
}
- related = PartCache.objects.defer('part_id')\
+ parts = PartCache.objects.defer('part_id')\
.values_list('part_id', 'document_id').distinct()
+
+ document_tree = dict(documents)
- for part, docid in related:
+ for part, docid in parts:
# this way, we won't display broken links
if not documents.has_key(part):
+ print "NOT FOUND:", part
continue
- child = documents[part]
parent = documents[docid]
+ child = documents[part]
+
+ # not top-level anymore
+ document_tree.pop(part)
+ parent['parts'].append(child)
+
+ # sort the right way
+
+
+ for doc in documents.itervalues():
+ doc['parts'].sort(key=natural_order(lambda d: d['name']))
- if isinstance(parent, dict): # the parent is top-level
- documents.pop(part)
- parent['parts'].append(child)
- documents[part] = child['parts']
- else: # not top-level
- parent.append(child)
-
- return {
- 'documents': [d for d in documents.itervalues() if isinstance(d, dict)]
- }
+ return {'documents': sorted(document_tree.itervalues(),
+ key=natural_order(lambda d: d['name']) ) }
@validate_form(forms.DocumentUploadForm, 'POST')
@hglibrary
result = {
'name': doc.id,
- 'html_url': reverse('dochtml_view', args=[doc.id,doc.revision]),
- 'text_url': reverse('doctext_view', args=[doc.id,doc.revision]),
- 'dc_url': reverse('docdc_view', args=[doc.id,doc.revision]),
+ 'html_url': reverse('dochtml_view', args=[doc.id]),
+ 'text_url': reverse('doctext_view', args=[doc.id]),
+ 'dc_url': reverse('docdc_view', args=[doc.id]),
'public_revision': doc.revision,
}
try:
doc = lib.document(docid)
udoc = doc.take(request.user.username)
- except RevisionNotFound:
- return request.EnityNotFound().django_response()
+ except RevisionNotFound, e:
+ return response.EntityNotFound().django_response({
+ 'exception': type(e), 'message': e.message})
# is_shared = udoc.ancestorof(doc)
# is_uptodate = is_shared or shared.ancestorof(document)
result = {
'name': udoc.id,
- 'html_url': reverse('dochtml_view', args=[udoc.id,udoc.revision]),
- 'text_url': reverse('doctext_view', args=[udoc.id,udoc.revision]),
- 'dc_url': reverse('docdc_view', args=[udoc.id,udoc.revision]),
+ 'html_url': reverse('dochtml_view', args=[udoc.id]),
+ 'text_url': reverse('doctext_view', args=[udoc.id]),
+ 'dc_url': reverse('docdc_view', args=[udoc.id]),
+ 'gallery_url': reverse('docgallery_view', args=[udoc.id]),
+ 'merge_url': reverse('docmerge_view', args=[udoc.id]),
'user_revision': udoc.revision,
- 'public_revision': doc.revision,
+ 'user_timestamp': udoc.revision.timestamp,
+ 'public_revision': doc.revision,
+ 'public_timestamp': doc.revision.timestamp,
}
return result
#
#
class DocumentHTMLHandler(BaseHandler):
- allowed_methods = ('GET', 'PUT')
+ allowed_methods = ('GET')
@hglibrary
- def read(self, request, docid, revision, lib):
+ def read(self, request, docid, lib):
"""Read document as html text"""
try:
+ revision = request.GET.get('revision', 'latest')
+
if revision == 'latest':
document = lib.document(docid)
else:
document = lib.document_for_rev(revision)
+ if document.id != docid:
+ return response.BadRequest().django_response({'reason': 'name-mismatch',
+ 'message': 'Provided revision refers, to document "%s", but provided "%s"' % (document.id, docid) })
+
return librarian.html.transform(document.data('xml'), is_file=False)
- except RevisionNotFound:
- return response.EntityNotFound().django_response()
+ except (EntryNotFound, RevisionNotFound), e:
+ return response.EntityNotFound().django_response({
+ 'exception': type(e), 'message': e.message})
+
+
+#
+# Image Gallery
+#
+from django.core.files.storage import FileSystemStorage
+
+class DocumentGalleryHandler(BaseHandler):
+ allowed_methods = ('GET')
+
+ def read(self, request, docid):
+ """Read meta-data about scans for gallery of this document."""
+ galleries = []
+
+ for assoc in GalleryForDocument.objects.filter(document=docid):
+ dirpath = os.path.join(settings.MEDIA_ROOT, assoc.subpath)
+
+ if not os.path.isdir(dirpath):
+ print u"[WARNING]: missing gallery %s" % dirpath
+ continue
+
+ gallery = {'name': assoc.name, 'pages': []}
+
+ for file in sorted(os.listdir(dirpath), key=natural_order()):
+ print file
+ name, ext = os.path.splitext(os.path.basename(file))
+ if ext.lower() not in ['.png', '.jpeg', '.jpg']:
+ print "Ignoring:", name, ext
+ continue
+ url = settings.MEDIA_URL + assoc.subpath + u'/' + file.decode('utf-8');
+ gallery['pages'].append(url)
+
+ galleries.append(gallery)
+ return galleries
#
# Document Text View
XINCLUDE_REGEXP = r"""<(?:\w+:)?include\s+[^>]*?href=("|')wlrepo://(?P<link>[^\1]+?)\1\s*[^>]*?>"""
#
#
+#
class DocumentTextHandler(BaseHandler):
- allowed_methods = ('GET', 'PUT')
+ allowed_methods = ('GET', 'POST')
@hglibrary
- def read(self, request, docid, revision, lib):
- """Read document as raw text"""
+ def read(self, request, docid, lib):
+ """Read document as raw text"""
+ revision = request.GET.get('revision', 'latest')
try:
if revision == 'latest':
document = lib.document(docid)
else:
document = lib.document_for_rev(revision)
+
+ if document.id != docid:
+ return response.BadRequest().django_response({'reason': 'name-mismatch',
+ 'message': 'Provided revision is not valid for this document'})
# TODO: some finer-grained access control
return document.data('xml')
- except RevisionNotFound:
- return response.EntityNotFound().django_response()
+ except (EntryNotFound, RevisionNotFound), e:
+ return response.EntityNotFound().django_response({
+ 'exception': type(e), 'message': e.message})
@hglibrary
- def update(self, request, docid, revision, lib):
+ def create(self, request, docid, lib):
try:
- data = request.PUT['contents']
+ data = request.POST['contents']
+ revision = request.POST['revision']
- if request.PUT.has_key('message'):
- msg = u"$USER$ " + request.PUT['message']
+ if request.POST.has_key('message'):
+ msg = u"$USER$ " + request.POST['message']
else:
msg = u"$AUTO$ XML content update."
includes = [m.groupdict()['link'] for m in (re.finditer(\
XINCLUDE_REGEXP, data, flags=re.UNICODE) or []) ]
+ print "INCLUDES: ", includes
+
# TODO: provide useful routines to make this simpler
def xml_update_action(lib, resolve):
try:
"document": ndoc.id,
"subview": "xml",
"previous_revision": current.revision,
- "updated_revision": ndoc.revision,
- "url": reverse("doctext_view", args=[ndoc.id, ndoc.revision])
+ "revision": ndoc.revision,
+ 'timestamp': ndoc.revision.timestamp,
+ "url": reverse("doctext_view", args=[ndoc.id])
})
except Exception, e:
if ndoc: lib._rollback()
raise e
except RevisionNotFound, e:
- return response.EntityNotFound().django_response(e)
+ return response.EntityNotFound(mimetype="text/plain").\
+ django_response(e.message)
+
#
# Dublin Core handlers
# @requires librarian
#
class DocumentDublinCoreHandler(BaseHandler):
- allowed_methods = ('GET', 'PUT')
+ allowed_methods = ('GET', 'POST')
@hglibrary
- def read(self, request, docid, revision, lib):
+ def read(self, request, docid, lib):
"""Read document as raw text"""
try:
+ revision = request.GET.get('revision', 'latest')
+
if revision == 'latest':
doc = lib.document(docid)
else:
doc = lib.document_for_rev(revision)
+
+
+ if document.id != docid:
+ return response.BadRequest().django_response({'reason': 'name-mismatch',
+ 'message': 'Provided revision is not valid for this document'})
bookinfo = dcparser.BookInfo.from_string(doc.data('xml'))
return bookinfo.serialize()
- except RevisionNotFound:
- return response.EntityNotFound().django_response()
+ except (EntryNotFound, RevisionNotFound), e:
+ return response.EntityNotFound().django_response({
+ 'exception': type(e), 'message': e.message})
@hglibrary
- def update(self, request, docid, revision, lib):
+ def create(self, request, docid, lib):
try:
- bi_json = request.PUT['contents']
- if request.PUT.has_key('message'):
+ bi_json = request.POST['contents']
+ revision = request.POST['revision']
+
+ if request.POST.has_key('message'):
msg = u"$USER$ " + request.PUT['message']
else:
msg = u"$AUTO$ Dublin core update."
"document": ndoc.id,
"subview": "dc",
"previous_revision": current.revision,
- "updated_revision": ndoc.revision
+ "revision": ndoc.revision,
+ 'timestamp': ndoc.revision.timestamp,
+ "url": reverse("docdc_view", args=[ndoc.id])
}
except Exception, e:
- lib._rollback()
+ if ndoc: lib._rollback()
raise e
except RevisionNotFound:
return response.EntityNotFound().django_response()
-
-
class MergeHandler(BaseHandler):
allowed_methods = ('POST',)
document=docid,
source_revision = str(udoc.revision),
status="N",
- comment = form.cleaned_data['comment'] or '$AUTO$ Document shared.'
+ comment = form.cleaned_data['message'] or '$AUTO$ Document shared.'
)
prq.save()
success, changed = udoc.update(request.user.username)
if form.cleaned_data['type'] == 'share':
- success, changed = udoc.share(form.cleaned_data['comment'])
+ success, changed = udoc.share(form.cleaned_data['message'])
if not success:
- return response.EntityConflict().django_response()
+ return response.EntityConflict().django_response({})
if not changed:
return response.SuccessNoContent().django_response()
"name": udoc.id,
"parent_user_resivion": udoc.revision,
"parent_revision": doc.revision,
- "revision": udoc.revision,
+ "revision": ndoc.revision,
+ 'timestamp': ndoc.revision.timestamp,
})
for part in created:
me.objects.create(user_id=userid, document_id=docid, part_id=part)
+
+
+
document_text_resource = Resource(dh.DocumentTextHandler, **authdata)
document_html_resource = Resource(dh.DocumentHTMLHandler, **authdata)
document_dc_resource = Resource(dh.DocumentDublinCoreHandler, **authdata)
+document_gallery = Resource(dh.DocumentGalleryHandler, **authdata)
document_merge = Resource(dh.MergeHandler, **authdata)
import api.handlers.manage_handlers as mh
'document_text_resource',
'document_html_resource',
'document_dc_resource',
+ 'document_gallery',
'document_merge',
'toolbar_buttons',
'scriptlets',
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')
+ # data = u"%s\n%s" % (self.MESSAGE, unicode(body))
+ data = unicode(body).encode('utf-8')
return HttpResponse(content=data, status=self._code, \
content_type=self._mime+'; charset=utf-8' )
@temprepo('simple')
- def test_document_text_update(self):
+ def test_document_text_save(self):
self.assertTrue(self.client.login(username='admin', password='admin'))
TEXT = u"Ala ma kota i psa"
FORMAT = r"\.(?P<emitter_format>xml|json|yaml)"
DOC = r'(?P<docid>[^/]+)'
-REVISION = r'(?P<revision>latest|[0-9a-f]{40})'
+# REVISION = r'(?P<revision>latest|[0-9a-f]{40})'
def urlpath(*args, **kwargs):
format = kwargs.get('format', True)
url(urlpath(r'documents'), library_resource,
name="document_list_view_withformat"),
- url(urlpath(r'documents', DOC),
- document_resource, name="document_view_withformat"),
+ #url(urlpath(r'documents', DOC),
+ # document_resource, name="document_view_withformat"),
url(urlpath(r'documents', DOC, format=False),
document_resource, {'emitter_format': 'json'},
name="document_view"),
-
- url(urlpath(r'documents', DOC, 'text', REVISION, format=False),
+
+ url(urlpath(r'documents', DOC, 'gallery', format=False),
+ document_gallery, {'emitter_format': 'json'},
+ name="docgallery_view"),
+
+ # XML
+ url(urlpath(r'documents', DOC, 'text', format=False),
document_text_resource, {'emitter_format': 'rawxml'},
name="doctext_view"),
- url(urlpath(r'documents', DOC, 'html', REVISION, format=False),
+ # HTML
+ url(urlpath(r'documents', DOC, 'html', format=False),
document_html_resource, {'emitter_format': 'rawhtml'},
name="dochtml_view"),
- url(urlpath(r'documents', DOC, 'dc', REVISION),
- document_dc_resource,
- name="docdc_view_withformat"),
+ # DC
+ #url(urlpath(r'documents', DOC, 'dc'),
+ # document_dc_resource,
+ # name="docdc_view_withformat"),
- url(urlpath(r'documents', DOC, 'dc', REVISION, format=False),
+ url(urlpath(r'documents', DOC, 'dc', format=False),
document_dc_resource, {'emitter_format': 'json'},
name="docdc_view"),
+ # MERGE
url(urlpath(r'documents', DOC, 'revision', format=False),
document_merge, {'emitter_format': 'json'}, name="docmerge_view")
import api.response
-from wlrepo import MercurialLibrary
+import wlrepo
import settings
class TextEmitter(Emitter):
def hglibrary(func):
@wraps(func)
def decorated(self, *args, **kwargs):
- l = MercurialLibrary(settings.REPOSITORY_PATH)
+ l = wlrepo.open_library(settings.REPOSITORY_PATH, 'hg')
kwargs['lib'] = l
return func(self, *args, **kwargs)
return decorated
-
-
-
+
+
+
+import re
+NAT_EXPR = re.compile(r'(\d+)', re.LOCALE | re.UNICODE)
+def natural_order(get_key=lambda x: x):
+ def getter(key):
+ key = [int(x) if n%2 else x for (n,x) in enumerate(NAT_EXPR.split(get_key(key))) ]
+ return key
+
+ return getter
admin.site.register(explorer.models.EditorSettings)
admin.site.register(explorer.models.EditorPanel)
-admin.site.register(explorer.models.PullRequest)
\ No newline at end of file
+admin.site.register(explorer.models.PullRequest)
+admin.site.register(explorer.models.GalleryForDocument)
\ No newline at end of file
Przykład:
{
'panels': [
- {'name': 'htmleditor', 'ratio': 0.5},
+ {'name': 'htmleditor',
+ 'ratio': 0.5},
{'name': 'gallery', 'ratio': 0.5}
],
'recentFiles': [
# revision number in which the changes were merged (if any)
merged_rev = models.CharField(max_length=40, blank=True, null=True)
-
def __unicode__(self):
return unicode(self.comitter) + u':' + self.document
-
-def get_image_folders():
- return sorted(fn for fn in os.listdir(os.path.join(settings.MEDIA_ROOT, settings.IMAGE_DIR)) if not fn.startswith('.'))
+# Yes, this is intentionally unnormalized !
+class GalleryForDocument(models.Model):
+ name = models.CharField(max_length=100)
+
+ # directory containing scans under MEDIA_ROOT/
+ subpath = models.CharField(max_length=255)
-def get_images_from_folder(folder):
- return sorted(settings.MEDIA_URL + settings.IMAGE_DIR + u'/' + folder + u'/' + fn.decode('utf-8') for fn
- in os.listdir(os.path.join(settings.MEDIA_ROOT, settings.IMAGE_DIR, folder))
- if not fn.decode('utf-8').startswith('.'))
+ # document associated with the gallery
+ document = models.CharField(max_length=255)
+ def __unicode__(self):
+ return u"%s:%s" % self.subpath, self.document
\ No newline at end of file
def with_repo(view):
"""Open a repository for this view"""
def view_with_repo(request, *args, **kwargs):
- kwargs['repo'] = wlrepo.MercurialLibrary(settings.REPOSITORY_PATH)
+ kwargs['repo'] = wlrepo.open_library(settings.REPOSITORY_PATH, 'hg')
return view(request, *args, **kwargs)
return view_with_repo
# short-circut the api document list
doctree = library_resource.handler.read(request)
- print doctree['documents']
+ print "DOCTREE:", doctree['documents']
return direct_to_template(request, 'explorer/file_list.html', extra_context={
'filetree': doctree['documents'], 'bookform': bookform,
class RevisionNotFound(LibraryException):
def __init__(self, rev):
LibraryException.__init__(self, "Revision %r not found." % rev)
- pass
+
+class EntryNotFound(LibraryException):
+ def __init__(self, rev, entry, guesses=[]):
+ LibraryException.__init__(self, \
+ u"Entry '%s' at revision %r not found. %s" % (entry, rev, \
+ (u"Posible values:\n" + u',\n'.join(guesses)) if len(guesses) else u'') )
class DocumentAlreadyExists(LibraryException):
pass
# import backends to local namespace
-from mercurial_backend.library import MercurialLibrary
\ No newline at end of file
+
+def open_library(path, proto, *args, **kwargs):
+ if proto == 'hg':
+ import wlrepo.mercurial_backend
+ return wlrepo.mercurial_backend.MercurialLibrary(path, *args, **kwargs)
+
+ raise NotImplemented()
\ No newline at end of file
+++ /dev/null
-## -*- encoding: utf-8 -*-
-#
-#__author__ = "Łukasz Rekucki"
-#__date__ = "$2009-09-18 10:49:24$"
-#
-#__doc__ = """RAL implementation over Mercurial"""
-#
-#import mercurial
-#from mercurial import localrepo as hglrepo
-#from mercurial import ui as hgui
-#from mercurial.node import nullid
-#import re
-#import wlrepo
-#
-#FILTER = re.compile(r"^pub_(.+)\.xml$", re.UNICODE)
-#
-#def default_filter(name):
-# m = FILTER.match(name)
-# if m is not None:
-# return name, m.group(1)
-# return None
-#
-#class MercurialLibrary(wlrepo.Library):
-#
-# def __init__(self, path, maincabinet="default", ** kwargs):
-# super(wlrepo.Library, self).__init__( ** kwargs)
-#
-# self._hgui = hgui.ui()
-# self._hgui.config('ui', 'quiet', 'true')
-# self._hgui.config('ui', 'interactive', 'false')
-#
-# import os.path
-# self._ospath = self._sanitize_string(os.path.realpath(path))
-#
-# maincabinet = self._sanitize_string(maincabinet)
-#
-# if os.path.isdir(path):
-# try:
-# self._hgrepo = hglrepo.localrepository(self._hgui, path)
-# except mercurial.error.RepoError:
-# raise wlrepo.LibraryException("[HGLibrary] Not a valid repository at path '%s'." % path)
-# elif kwargs.get('create', False):
-# os.makedirs(path)
-# try:
-# self._hgrepo = hglrepo.localrepository(self._hgui, path, create=1)
-# except mercurial.error.RepoError:
-# raise wlrepo.LibraryException("[HGLibrary] Can't create a repository on path '%s'." % path)
-# else:
-# raise wlrepo.LibraryException("[HGLibrary] Can't open a library on path '%s'." % path)
-#
-# # fetch the main cabinet
-# lock = self._hgrepo.lock()
-# try:
-# btags = self._hgrepo.branchtags()
-#
-# if not self._has_branch(maincabinet):
-# raise wlrepo.LibraryException("[HGLibrary] No branch named '%s' to init main cabinet" % maincabinet)
-#
-# self._maincab = MercurialCabinet(self, maincabinet)
-# finally:
-# lock.release()
-#
-# @property
-# def ospath(self):
-# return self._ospath
-#
-# @property
-# def main_cabinet(self):
-# return self._maincab
-#
-# def document(self, docid, user, part=None, shelve=None):
-# return self.cabinet(docid, user, create=False).retrieve(part=part, shelve=shelve)
-#
-# def cabinet(self, docid, user, create=False):
-# docid = self._sanitize_string(docid)
-# user = self._sanitize_string(user)
-#
-# bname = self._bname(user, docid)
-#
-# lock = self._lock(True)
-# try:
-# if self._has_branch(bname):
-# return MercurialCabinet(self, doc=docid, user=user)
-#
-# if not create:
-# raise wlrepo.CabinetNotFound(bname)
-#
-# # check if the docid exists in the main cabinet
-# needs_touch = not self._maincab.exists(docid)
-# cab = MercurialCabinet(self, doc=docid, user=user)
-#
-# name, fileid = cab._filename(None)
-#
-# def cleanup_action(l):
-# if needs_touch:
-# l._fileopener()(fileid, "w").write('')
-# l._fileadd(fileid)
-#
-# garbage = [fid for (fid, did) in l._filelist() if not did.startswith(docid)]
-# l._filesrm(garbage)
-# print "removed: ", garbage
-#
-# # create the branch
-# self._create_branch(bname, before_commit=cleanup_action)
-# return MercurialCabinet(self, doc=docid, user=user)
-# finally:
-# lock.release()
-#
-# #
-# # Private methods
-# #
-#
-# #
-# # Locking
-# #
-#
-# def _lock(self, write_mode=False):
-# return self._hgrepo.wlock() # no support for read/write mode yet
-#
-# def _transaction(self, write_mode, action):
-# lock = self._lock(write_mode)
-# try:
-# return action(self)
-# finally:
-# lock.release()
-#
-# #
-# # Basic repo manipulation
-# #
-#
-# def _checkout(self, rev, force=True):
-# return MergeStatus(mercurial.merge.update(self._hgrepo, rev, False, force, None))
-#
-# def _merge(self, rev):
-# """ Merge the revision into current working directory """
-# return MergeStatus(mercurial.merge.update(self._hgrepo, rev, True, False, None))
-#
-# def _common_ancestor(self, revA, revB):
-# return self._hgrepo[revA].ancestor(self.repo[revB])
-#
-# def _commit(self, message, user=u"library"):
-# return self._hgrepo.commit(text=message, user=user)
-#
-#
-# def _fileexists(self, fileid):
-# return (fileid in self._hgrepo[None])
-#
-# def _fileadd(self, fileid):
-# return self._hgrepo.add([fileid])
-#
-# def _filesadd(self, fileid_list):
-# return self._hgrepo.add(fileid_list)
-#
-# def _filerm(self, fileid):
-# return self._hgrepo.remove([fileid])
-#
-# def _filesrm(self, fileid_list):
-# return self._hgrepo.remove(fileid_list)
-#
-# def _filelist(self, filter=default_filter):
-# for name in self._hgrepo[None]:
-# result = filter(name)
-# if result is None: continue
-#
-# yield result
-#
-# def _fileopener(self):
-# return self._hgrepo.wopener
-#
-# def _filectx(self, fileid, branchid):
-# return self._hgrepo.filectx(fileid, changeid=branchid)
-#
-# def _changectx(self, nodeid):
-# return self._hgrepo.changectx(nodeid)
-#
-# #
-# # BASIC BRANCH routines
-# #
-#
-# def _bname(self, user, docid):
-# """Returns a branch name for a given document and user."""
-# docid = self._sanitize_string(docid)
-# uname = self._sanitize_string(user)
-# return "personal_" + uname + "_file_" + docid;
-#
-# def _has_branch(self, name):
-# return self._hgrepo.branchmap().has_key(self._sanitize_string(name))
-#
-# def _branch_tip(self, name):
-# name = self._sanitize_string(name)
-# return self._hgrepo.branchtags()[name]
-#
-# def _create_branch(self, name, parent=None, before_commit=None):
-# name = self._sanitize_string(name)
-#
-# if self._has_branch(name): return # just exit
-#
-# if parent is None:
-# parent = self._maincab
-#
-# parentrev = parent._hgtip()
-#
-# self._checkout(parentrev)
-# self._hgrepo.dirstate.setbranch(name)
-#
-# if before_commit: before_commit(self)
-#
-# self._commit("[AUTO] Initial commit for branch '%s'." % name, user='library')
-#
-# # revert back to main
-# self._checkout(self._maincab._hgtip())
-# return self._branch_tip(name)
-#
-# def _switch_to_branch(self, branchname):
-# current = self._hgrepo[None].branch()
-#
-# if current == branchname:
-# return current # quick exit
-#
-# self._checkout(self._branch_tip(branchname))
-# return branchname
-#
-# def shelf(self, nodeid=None):
-# if nodeid is None:
-# nodeid = self._maincab._name
-# return MercurialShelf(self, self._changectx(nodeid))
-#
-#
-# #
-# # Utils
-# #
-#
-# @staticmethod
-# def _sanitize_string(s):
-# if isinstance(s, unicode):
-# s = s.encode('utf-8')
-# return s
-#
-#class MercurialCabinet(wlrepo.Cabinet):
-#
-# def __init__(self, library, branchname=None, doc=None, user=None):
-# if doc and user:
-# super(MercurialCabinet, self).__init__(library, doc=doc, user=user)
-# self._branchname = library._bname(user=user, docid=doc)
-# elif branchname:
-# super(MercurialCabinet, self).__init__(library, name=branchname)
-# self._branchname = branchname
-# else:
-# raise ValueError("Provide either doc/user or branchname")
-#
-# def shelf(self):
-# return self._library.shelf(self._branchname)
-#
-# def parts(self):
-# return self._execute_in_branch(action=lambda l, c: (e[1] for e in l._filelist()))
-#
-# def retrieve(self, part=None, shelf=None):
-# name, fileid = self._filename(part)
-#
-# print "Retrieving document %s from cab %s" % (name, self._name)
-#
-# if fileid is None:
-# raise wlrepo.LibraryException("Can't retrieve main document from main cabinet.")
-#
-# def retrieve_action(l,c):
-# if l._fileexists(fileid):
-# return MercurialDocument(c, name=name, fileid=fileid)
-# print "File %s not found " % fileid
-# return None
-#
-# return self._execute_in_branch(retrieve_action)
-#
-# def create(self, name, initial_data):
-# name, fileid = self._filename(name)
-#
-# if name is None:
-# raise ValueError("Can't create main doc for maincabinet.")
-#
-# def create_action(l, c):
-# if l._fileexists(fileid):
-# raise wlrepo.LibraryException("Can't create document '%s' in cabinet '%s' - it already exists" % (fileid, c.name))
-#
-# fd = l._fileopener()(fileid, "w")
-# fd.write(initial_data)
-# fd.close()
-# l._fileadd(fileid)
-# l._commit("File '%s' created." % fileid)
-# return MercurialDocument(c, fileid=fileid, name=name)
-#
-# return self._execute_in_branch(create_action)
-#
-# def exists(self, part=None, shelf=None):
-# name, filepath = self._filename(part)
-#
-# if filepath is None: return False
-# return self._execute_in_branch(lambda l, c: l._fileexists(filepath))
-#
-# def _execute_in_branch(self, action, write=False):
-# def switch_action(library):
-# old = library._switch_to_branch(self._branchname)
-# try:
-# return action(library, self)
-# finally:
-# library._switch_to_branch(old)
-#
-# return self._library._transaction(write_mode=write, action=switch_action)
-#
-#
-# def _filename(self, docid):
-# return self._partname(docid, 'xml')
-#
-# def _partname(self, docid, part):
-# docid = self._library._sanitize_string(part)
-# part = self._library._sanitize_string(part)
-#
-# if part is None:
-# part = 'xml'
-#
-# if self._maindoc == '' and docid is None:
-# return None
-#
-# return 'pub_' + docid + '.' + part
-#
-# def _fileopener(self):
-# return self._library._fileopener()
-#
-# def _hgtip(self):
-# return self._library._branch_tip(self._branchname)
-#
-# def _filectx(self, fileid):
-# return self._library._filectx(fileid, self._branchname)
-#
-# def ismain(self):
-# return (self._library.main_cabinet == self)
-#
-#class MercurialDocument(wlrepo.Document):
-#
-# def __init__(self, cabinet, docid):
-# super(MercurialDocument, self).__init__(cabinet, name=docid)
-# self._opener = self._cabinet._fileopener()
-# self._docid = docid
-# self._ctxs = {}
-#
-# def _ctx(self, part):
-# if not self._ctxs.has_key(part):
-# self._ctxs[part] = self._cabinet._filectx(self._fileid())
-# return self._ctxs[part]
-#
-# def _fileid(self, part='xml'):
-# return self._cabinet._partname(self._docid, part)
-#
-# def read(self, part='xml'):
-# return self._opener(self._ctx(part).path(), "r").read()
-#
-# def write(self, data, part='xml'):
-# return self._opener(self._ctx(part).path(), "w").write(data)
-#
-# def commit(self, message, user):
-# """Commit all parts of the document."""
-# self.library._fileadd(self._fileid)
-# self.library._commit(self._fileid, message, user)
-#
-# def update(self):
-# """Update parts of the document."""
-# lock = self.library._lock()
-# try:
-# if self._cabinet.ismain():
-# return True # always up-to-date
-#
-# user = self._cabinet.username or 'library'
-# mdoc = self.library.document(self._fileid)
-#
-# mshelf = mdoc.shelf()
-# shelf = self.shelf()
-#
-# if not mshelf.ancestorof(shelf) and not shelf.parentof(mshelf):
-# shelf.merge_with(mshelf, user=user)
-#
-# return True
-# finally:
-# lock.release()
-#
-# def share(self, message):
-# lock = self.library._lock()
-# try:
-# print "sharing from", self._cabinet, self._cabinet.username
-#
-# if self._cabinet.ismain():
-# return True # always shared
-#
-# if self._cabinet.username is None:
-# raise ValueError("Can only share documents from personal cabinets.")
-#
-# user = self._cabinet.username
-#
-# main = self.library.shelf()
-# local = self.shelf()
-#
-# no_changes = True
-#
-# # Case 1:
-# # * local
-# # |
-# # * <- can also be here!
-# # /|
-# # / |
-# # main * *
-# # | |
-# # The local branch has been recently updated,
-# # so we don't need to update yet again, but we need to
-# # merge down to default branch, even if there was
-# # no commit's since last update
-#
-# if main.ancestorof(local):
-# print "case 1"
-# main.merge_with(local, user=user, message=message)
-# no_changes = False
-# # Case 2:
-# #
-# # main * * local
-# # |\ |
-# # | \|
-# # | *
-# # | |
-# #
-# # Default has no changes, to update from this branch
-# # since the last merge of local to default.
-# elif local.has_common_ancestor(main):
-# print "case 2"
-# if not local.parentof(main):
-# main.merge_with(local, user=user, message=message)
-# no_changes = False
-#
-# # Case 3:
-# # main *
-# # |
-# # * <- this case overlaps with previos one
-# # |\
-# # | \
-# # | * local
-# # | |
-# #
-# # There was a recent merge to the defaul branch and
-# # no changes to local branch recently.
-# #
-# # Use the fact, that user is prepared to see changes, to
-# # update his branch if there are any
-# elif local.ancestorof(main):
-# print "case 3"
-# if not local.parentof(main):
-# local.merge_with(main, user=user, message='Local branch update.')
-# no_changes = False
-# else:
-# print "case 4"
-# local.merge_with(main, user=user, message='Local branch update.')
-# local = self.shelf()
-# main.merge_with(local, user=user, message=message)
-#
-# print "no_changes: ", no_changes
-# return no_changes
-# finally:
-# lock.release()
-#
-# def shared(self):
-# return self.library.main_cabinet.retrieve(self._name)
-#
-# def exists(self, part='xml'):
-# return self._cabinet.exists(self._fileid(part))
-#
-# @property
-# def size(self):
-# return self._filectx.size()
-#
-# def shelf(self):
-# return self._cabinet.shelf()
-#
-# @property
-# def last_modified(self):
-# return self._filectx.date()
-#
-# def __str__(self):
-# return u"Document(%s->%s)" % (self._cabinet.name, self._name)
-#
-# def __eq__(self, other):
-# return self._filectx == other._filectx
-#
-#
-#
-#class MercurialShelf(wlrepo.Shelf):
-#
-# def __init__(self, lib, changectx):
-# super(MercurialShelf, self).__init__(lib)
-#
-# if isinstance(changectx, str):
-# self._changectx = lib._changectx(changectx)
-# else:
-# self._changectx = changectx
-#
-# @property
-# def _rev(self):
-# return self._changectx.node()
-#
-# def __str__(self):
-# return self._changectx.hex()
-#
-# def __repr__(self):
-# return "MercurialShelf(%s)" % self._changectx.hex()
-#
-# def ancestorof(self, other):
-# nodes = list(other._changectx._parents)
-# while nodes[0].node() != nullid:
-# v = nodes.pop(0)
-# if v == self._changectx:
-# return True
-# nodes.extend( v._parents )
-# return False
-#
-# def parentof(self, other):
-# return self._changectx in other._changectx._parents
-#
-# def has_common_ancestor(self, other):
-# a = self._changectx.ancestor(other._changectx)
-# # print a, self._changectx.branch(), a.branch()
-#
-# return (a.branch() == self._changectx.branch())
-#
-# def merge_with(self, other, user, message):
-# lock = self._library._lock(True)
-# try:
-# self._library._checkout(self._changectx.node())
-# self._library._merge(other._changectx.node())
-# self._library._commit(user=user, message=message)
-# finally:
-# lock.release()
-#
-# def __eq__(self, other):
-# return self._changectx.node() == other._changectx.node()
-#
-#
-#class MergeStatus(object):
-# def __init__(self, mstatus):
-# self.updated = mstatus[0]
-# self.merged = mstatus[1]
-# self.removed = mstatus[2]
-# self.unresolved = mstatus[3]
-#
-# def isclean(self):
-# return self.unresolved == 0
-#
-#class UpdateStatus(object):
-#
-# def __init__(self, mstatus):
-# self.modified = mstatus[0]
-# self.added = mstatus[1]
-# self.removed = mstatus[2]
-# self.deleted = mstatus[3]
-# self.untracked = mstatus[4]
-# self.ignored = mstatus[5]
-# self.clean = mstatus[6]
-#
-# def has_changes(self):
-# return bool(len(self.modified) + len(self.added) + \
-# len(self.removed) + len(self.deleted))
-#
-#__all__ = ["MercurialLibrary"]
\ No newline at end of file
@property
def document_name(self):
- return self._docname
+ return self._docname.decode('utf-8')
@property
def user_name(self):
- return self._username
+ return self._username.decode('utf-8')
def hgrev(self):
return self._changectx.node()
def hgbranch(self):
return self._changectx.branch()
+ @property
+ def timestamp(self):
+ return self._changectx.date()[0]
+
def __unicode__(self):
return u"%s" % self._changectx.hex()
+ def __str__(self):
+ return self.__unicode__().encode('utf-8')
+
def __repr__(self):
return "%s" % self._changectx.hex()
__doc__ = "Module documentation."
import wlrepo
+import mercurial.error
class MercurialDocument(wlrepo.Document):
def data(self, entry):
- path = self._revision._docname + '.' + entry
- return self._library._filectx(path, \
- self._revision.hgrev()).data()
+ path = self._library._sanitize_string(self.id + u'.' + entry)
+ try:
+ return self._library._filectx(path, \
+ self._revision.hgrev()).data().decode('utf-8')
+ except mercurial.error.LookupError, e:
+ fl = [x.decode('utf-8') for x in self._revision._changectx]
+ raise wlrepo.EntryNotFound(self._revision, path.decode('utf-8'), fl)
def quickwrite(self, entry, data, msg, user=None):
user = user or self.owner
f.close()
l._fileadd(r(entry))
- return self.invoke_and_commit(write, lambda d: (msg, self.owner))
+ return self.invoke_and_commit(write, lambda d: (msg, \
+ self._library._sanitize_string(self.owner)) )
- def invoke_and_commit(self, ops,
- commit_info):
+ def invoke_and_commit(self, ops, commit_info):
lock = self._library.lock()
try:
self._library._checkout(self._revision.hgrev())
def entry_path(entry):
- return self.id + '.' + entry
+ return self._library._sanitize_string(self.id + u'.' + entry)
ops(self._library, entry_path)
message, user = commit_info(self)
finally:
lock.release()
- def __str__(self):
+ def __unicode__(self):
return u"Document(%s:%s)" % (self.name, self.owner)
+ def __str__(self):
+ return self.__unicode__().encode('utf-8')
+
def __eq__(self, other):
return (self._revision == other._revision) and (self.name == other.name)
from mercurial import error
import wlrepo
-from wlrepo.mercurial_backend.document import MercurialDocument
from wlrepo.mercurial_backend import MercurialRevision
+from wlrepo.mercurial_backend.document import MercurialDocument
class MergeStatus(object):
def __init__(self, mstatus):
@property
def ospath(self):
- return self._ospath
+ return self._ospath.decode('utf-8')
def document_for_rev(self, revision):
if revision is None:
raise ValueError("Revision can't be None.")
if not isinstance(revision, MercurialRevision):
+ revision = self._sanitize_string(unicode(revision))
rev = self.get_revision(revision)
else:
rev = revision
def get_revision(self, revid):
revid = self._sanitize_string(revid)
-
- ctx = self._changectx(revid)
+
+ try:
+ ctx = self._changectx(revid)
+ except mercurial.error.RepoError, e:
+ raise wlrepo.RevisionNotFound(revid)
if ctx is None:
- raise RevisionNotFound(revid)
+ raise wlrepo.RevisionNotFound(revid)
if self._revcache.has_key(ctx):
return self._revcache[ctx]
return MercurialRevision(self, ctx)
- def fulldocid(self, docid, user=None):
- docid = self._sanitize_string(docid)
- user = self._sanitize_string(user)
-
- fulldocid = ''
+ def fulldocid(self, docid, user=None):
+ fulldocid = u''
if user is not None:
- fulldocid += '$user:' + user
- fulldocid += '$doc:' + docid
+ fulldocid += u'$user:' + user
+ fulldocid += u'$doc:' + docid
return fulldocid
try:
self._hgrepo[revid]
return True
- except error.RepoError:
+ except mercurial.error.RepoError:
return False
def document_create(self, docid):
- docid = self._sanitize_string(docid)
+
# check if it already exists
fullid = self.fulldocid(docid)
if self.has_revision(fullid):
- raise wlrepo.DocumentAlreadyExists("Document %s already exists!" % docid);
+ raise wlrepo.DocumentAlreadyExists(u"Document %s already exists!" % docid);
# doesn't exist
- self._create_branch(fullid)
+ self._create_branch(self._sanitize_string(fullid))
return self.document_for_rev(fullid)
#
});
+Editor.ImageGalleryModel = Editor.Model.extend({
+ _className: 'Editor.ImageGalleryModel',
+ serverURL: null,
+ state: 'empty',
+
+ init: function(serverURL) {
+ this._super();
+ this.set('state', 'empty');
+ this.serverURL = serverURL;
+ // olewać data
+ this.pages = [];
+ },
+
+ load: function() {
+ if (this.get('state') == 'empty') {
+ this.set('state', 'loading');
+ $.ajax({
+ url: this.serverURL,
+ dataType: 'json',
+ success: this.loadingSucceeded.bind(this)
+ });
+ }
+ },
+
+ loadingSucceeded: function(data) {
+ if (this.get('state') != 'loading') {
+ alert('erroneous state:', this.get('state'));
+ }
+
+ this.set('pages', data[0].pages);
+ this.set('state', 'synced');
+ },
+
+ set: function(property, value) {
+ if (property == 'state') {
+ console.log(this.description(), ':', property, '=', value);
+ }
+ return this._super(property, value);
+ }
+});
+
+
Editor.DocumentModel = Editor.Model.extend({
_className: 'Editor.DocumentModel',
data: null, // name, text_url, user_revision, latest_shared_rev, parts_url, dc_url, size, merge_url
this.set('state', 'synced');
this.contentModels = {
'xml': new Editor.XMLModel(data.text_url, data.user_revision),
- 'html': new Editor.HTMLModel(data.html_url, data.user_revision)
+ 'html': new Editor.HTMLModel(data.html_url, data.user_revision),
+ 'gallery': new Editor.ImageGalleryModel(data.gallery_url)
};
for (var key in this.contentModels) {
this.contentModels[key].addObserver(this, 'state', this.contentModelStateChanged.bind(this));
<script src="{{STATIC_URL}}js/views/split.js" type="text/javascript" charset="utf-8"></script>
<script src="{{STATIC_URL}}js/views/xml.js" type="text/javascript" charset="utf-8"></script>
<script src="{{STATIC_URL}}js/views/html.js" type="text/javascript" charset="utf-8"></script>
+ <script src="{{STATIC_URL}}js/views/gallery.js" type="text/javascript" charset="utf-8"></script>
<script src="{{STATIC_URL}}js/views/panel_container.js" type="text/javascript" charset="utf-8"></script>
<script src="{{STATIC_URL}}js/models.js" type="text/javascript" charset="utf-8"></script>
<div class="htmlview">
</div>
</script>
+
+ <script type="text/html" charset="utf-8" id="image-gallery-view-template">
+ <div class="image-gallery-view-template">
+
+ <div class="image-gallery-panel-header">
+ <p>
+ <button type="button" class="image-gallery-prev-button">Previous</button>
+ <input type="input" class="image-gallery-current-page" />
+ <button type="button" class="image-gallery-next-button">Next</button>
+ </p>
+ </div>
+
+ <div>
+ <% for (page in model.pages) { %>
+ <p>page.url</p>
+ <% }; %>
+ </div>
+
+ </div>
+ </script>
<script type="text/html" charset="utf-8" id="button-toolbar-view-template">
<div class="buttontoolbarview">