[gen] Added px.override allowing to modify PX code; bugfixes; added migration code for converting File instances to FileInfo instances.

This commit is contained in:
Gaetan Delannay 2014-02-26 23:40:27 +01:00
parent be145be254
commit c002b5cb59
8 changed files with 71 additions and 21 deletions

View file

@ -181,7 +181,7 @@ class File(Field):
pxView = pxCell = Px('''
<x var="downloadUrl='%s/download?name=%s' % (zobj.absolute_url(), name);
shownSize=value.getShownSize()">
shownSize=value and value.getShownSize() or 0">
<x if="value and not field.isImage">
<a href=":downloadUrl">:value.uploadName</a>&nbsp;&nbsp;-
<i class="discreet">:shownSize</i>
@ -319,7 +319,11 @@ class File(Field):
dbFolder, folder = zobj.getFsFolder(create=True)
# Remove the previous file if it existed.
info = getattr(obj.aq_base, self.name, None)
if info: info.removeFile(dbFolder)
if info:
# The previous file can be a legacy File object in an old
# database we are migrating.
if isinstance(info, FileInfo): info.removeFile(dbFolder)
else: delattr(obj, self.name)
# Store the new file. As a preamble, create a FileInfo instance.
info = FileInfo(folder)
cfg = zobj.getProductConfig()

View file

@ -306,7 +306,7 @@ class UiGroup:
<!-- Group content -->
<div var="display=expanded and 'display:block' or 'display:none'"
id=":field.labelId" style=":'padding-left: 10px; %s' % display">
<x for="searches in field.widgets">
<x for="searches in field.elements">
<x for="elem in searches">
<!-- An inner group within this group -->
<x if="elem.type == 'group'"

View file

@ -40,6 +40,11 @@ from appy.fields.workflow import *
from appy.gen.layout import Table
from appy.gen.utils import No
# Make the following classes available here: people may need to monkey-patch
# some PXs on thoses classes.
from appy.gen.wrappers import AbstractWrapper as BaseObject
from appy.gen.wrappers.ToolWrapper import ToolWrapper as BaseTool
class Import:
'''Used for describing the place where to find the data to use for creating
an object.'''

View file

@ -1,5 +1,6 @@
# ------------------------------------------------------------------------------
import time
from appy.fields.file import FileInfo
# ------------------------------------------------------------------------------
class Migrator:
@ -11,13 +12,36 @@ class Migrator:
self.app = installer.app
self.tool = self.app.config.appy()
@staticmethod
def migrateFileFields(obj):
'''Ensures all file fields on p_obj are FileInfo instances.'''
migrated = 0 # Count the number of migrated fields
for field in obj.fields:
if field.type != 'File': continue
oldValue = getattr(obj, field.name)
if oldValue and not isinstance(oldValue, FileInfo):
# A legacy File object. Convert it to a FileInfo instance and
# extract the binary to the filesystem.
setattr(obj, field.name, oldValue)
migrated += 1
return migrated
def migrateTo_0_9_0(self):
'''Migrates this DB to Appy 0.9.x.'''
pass
# Put all binaries to the filesystem
tool = self.tool
tool.log('Migrating file fields...')
context = {'migrate': self.migrateFileFields, 'nb': 0}
for className in tool.o.getAllClassNames():
tool.compute(className, context=context, noSecurity=True,
expression="ctx['nb'] += ctx['migrate'](obj)")
tool.log('Migrated %d File field(s).' % context['nb'])
def run(self):
def run(self, force=False):
'''Executes a migration when relevant, or do it for sure if p_force is
True.'''
appyVersion = self.tool.appyVersion
if not appyVersion or (appyVersion < '0.9.0'):
if force or not appyVersion or (appyVersion < '0.9.0'):
# Migration is required.
startTime = time.time()
self.migrateTo_0_9_0()

View file

@ -470,6 +470,11 @@ class ToolMixin(BaseMixin):
if wrapper: return zopeClass.wrapperClass
else: return zopeClass.wrapperClass.__bases__[-1]
def getAllClassNames(self):
'''Returns the name of all classes within this app, including default
Appy classes (Tool, Translation, Page, etc).'''
return self.getProductConfig().allClassNames + [self.__class__.__name__]
def getCreateMeans(self, klass):
'''Gets the different ways objects of p_klass can be created (via a web
form, by importing external data, etc). Result is a dict whose keys

View file

@ -1,11 +1,10 @@
# ------------------------------------------------------------------------------
import os.path, time
import appy
from appy.gen.mail import sendMail
from appy.shared.utils import executeCommand
from appy.gen.wrappers import AbstractWrapper
from appy.px import Px
from appy.gen.mail import sendMail
from appy.gen.wrappers import AbstractWrapper
from appy.shared.utils import executeCommand
# ------------------------------------------------------------------------------
class ToolWrapper(AbstractWrapper):
@ -233,7 +232,7 @@ class ToolWrapper(AbstractWrapper):
</x>
<!-- Predefined searches -->
<x for="search in searchInfo.searches">
<x for="search in searchInfo.searches" var2="field=search">
<x if="search.type == 'group'">:search.px</x>
<x if="search.type != 'group'">:search.pxView</x>
</x>

View file

@ -123,7 +123,7 @@ class UserWrapper(AbstractWrapper):
# Browse all objects of the database and update potential local roles
# that referred to the old login.
context = {'nb': 0, 'old': oldLogin, 'new': newLogin}
for className in self.o.getProductConfig().allClassNames:
for className in self.tool.o.getAllClassNames():
self.compute(className, context=context, noSecurity=True,
expression="ctx['nb'] += obj.o.applyUserIdChange(" \
"ctx['old'], ctx['new'])")

View file

@ -42,10 +42,22 @@ class Px:
else:
self.content = content
# It this content a complete XML file, or just some part of it?
if partial:
self.partial = partial
# Is this PX based on a template PX?
self.template = template
self.hook = hook
# Is there some (XML, XHTML...) prologue to dump?
self.prologue = prologue
# Will the result be unicode or str?
self.unicode = unicode
self.parse()
def parse(self):
'''Parses self.content and create the structure corresponding to this
PX.'''
if self.partial:
# Surround the partial chunk with a root tag: it must be valid XML.
self.content = '<x>%s</x>' % self.content
self.partial = partial
# Create a PX parser
self.parser = PxParser(PxEnvironment(), self)
# Parses self.content (a PX code in a string) with self.parser, to
@ -55,13 +67,6 @@ class Px:
except xml.sax.SAXParseException, spe:
self.completeErrorMessage(spe)
raise spe
# Is this PX based on a template PX?
self.template = template
self.hook = hook
# Is there some (XML, XHTML...) prologue to dump?
self.prologue = prologue
# Will the result be unicode or str?
self.unicode = unicode
def completeErrorMessage(self, parsingError):
'''A p_parsingError occurred. Complete the error message with the
@ -108,4 +113,12 @@ class Px:
if not self.unicode:
res = res.encode('utf-8')
return res
def override(self, content, partial=True):
'''Overrides the content of this PX with a new p_content (as a
string).'''
self.partial = partial
self.content = content
# Parse again, with new content.
self.parse()
# ------------------------------------------------------------------------------