diff --git a/browser/concept.py b/browser/concept.py index e795ade..0aa03e3 100644 --- a/browser/concept.py +++ b/browser/concept.py @@ -413,7 +413,7 @@ class ConceptView(BaseView): if r.order != pos: r.order = pos - def resources(self): + def getResources(self): form = self.request.form #if form.get('loops.viewName') == 'index.html' and self.editable: if self.editable: @@ -430,6 +430,9 @@ class ConceptView(BaseView): if fv.check(r.first): yield ResourceRelationView(r, self.request, contextIsSecond=True) + def resources(self): + return self.getResources() + @Lazy def resourcesList(self): from loops.browser.resource import ResourceRelationView diff --git a/common.py b/common.py index 27e0ede..0b00e65 100644 --- a/common.py +++ b/common.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2011 Helmut Merz helmutm@cy55.de +# Copyright (c) 2012 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -98,7 +98,7 @@ class AdapterBase(object): adapts(IConcept) - _adapterAttributes = ('context', '__parent__') + _adapterAttributes = ('context', '__parent__', 'request') _contextAttributes = list(IConcept) _noexportAttributes = () _textIndexAttributes = () @@ -106,6 +106,7 @@ class AdapterBase(object): __is_dummy__ = False __type__ = None + request = None languageInfo = None def __init__(self, context): diff --git a/compound/book/browser.py b/compound/book/browser.py index d6e2232..533e12d 100644 --- a/compound/book/browser.py +++ b/compound/book/browser.py @@ -77,6 +77,30 @@ class SectionView(Base, ConceptView): def sectionType(self): return self.conceptManager['section'] + def getResources(self): + relViews = super(SectionView, self).getResources() + return relViews + + @Lazy + def textResources(self): + self.images = [[]] + result = [] + idx = 0 + for rv in self.getResources(): + if rv.context.contentType.startswith('text/'): + idx += 1 + result.append(rv) + self.images.append([]) + else: + self.registerDojoLightbox() + url = self.nodeView.getUrlForTarget(rv.context) + src = '%s/mediaasset.html?v=small' % url + fullSrc = '%s/mediaasset.html?v=medium' % url + img = dict(src=src, fullImageUrl=fullSrc, title=rv.title, + description=rv.description, url=url, object=rv) + self.images[idx].append(img) + return result + def getCssClassForResource(self, r): for c in r.context.getConcepts([self.defaultPredicate]): if c.conceptType == self.documentTypeType: diff --git a/compound/book/loops_book_de.dmp b/compound/book/loops_book_de.dmp index 171323d..0d3d92d 100644 --- a/compound/book/loops_book_de.dmp +++ b/compound/book/loops_book_de.dmp @@ -21,6 +21,7 @@ concept(u'issubtype', u'is Subtype', u'predicate', options=u'hide_children', # document types concept(u'keyquestions', u'Leitfragen', u'documenttype') concept(u'textelement', u'Textabschnitt', u'documenttype') +concept(u'textelement2', u'Textabschnitt separat', u'documenttype') concept(u'quote', u'Zitat', u'documenttype') concept(u'story', u'Geschichte', u'documenttype') concept(u'usecase', u'Fallbeispiel', u'documenttype') diff --git a/compound/book/view_macros.pt b/compound/book/view_macros.pt index d64994d..cef53c2 100644 --- a/compound/book/view_macros.pt +++ b/compound/book/view_macros.pt @@ -14,7 +14,7 @@ -
+
@@ -45,6 +46,15 @@
+
diff --git a/integrator/README.txt b/integrator/README.txt index cba0381..62b6532 100644 --- a/integrator/README.txt +++ b/integrator/README.txt @@ -231,7 +231,7 @@ Extracting Document Properties from MS Office Files >>> path = os.path.join(dataDir, 'office') >>> fn = os.path.join(path, 'example.docx') >>> os.path.getsize(fn) - 20337... + 23561... >>> officeFile = addAndConfigureObject(resources, Resource, 'test.docx', ... title=u'Example Word File', resourceType=tOfficeFile, @@ -241,7 +241,7 @@ Extracting Document Properties from MS Office Files >>> content = aOfficeFile.data >>> len(content) - 17409 + 20327 Clean up: >>> shutil.copy(fn + '.sav', fn) diff --git a/integrator/browser.py b/integrator/browser.py index 0ecf9bd..aeafa87 100644 --- a/integrator/browser.py +++ b/integrator/browser.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2008 Helmut Merz helmutm@cy55.de +# Copyright (c) 2012 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,8 +18,6 @@ """ View class(es) for integrating external objects. - -$Id$ """ from zope import interface, component @@ -42,7 +40,9 @@ class ExternalCollectionView(ConceptView): def update(self): if 'update' in self.request.form: cta = adapted(self.context) - if cta is not None: - cta.update() + cta.request = self.request + cta.update() + if cta.updateMessage is not None: + self.request.form['message'] = cta.updateMessage return True diff --git a/integrator/collection.py b/integrator/collection.py index a6a6670..35d4a9c 100644 --- a/integrator/collection.py +++ b/integrator/collection.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2009 Helmut Merz helmutm@cy55.de +# Copyright (c) 2012 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -19,8 +19,6 @@ """ Concept adapter(s) for external collections, e.g. a directory in the file system. - -$Id$ """ from datetime import datetime @@ -62,10 +60,12 @@ class ExternalCollectionAdapter(AdapterBase): implements(IExternalCollection) adapts(IConcept) - _adapterAttributes = ('context', '__parent__', 'exclude', 'newResources') + _adapterAttributes = AdapterBase._adapterAttributes + ( + 'exclude', 'newResources', 'updateMessage') _contextAttributes = list(IExternalCollection) + list(IConcept) newResources = None + updateMessage = None def getExclude(self): return getattr(self.context, '_exclude', None) or [] @@ -101,12 +101,17 @@ class ExternalCollectionAdapter(AdapterBase): adobj = adapted(obj) directory = provider.getDirectory(self) adobj.storageParams=dict(subdirectory=directory) + adobj.request = self.request adobj.externalAddress = addr + # collect error information + if adobj.processingErrors: + message = self.updateMessage or u'' + message += u'
'.join(adobj.processingErrors) + self.updateMessage = message # force reindexing notify(ObjectModifiedEvent(obj)) else: new.append(addr) - #print '*** new', new if new: self.newResources = provider.createExtFileObjects(self, new) for r in self.newResources: @@ -205,7 +210,13 @@ class DirectoryCollectionProvider(object): contentType=contentType, ) adobj = adapted(obj) + adobj.request = client.request adobj.externalAddress = addr # must be set last + # collect error information + if adobj.processingErrors: + message = client.updateMessage or u'' + message += u'
'.join(adobj.processingErrors) + client.updateMessage = message yield obj def getDirectory(self, client): diff --git a/integrator/collection_macros.pt b/integrator/collection_macros.pt index 6df9ca0..8c3e898 100644 --- a/integrator/collection_macros.pt +++ b/integrator/collection_macros.pt @@ -7,6 +7,10 @@ +
diff --git a/integrator/office/base.py b/integrator/office/base.py index 92ed93b..67fe4bc 100644 --- a/integrator/office/base.py +++ b/integrator/office/base.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2010 Helmut Merz helmutm@cy55.de +# Copyright (c) 2012 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,8 +18,6 @@ """ Resource adapter(s) for MS Office files. - -$Id$ """ from datetime import date, datetime, timedelta @@ -56,6 +54,7 @@ class OfficeFile(ExternalFileAdapter): propertyMap = {u'Revision:': 'version'} propFileName = 'docProps/custom.xml' + corePropFileName = 'docProps/core.xml' fileExtensions = ('.docm', '.docx', 'dotm', 'dotx', 'pptx', 'potx', 'ppsx', '.xlsm', '.xlsx', '.xltm', '.xltx') @@ -88,20 +87,32 @@ class OfficeFile(ExternalFileAdapter): from logging import getLogger self.logger.warn(e) return [] + if self.corePropFileName not in zf.namelist(): + self.logger.warn('Core properties not found in file %s.' % + self.externalAddress) if self.propFileName not in zf.namelist(): self.logger.warn('Custom properties not found in file %s.' % self.externalAddress) propsXml = zf.read(self.propFileName) + corePropsXml = zf.read(self.corePropFileName) + # TODO: read core.xml, return both trees in dictionary zf.close() - return etree.fromstring(propsXml) + return {'custom': etree.fromstring(propsXml), + 'core': etree.fromstring(corePropsXml)} def getDocProperty(self, pname): - for p in self.docPropertyDom: + for p in self.docPropertyDom['custom']: name = p.attrib.get('name') if name == pname: return p[0].text return None + def getCoreProperty(self, pname): + for p in self.docPropertyDom['core']: + if p.tag.endswith(pname): + return p.text + return None + def processDocument(self): changed = False docVersion = None @@ -109,11 +120,14 @@ class OfficeFile(ExternalFileAdapter): strType = ('{http://schemas.openxmlformats.org/' 'officeDocument/2006/docPropsVTypes}lpwstr') attributes = {} - dom = self.docPropertyDom + # get dc:description from core.xml + desc = self.getCoreProperty('description') + if desc is not None: + attributes['comments'] = desc + dom = self.docPropertyDom['custom'] for p in dom: name = p.attrib.get('name') value = p[0].text - #print '***', self.externalAddress, name, value, p[0].tag attr = self.propertyMap.get(name) if attr == 'version': docVersion = value @@ -136,7 +150,9 @@ class OfficeFile(ExternalFileAdapter): newZf.writestr(self.propFileName, etree.tostring(dom)) newZf.close() shutil.move(newFn, fn) - self.update(attributes) + errors = self.update(attributes) + if errors: + self.processingErrors = errors def update(self, attributes): # to be implemented by subclass @@ -146,10 +162,10 @@ class OfficeFile(ExternalFileAdapter): def parseDate(s): if not s: return None - tt = strptime(s, '%Y-%m-%dT%H:%M:%SZ') - #try: - # tt = strptime(s, '%Y-%m-%dT%H:%M:%SZ') - #except ValueError: + try: + tt = strptime(s, '%Y-%m-%dT%H:%M:%SZ') + except ValueError: + return None # try: # tt = strptime(s, '%d.%m.%y') # except ValueError: diff --git a/integrator/testdata/office/example.docx b/integrator/testdata/office/example.docx index 0ab00cb..7f17545 100644 Binary files a/integrator/testdata/office/example.docx and b/integrator/testdata/office/example.docx differ diff --git a/integrator/testdata/office/example.docx.sav b/integrator/testdata/office/example.docx.sav index 0ab00cb..7f17545 100644 Binary files a/integrator/testdata/office/example.docx.sav and b/integrator/testdata/office/example.docx.sav differ diff --git a/locales/de/LC_MESSAGES/loops.mo b/locales/de/LC_MESSAGES/loops.mo index cafb12f..d079c1e 100644 Binary files a/locales/de/LC_MESSAGES/loops.mo and b/locales/de/LC_MESSAGES/loops.mo differ diff --git a/locales/de/LC_MESSAGES/loops.po b/locales/de/LC_MESSAGES/loops.po index 9033888..282a6e4 100644 --- a/locales/de/LC_MESSAGES/loops.po +++ b/locales/de/LC_MESSAGES/loops.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: $Id$\n" "POT-Creation-Date: 2007-05-22 12:00 CET\n" -"PO-Revision-Date: 2012-08-20 12:00 CET\n" +"PO-Revision-Date: 2012-09-17 12:00 CET\n" "Last-Translator: Helmut Merz \n" "Language-Team: loops developers \n" "MIME-Version: 1.0\n" @@ -758,6 +758,9 @@ msgstr "Kommentare" msgid "Add Comment" msgstr "Kommentar hinzufügen" +msgid "Subject" +msgstr "Thema" + msgid "Selection using: $targets" msgstr "Auswahl über: $targets" diff --git a/organize/comment/browser.py b/organize/comment/browser.py index 1a46402..2179c76 100644 --- a/organize/comment/browser.py +++ b/organize/comment/browser.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2008 Helmut Merz helmutm@cy55.de +# Copyright (c) 2012 Helmut Merz helmutm@cy55.de # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,8 +18,6 @@ """ Definition of view classes and other browser related stuff for comments. - -$Id$ """ from zope import interface, component @@ -52,6 +50,8 @@ class CommentsView(NodeView): @Lazy def allowed(self): + if self.isAnonymous: + return False return (self.virtualTargetObject is not None and self.globalOptions('organize.allowComments')) @@ -120,8 +120,8 @@ class CreateComment(EditObject): def update(self): form = self.request.form subject = form.get('subject') - text = form.get('text') - if not subject or not text or self.personId is None or self.object is None: + text = form.get('text') or u'' + if not subject or self.personId is None or self.object is None: return True #contentType = form.get('contentType') or 'text/restructured' rm = self.view.loopsRoot.getRecordManager() diff --git a/organize/comment/comment_macros.pt b/organize/comment/comment_macros.pt index 67c4b41..c512233 100644 --- a/organize/comment/comment_macros.pt +++ b/organize/comment/comment_macros.pt @@ -58,7 +58,7 @@