summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrédéric Péters <fpeters@entrouvert.com>2014-11-18 13:11:32 (GMT)
committerFrédéric Péters <fpeters@entrouvert.com>2014-11-18 13:12:39 (GMT)
commit04506ca8502230342821463368dab715947e9730 (patch)
tree5fa3dbbc81824da01461ef18eaf07c9b2177b942
parent0dc5fe57ed62f325d36aff4358524a844e695006 (diff)
downloadpfwbged.tabellio-04506ca8502230342821463368dab715947e9730.zip
pfwbged.tabellio-04506ca8502230342821463368dab715947e9730.tar.gz
pfwbged.tabellio-04506ca8502230342821463368dab715947e9730.tar.bz2
add DocumentsFolder listing documents from Tabellio
Creating dynamic DmsFile as objects for the moment.
-rw-r--r--setup.py1
-rw-r--r--src/pfwbged/tabellio/configure.zcml8
-rw-r--r--src/pfwbged/tabellio/documents.py175
-rw-r--r--src/pfwbged/tabellio/profiles/default/metadata.xml6
-rw-r--r--src/pfwbged/tabellio/profiles/default/types.xml5
-rw-r--r--src/pfwbged/tabellio/profiles/default/types/pfwbged.tabellio.documentsfolder.xml47
6 files changed, 242 insertions, 0 deletions
diff --git a/setup.py b/setup.py
index 3eb6be9..5e4edd9 100644
--- a/setup.py
+++ b/setup.py
@@ -45,6 +45,7 @@ setup(
'setuptools',
'five.grok',
'plone.app.contenttypes',
+ 'Products.SQLAlchemyDA',
],
entry_points="""
[z3c.autoinclude.plugin]
diff --git a/src/pfwbged/tabellio/configure.zcml b/src/pfwbged/tabellio/configure.zcml
index 64ab71a..15d1239 100644
--- a/src/pfwbged/tabellio/configure.zcml
+++ b/src/pfwbged/tabellio/configure.zcml
@@ -11,4 +11,12 @@
<include package="five.grok" />
<grok:grok package="." />
+ <genericsetup:registerProfile
+ name="default"
+ title="pfwbged.tabellio"
+ directory="profiles/default"
+ provides="Products.GenericSetup.interfaces.EXTENSION"
+ />
+
+
</configure>
diff --git a/src/pfwbged/tabellio/documents.py b/src/pfwbged/tabellio/documents.py
new file mode 100644
index 0000000..336d303
--- /dev/null
+++ b/src/pfwbged/tabellio/documents.py
@@ -0,0 +1,175 @@
+import datetime
+
+from plone import api
+from five import grok
+from zope.interface import implements
+from AccessControl import ClassSecurityInfo, getSecurityManager
+from AccessControl.Permissions import access_contents_information
+
+from plone.dexterity.content import Container
+from plone.supermodel import model
+
+class IDocumentsFolder(model.Schema):
+ pass
+
+
+class DocumentsFolder(Container):
+ implements(IDocumentsFolder)
+ security = ClassSecurityInfo()
+
+ _v_dbcache = None # volatile attribute
+
+ @property
+ def db_connection(self):
+ return api.portal.get().db._wrapper.connection
+
+ def __iter__(self):
+ if not self._v_dbcache:
+ self._v_dbcache = {}
+
+ cursor = self.db_connection.cursor()
+ cursor.execute('''SELECT id, ts, intit, textdefts
+ FROM t_document''')
+ while True:
+ row = cursor.fetchone()
+ if row is None:
+ break
+ rowid, ts, intit, textdfts = row
+ self._v_dbcache[rowid] = {'ts': ts, 'intit': intit, 'textdfts': textdfts}
+ yield rowid
+
+ cursor.close()
+
+ def __getitem__(self, id):
+ try:
+ int(id)
+ except ValueError:
+ pass
+ else:
+ cursor = self.db_connection.cursor()
+ cursor.execute('''SELECT id, intit, sess
+ FROM t_document
+ WHERE id = %(id)s''', {'id': id})
+ row = cursor.fetchone()
+ if row is None:
+ return super(DocumentsFolder, self).__getitem__(id)
+ cursor.close()
+
+ row_id, intit, sess = row
+ from collective.dms.basecontent.dmsfile import DmsFile
+ t = DmsFile(id=row_id, title=intit, label=sess)
+ t.portal_type = 'dmsmainfile'
+ from Acquisition import aq_chain
+ return aq_chain(t.__of__(self))[0]
+ return super(DocumentsFolder, self).__getitem__(id)
+
+ def keys(self):
+ return list(self.__iter__())
+
+ def getFolderContents(self, *args, **kwargs):
+ folder = self
+ parent_path = '/'.join(folder.getPhysicalPath()) + '/'
+ parent_url = folder.absolute_url() + '/'
+
+ class FakeBrain(object):
+ def __init__(self, object_id):
+ self.id = object_id
+ self._object = None
+ self.getId = object_id
+ self.getObjSize = 0
+ self.is_folderish = True
+ self.portal_type = 'dmsmainfile'
+ self.Creator = 'Tabellio'
+
+ def Type(self):
+ return self.portal_type
+
+ def get_object_attibute(self, attribute):
+ if not self._object:
+ self._object = folder[self.id]
+ return getattr(self._object, attribute)
+
+ @property
+ def modified(self):
+ if folder._v_dbcache and self.id in folder._v_dbcache:
+ return folder._v_dbcache[self.id]['ts']
+ return datetime.datetime.now()
+
+ def ModificationDate(self):
+ return self.modified
+
+ @property
+ def CreationDate(self):
+ if folder._v_dbcache and self.id in folder._v_dbcache:
+ t = folder._v_dbcache[self.id]['textdfts']
+ if t:
+ return t
+ return datetime.datetime.now()
+
+ @property
+ def title(self):
+ if folder._v_dbcache and self.id in folder._v_dbcache:
+ return folder._v_dbcache[self.id]['intit']
+ return self.get_object_attibute('title')
+
+ def pretty_title_or_id(self):
+ if self.title:
+ return self.title
+ return self.id
+
+ def Title(self):
+ return self.title
+
+ review_state = None
+ Description = None
+
+ def getPath(self):
+ return parent_path + self.id
+
+ def getURL(self, relative=True):
+ if relative:
+ return self.id
+ return parent_url + self.id
+
+ # plone.batching.batch doesn't support generators
+ t = []
+ for k in self.__iter__():
+ t.append(FakeBrain(k))
+ return t
+
+ # Acquisition wrappers don't support the __iter__ slot, so re-implement
+ # iteritems to call __iter__ directly.
+ def iteritems(self):
+ for k in self.__iter__():
+ yield (k, self[k])
+
+ security.declareProtected(access_contents_information,
+ 'objectIds')
+ def objectIds(self, spec=None):
+ # Returns a list of subobject ids of the current object.
+ # If 'spec' is specified, returns objects whose meta_type
+ # matches 'spec'.
+ assert spec is None, 'spec argument unsupported'
+ return self.__iter__()
+
+
+ security.declareProtected(access_contents_information,
+ 'objectValues')
+ def objectValues(self, spec=None):
+ # Returns a list of actual subobjects of the current object.
+ # If 'spec' is specified, returns only objects whose meta_type
+ # match 'spec'.
+ assert spec is None, 'spec argument unsupported'
+ for k in self.__iter__():
+ yield self[k]
+
+ security.declareProtected(access_contents_information,
+ 'objectItems')
+ def objectItems(self, spec=None):
+ # Returns a list of (id, subobject) tuples of the current object.
+ # If 'spec' is specified, returns only objects whose meta_type match
+ # 'spec'
+ assert spec is None, 'spec argument unsupported'
+ return self.iteritems()
+
+grok.context(DocumentsFolder)
diff --git a/src/pfwbged/tabellio/profiles/default/metadata.xml b/src/pfwbged/tabellio/profiles/default/metadata.xml
new file mode 100644
index 0000000..58812bd
--- /dev/null
+++ b/src/pfwbged/tabellio/profiles/default/metadata.xml
@@ -0,0 +1,6 @@
+<metadata>
+ <version>0.1</version>
+ <dependencies>
+ </dependencies>
+</metadata>
+
diff --git a/src/pfwbged/tabellio/profiles/default/types.xml b/src/pfwbged/tabellio/profiles/default/types.xml
new file mode 100644
index 0000000..13c4681
--- /dev/null
+++ b/src/pfwbged/tabellio/profiles/default/types.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0"?>
+<object name="portal_types" meta_type="Plone Types Tool">
+ <property name="title">Controls the available content types in your portal</property>
+ <object name="pfwbged.tabellio.documentsfolder" meta_type="Dexterity FTI"/>
+</object>
diff --git a/src/pfwbged/tabellio/profiles/default/types/pfwbged.tabellio.documentsfolder.xml b/src/pfwbged/tabellio/profiles/default/types/pfwbged.tabellio.documentsfolder.xml
new file mode 100644
index 0000000..7a58827
--- /dev/null
+++ b/src/pfwbged/tabellio/profiles/default/types/pfwbged.tabellio.documentsfolder.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<object name="pfwbged.tabellio.documentsfolder" meta_type="Dexterity FTI" i18n:domain="plone"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n">
+ <property name="title" i18n:translate="">Documents from Tabellio</property>
+ <property name="icon_expr">string:${portal_url}/++resource++pfwbged.tabellio.documentsfolder_icon.png</property>
+ <!--<property name="factory">pfwbged.tabellio.documentsfolder</property>-->
+ <property name="add_view_expr">string:${folder_url}/++add++pfwbged.tabellio.documentsfolder</property>
+ <property name="link_target"></property>
+ <property name="immediate_view">view</property>
+ <property name="global_allow">True</property>
+ <property name="filter_content_types">True</property>
+ <property name="allow_discussion">False</property>
+ <property name="default_view">view</property>
+ <property name="view_methods">
+ <element value="view"/>
+ </property>
+ <property name="default_view_fallback">False</property>
+ <property name="add_permission">cmf.AddPortalContent</property>
+ <property name="klass">pfwbged.tabellio.documents.DocumentsFolder</property>
+ <property name="behaviors">
+ <element value="plone.app.content.interfaces.INameFromTitle"/>
+ <element value="plone.app.dexterity.behaviors.metadata.IBasic"/>
+ </property>
+
+ <!-- Contained Types -->
+ <property name="filter_content_types">True</property>
+ <property name="allowed_content_types" purge="False">
+ </property>
+
+ <!-- DO NOT use a model_source or it removes manually added fields while reapplying the profile -->
+ <!--property name="model_source" /-->
+ <property name="schema">pfwbged.tabellio.documents.IDocumentsFolder</property>
+ <alias from="(Default)" to="(dynamic view)"/>
+ <alias from="edit" to="@@edit"/>
+ <alias from="sharing" to="@@sharing"/>
+ <alias from="view" to="(selected layout)"/>
+ <action title="View" action_id="view" category="object" condition_expr=""
+ description="" icon_expr="" link_target="" url_expr="string:${object_url}"
+ visible="True">
+ <permission value="View"/>
+ </action>
+ <action title="Edit" action_id="edit" category="object" condition_expr=""
+ description="" icon_expr="" link_target=""
+ url_expr="string:${object_url}/edit" visible="True">
+ <permission value="Modify portal content"/>
+ </action>
+</object>