# Copyright (c) 2002-2010 Infrae. All rights reserved.
# See also LICENSE.txt
# $Id: CSVSource.py 40258 2010-03-02 12:08:43Z sylvain $
from Products.SilvaExternalSources.interfaces import IExternalSource
from Products.SilvaExternalSources.ExternalSource import ExternalSource
from Products.SilvaExternalSources import ASV
from zope.interface import implements
# Zope
from AccessControl import ClassSecurityInfo
from App.Common import package_home
from App.class_init import InitializeClass
from OFS.Folder import Folder
from Products.Formulator.Form import ZMIForm
from Products.Formulator.XMLToForm import XMLToForm
from Products.PageTemplates.PageTemplateFile import PageTemplateFile
from Products.PageTemplates.ZopePageTemplate import ZopePageTemplate
# Silva
from Products.Silva import SilvaPermissions
from Products.Silva.helpers import add_and_edit
from Products.Silva.Asset import Asset
from silva.core import conf
from silva.core.interfaces import IAsset
from silva.translations import translate
class CSVSource(ExternalSource, Asset, Folder):
"""CSV Source is an asset that displays tabular data from a
spreadsheet or database. The format of the uploaded text file
should be ‘comma separated values’. The asset can
be linked directly, or inserted in a document with the External
Source element. If necessary, all aspects of the display can be
customized in the rendering templates of the CSV Source.
"""
implements(IExternalSource, IAsset)
meta_type = "Silva CSV Source"
management_page_charset = 'utf-8'
security = ClassSecurityInfo()
# ZMI Tabs
manage_options = (
{'label':'Edit', 'action':'editCSVSource'},
{'label':'Edit Data', 'action':'editDataCSVSource'},
) + Folder.manage_options
security.declareProtected(
SilvaPermissions.ViewManagementScreens, 'editCSVSource')
editCSVSource = PageTemplateFile(
'www/csvSourceEdit', globals(), __name__='editCSVSource')
security.declareProtected(
SilvaPermissions.ViewManagementScreens, 'editDataCSVSource')
editDataCSVSource = PageTemplateFile(
'www/csvSourceEditData', globals(), __name__='editCSVSourceData')
_layout_id = 'layout'
_default_batch_size = 20
# register priority, icon and factory
silvaconf.priority(1)
silvaconf.icon('www/csvsource.png')
silvaconf.factory('manage_addCSVSource')
def __init__(self, id):
CSVSource.inheritedAttribute('__init__')(self, id)
self._raw_data = None
self._data = []
# ACCESSORS
security.declareProtected(
SilvaPermissions.AccessContentsInformation, 'get_file_size')
def get_file_size(self):
"""Get the size of the file as it will be downloaded.
"""
if self._raw_data:
return len(self._raw_data)
return 0
security.declareProtected(
SilvaPermissions.AccessContentsInformation, 'raw_data')
def raw_data (self):
if type(self._raw_data) != type(u''):
data = unicode(self._raw_data, self._data_encoding, 'replace')
else:
data = self._raw_data
return data
security.declareProtected(
SilvaPermissions.AccessContentsInformation, 'to_html')
def to_html(self, *args, **kw):
""" render HTML for CSV source
"""
layout = self[self._layout_id]
rows = self._data[:]
param = {}
param.update(kw)
if not param.get('csvtableclass'):
param['csvtableclass'] = 'default'
if param.get('csvbatchsize'):
bs = int(param.get('csvbatchsize'))
param['csvbatchsize'] = bs
else:
param['csvbatchsize'] = CSVSource._default_batch_size
if rows:
headings = rows[0]
rows = rows[1:]
param['headings'] = headings
return layout(table=rows, parameters=param)
security.declareProtected(
SilvaPermissions.AccessContentsInformation, 'get_title')
def get_title (self):
"""Return meta-data title for this instance
"""
ms = self.service_metadata
return ms.getMetadataValue(self, 'silva-content', 'maintitle')
security.declareProtected(
SilvaPermissions.ViewManagementScreens, 'get_table_class')
def get_table_class (self):
"""Returns css class for table """
return self._table_class
security.declareProtected(
SilvaPermissions.AccessContentsInformation, 'description')
def description (self):
""" Return desc from meta-data system"""
ms = self.service_metadata
return ms.getMetadataValue(self, 'silva-extra', 'content_description')
# MODIFIERS
security.declareProtected(
SilvaPermissions.ChangeSilvaContent, 'update_data')
def update_data (self, data):
asv = ASV.ASV()
asv.input(data, ASV.CSV(), has_field_names=0)
# extracting the raw data out of the asv structure
# thereby converting them into plain list-of-lists
# containing strings
rows = []
for r in asv:
l = []
for c in r:
l.append(c)
rows.append(l)
# convert the data to unicode
rows = self._unicode_helper(rows)
self._data = rows
self._raw_data = data
self.update_quota()
def _unicode_helper(self, rows):
for r in rows:
for i in xrange(len(r)):
value = r[i]
if type(value) is type(''):
r[i] = unicode(value, self._data_encoding, 'replace')
return rows
security.declareProtected(
SilvaPermissions.ChangeSilvaContent, 'set_data_encoding')
def set_data_encoding (self, encoding):
self._data_encoding = encoding
self.update_data(self._raw_data)
return
## security.declareProtected(ViewManagementScreens, 'set_headings')
## def set_headings (self, headings):
## self._has_headings = (not not headings)
## return
security.declareProtected(
SilvaPermissions.ChangeSilvaContent, 'set_table_class')
def set_table_class (self, css_class):
self._table_class = css_class
return
security.declareProtected(
SilvaPermissions.ChangeSilvaContent, 'set_description')
def set_description(self, desc):
t = type(desc)
if t == type(u''):
desc = desc.encode('utf-8')
# Since the metadata system will re-validate, it cannot
# accept unicode... ugh... so, re-encode to utf-8 first.
ms = self.service_metadata
binding = ms.getMetadata(self)
d = {'content_description' : desc}
binding.setValues('silva-extra', d)
pass
# MANAGERS
security.declareProtected(
SilvaPermissions.ViewManagementScreens, 'manage_editCSVSource')
def manage_editCSVSource(
self, title, character_set, description=None, cacheable=None,
headings=None, file=None, previewable=None):
""" Edit CSVSource object
"""
msg = u''
charset = character_set
# first check if encoding is known
# if not, don't change it and display error message
try:
unicode('abcd', charset, 'replace')
except LookupError:
# unknown encoding, return error message
m = _(
"Unknown encoding ${enc}, not changed! ",
mapping={"enc":charset})
msg += m #"Unknown encoding %s, not changed!. " % charset
return self.editCSVSource(manage_tabs_message=msg)
self.set_data_encoding(charset)
m = _(
"Data encoding changed to: ${enc}. ",
mapping={"enc":charset})
msg += m #'Data encoding changed to: %s. ' % charset
# Assume title is in the encoding as specified
# by "management_page_charset". Store it in unicode.
title = unicode(
title, self.management_page_charset)
if title and title != self.get_title():
self.set_title(title)
msg += _("Title changed. ")
# Assume description is in the encoding as specified
# by "management_page_charset". Store it in unicode.
description = unicode(
description, self.management_page_charset, 'replace')
if description and description != self._description:
self.set_description(description)
m = _("Description changed. ")
msg += m #'Description changed. '
if not (not not cacheable) is (not not self._is_cacheable):
self.set_is_cacheable(cacheable)
m = _("Cacheability setting changed. ")
msg += m #'Cacheability setting changed. '
if not (not not previewable) is (not not self.is_previewable()):
self.set_is_previewable(previewable)
m = _("Previewable setting changed. ")
msg += m #'Previewable setting changed. '
if file:
self.update_data(data.read())
m = _("Data updated. ")
msg += m #'Data updated. '
## if not (not not headings) is (not not self._has_headings):
## self._has_headings = (not not headings)
## msg += 'Has headings setting changed. '
return self.editCSVSource(manage_tabs_message=msg)
security.declareProtected(
SilvaPermissions.ViewManagementScreens, 'manage_editDataCSVSource')
def manage_editDataCSVSource(self, data=None):
""" Edit CSVSource raw data
"""
msg = u''
if data:
self.update_data(data)
msg = _('Raw data updated. ')
return self.editDataCSVSource(manage_tabs_message=msg)
InitializeClass(CSVSource)
import os
def reset_parameter_form(csvsource):
filename = os.path.join(package_home(globals()),
'layout',
'csvparameters.xml')
f = open(filename, 'rb')
form = ZMIForm('form', 'Parameters form', unicode_mode=1)
XMLToForm(f.read(), form)
f.close()
csvsource.set_form(form)
def reset_table_layout(cs):
# Works for Zope object implementing a 'write()" method...
layout = [
('layout', ZopePageTemplate, 'csvtable.zpt'),
('macro', ZopePageTemplate, 'macro.zpt'),
]
for id, klass, file in layout:
filename = os.path.join(package_home(globals()), 'layout', file)
f = open(filename, 'rb')
if not id in cs.objectIds():
cs._setObject(id, klass(id))
cs[id].write(f.read())
f.close()
def manage_addCSVSource(context, id, title, file=None, REQUEST=None):
"""Add a CSVSource object
"""
cs = CSVSource(id)
context._setObject(id, cs)
cs = context._getOb(id)
if file:
cs.update_data(file.read())
else:
cs.update_data("") # XXX: This is necessary ??
reset_table_layout(cs)
reset_parameter_form(cs)
cs.set_title(title)
cs.set_description('CSV Source description')
add_and_edit(context, id, REQUEST, screen='editCSVSource')
return ''
|