예제 #1
0
 def getVisibleTemplates(self, obj):
     '''Returns, among self.template, the template(s) that can be shown'''
     res = []
     if not self.showTemplate:
         # Show them all in the formats specified in self.formats
         for template in self.template:
             res.append(
                 Object(template=template,
                        formats=self.formats,
                        freezeFormats=self.getFreezeFormats(obj, template)))
     else:
         for template in self.template:
             formats = self.showTemplate(obj, template)
             if not formats: continue
             elif isinstance(formats, bool): formats = self.formats
             elif isinstance(formats, basestring): formats = (formats, )
             res.append(
                 Object(template=template,
                        formats=formats,
                        freezeFormats=self.getFreezeFormats(obj, template)))
     # Compute the already frozen documents, and update the available formats
     # accordingly when self.showFrozenOnly is True.
     for info in res:
         frozenFormats = []
         for fmt in info.formats:
             if self.isFrozen(obj, info.template, fmt):
                 frozenFormats.append(fmt)
         info.frozenFormats = frozenFormats
         # Replace formats with frozenFormats when relevant
         if frozenFormats and self.showFrozenOnly:
             info.formats = frozenFormats
     return res
예제 #2
0
 def getRequestValue(self, obj, requestName=None):
     '''Concatenates the list from distinct form elements in the request'''
     request = obj.REQUEST
     name = requestName or self.name  # A List may be into another List (?)
     prefix = name + '*-row-*'  # Allows to detect a row of data for this List
     res = {}
     isDict = True  # We manage both List and Dict
     for key in request.keys():
         if not key.startswith(prefix): continue
         # I have found a row: get its index
         row = Object()
         rowId = key.split('*')[-1]
         if rowId == '-1': continue  # Ignore the template row
         for subName, subField in self.fields:
             keyName = '%s*%s*%s' % (name, subName, rowId)
             if keyName + subField.getRequestSuffix() in request:
                 v = subField.getRequestValue(obj, requestName=keyName)
                 setattr(row, subName, v)
         if rowId.isdigit():
             rowId = int(rowId)
             isDict = False
         res[rowId] = row
     # Produce a sorted list (List only)
     if not isDict:
         keys = res.keys()
         keys.sort()
         res = [res[key] for key in keys]
     # I store in the request this computed value. This way, when individual
     # subFields will need to get their value, they will take it from here,
     # instead of taking it from the specific request key. Indeed, specific
     # request keys contain row indexes that may be wrong after row deletions
     # by the user.
     if res: request.set(name, res)
     return res
예제 #3
0
 def __init__(self, config, mode):
     # "config" is the main Appy config
     self.config = config
     # "mode" can be "fg" (foreground, debug mode) or "bg" (background)
     self.mode = mode
     # Initialise the loggers
     cfg = config.log
     self.loggers = Object(site=cfg.getLogger('site'),
                           app=cfg.getLogger('app', mode == 'fg'))
     try:
         # Load the application model
         self.model = config.model.get()
         # Initialise the HTTP server
         cfg = config.server
         HTTPServer.__init__(self, (cfg.address, cfg.port), Handler)
         # Initialise the database
         self.db = config.db.getDatabase(self.loggers.app)
     except Model.Error as err:
         self.loggers.app.error(err)
         logging.shutdown()
         sys.exit(1)
     except Exception as e:
         self.logTraceback()
         logging.shutdown()
         sys.exit(1)
     # The current user login
     self.user = '******'
     # The server is ready
     self.loggers.app.info(self.READY % (cfg.address, cfg.port, os.getpid()))
예제 #4
0
 def getCustomContext(self, obj, rq):
     '''Before calling pod to compute a result, if specific elements must be
        added to the context, compute it here. This request-dependent method
        is not called when computing a pod field for freezing it into the
        database.'''
     res = {}
     # Get potential custom params from the request. Custom params must be
     # coded as a string containing a valid Python dict.
     customParams = rq.get('customParams')
     if customParams:
         paramsDict = eval(customParams)
         res.update(paramsDict)
     # Compute the selected linked objects if self.getChecked is specified
     # and if the user can read this Ref field.
     if self.getChecked and \
        obj.allows(obj.getField(self.getChecked).readPermission):
         # Get the UIDs specified in the request
         reqUids = rq['checkedUids'] and rq['checkedUids'].split(',') or []
         unchecked = rq['checkedSem'] == 'unchecked'
         objects = []
         tool = obj.tool
         for uid in getattr(obj.o.aq_base, self.getChecked, ()):
             if unchecked: condition = uid not in reqUids
             else: condition = uid in reqUids
             if condition:
                 tied = tool.getObject(uid)
                 if tied.allows('read'): objects.append(tied)
         res['_checked'] = Object()
         setattr(res['_checked'], self.getChecked, objects)
     return res
예제 #5
0
 def getInfo(self, obj, layoutType):
     '''Gets information about this page, for p_obj, as an object.'''
     res = Object()
     for elem in Page.subElements:
         showable = self.isShowable(obj, layoutType, elem)
         setattr(res, 'show%s' % elem.capitalize(), showable)
     return res
예제 #6
0
 def addPageLinks(self, field, obj):
     '''If p_field is a navigable Ref, we must add, within self.pagesInfo,
        objects linked to p_obj through this Ref as links.'''
     if field.page.name in self.hiddenPages: return
     infos = []
     for ztied in field.getValue(obj, appy=False):
         infos.append(Object(title=ztied.title, url=ztied.absolute_url()))
     self.pagesInfo[field.page.name].links = infos
예제 #7
0
 def convertDict(klass, d):
     '''Returns a appy.Object instance representing dict p_d'''
     res = Object()
     for name, value in d.items():
         # Ensure "name" will be a valid attribute name for a Python object
         n = string.normalize(name, 'alphanum_')
         setattr(res, n, klass.convertValue(value))
     return res
예제 #8
0
 def encode(self):
     # Do nothing if we have a SOAP message already
     if isinstance(self.data, basestring): return self.data
     # self.data is here a Python object. Wrap it in a SOAP Body.
     soap = Object(Body=self.data)
     # Marshall it
     marshaller = XmlMarshaller(rootTag='Envelope',
                                namespaces=self.ns,
                                namespacedTags=self.namespacedTags)
     return marshaller.marshall(soap)
예제 #9
0
 def initialiseLoop(self, context, elems):
     '''Initialises information about the loop, before entering into it. It
        is possible that this loop overrides an outer loop whose iterator
        has the same name. This method returns a tuple
        (loop, outerOverriddenLoop).'''
     # The "loop" object, made available in the POD context, contains info
     # about all currently walked loops. For every walked loop, a specific
     # object, le'ts name it curLoop, accessible at
     # getattr(loop, self.iters[0]), stores info about its status:
     #   * curLoop.length  gives the total number of walked elements within
     #                     the loop
     #   * curLoop.nb      gives the index (starting at 0) if the currently
     #                     walked element.
     #   * curLoop.first   is True if the currently walked element is the
     #                     first one.
     #   * curLoop.last    is True if the currently walked element is the
     #                     last one.
     #   * curLoop.odd     is True if the currently walked element is odd
     #   * curLoop.even    is True if the currently walked element is even
     # For example, if you have a "for" statement like this:
     #        for elem in myListOfElements
     # Within the part of the ODT document impacted by this statement, you
     # may access to:
     #   * loop.elem.length to know the total length of myListOfElements
     #   * loop.elem.nb     to know the index of the current elem within
     #                      myListOfElements.
     if 'loop' not in context:
         context['loop'] = Object()
     try:
         total = len(elems)
     except Exception:
         total = 0
     curLoop = Object(length=total)
     # Does this loop override an outer loop with homonym iterator ?
     outerLoop = None
     iter = self.iters[0]
     if hasattr(context['loop'], iter):
         outerLoop = getattr(context['loop'], iter)
     # Put this loop in the global object "loop"
     setattr(context['loop'], iter, curLoop)
     return curLoop, outerLoop
예제 #10
0
 def addPage(self, field, obj, layoutType):
     '''Adds page-related information in the phase.'''
     # If the page is already there, we have nothing more to do.
     if (field.page.name in self.pages) or \
        (field.page.name in self.hiddenPages):
         return
     # Add the page only if it must be shown.
     showOnView = field.page.isShowable(obj, 'view')
     showOnEdit = field.page.isShowable(obj, 'edit')
     if showOnView or showOnEdit:
         # The page must be added
         self.pages.append(field.page.name)
         # Create the dict about page information and add it in self.pageInfo
         pageInfo = Object(page=field.page,
                           showOnView=showOnView,
                           showOnEdit=showOnEdit,
                           links=None)
         pageInfo.update(field.page.getInfo(obj, layoutType))
         self.pagesInfo[field.page.name] = pageInfo
     else:
         self.hiddenPages.append(field.page.name)
예제 #11
0
class Collapsible:
    '''Represents a chunk of HTML code that can be collapsed/expanded via
       clickable icons.'''
    # Various sets of icons can be used. Each one has a CSS class in appy.css
    iconSets = {
        'expandCollapse': Object(expand='expand', collapse='collapse'),
        'showHide': Object(expand='show', collapse='hide'),
        'showHideInv': Object(expand='hide', collapse='show')
    }

    # Icon allowing to collapse/expand a chunk of HTML
    px = Px('''
     <img var="coll=collapse; icons=coll.icons"
          id=":'%s_img' % coll.id" align=":coll.align" class=":coll.css"
          onclick=":'toggleCookie(%s,%s,%s,%s,%s)' % (q(coll.id), \
                    q(coll.display), q(coll.default), \
                    q(icons.expand), q(icons.collapse))"
       src=":coll.expanded and url(icons.collapse) or url(icons.expand)"/>''')

    def __init__(self,
                 id,
                 request,
                 default='collapsed',
                 display='block',
                 icons='expandCollapse',
                 align='left'):
        '''p_display is the value of style attribute "display" for the XHTML
           element when it must be displayed. By default it is "block"; for a
           table it must be "table", etc.'''
        self.id = id  # The ID of the collapsible HTML element
        self.request = request  # The request object
        self.default = default
        self.display = display
        self.align = align
        # Must the element be collapsed or expanded ?
        self.expanded = request.get(id, default) == 'expanded'
        self.style = 'display:%s' % (self.expanded and self.display or 'none')
        # The name of the CSS class depends on the set of applied icons
        self.css = icons
        self.icons = self.iconSets[icons]
예제 #12
0
 def createTotals(self, isEdit):
     '''When rendering the List field, if total rows are defined, create a
        Total instance for every sub-field for which a total must be
        computed.'''
     if isEdit or not self.totalRows: return
     res = {}  # Keyed by Totals.name
     for totals in self.totalRows:
         subTotals = Object()
         for name in totals.subFields:
             totalObj = Total(name, self.getField(name), totals.initValue)
             setattr(subTotals, name, totalObj)
         res[totals.id] = subTotals
     return res
예제 #13
0
 def getStorableRowValue(self, obj, requestValue):
     '''Gets a ready-to-store Object instance representing a single row,
        from p_requestValue.'''
     res = Object()
     for name, field in self.fields:
         if not hasattr(requestValue, name): continue
         subValue = getattr(requestValue, name)
         try:
             setattr(res, name, field.getStorableValue(obj, subValue))
         except ValueError:
             # The value for this field for this specific row is incorrect.
             # It can happen in the process of validating the whole List
             # field (a call to m_getStorableValue occurs at this time). We
             # don't care about it, because later on we will have sub-field
             # specific validation that will also detect the error and will
             # prevent storing the wrong value in the database.
             setattr(res, name, subValue)
     return res
예제 #14
0
 def process(self, obj):
     '''Processes a response from Ogone.'''
     # Call the response method defined in this Ogone field.
     if not self.ogoneResponseOk(obj):
         obj.log('Ogone response SHA failed. REQUEST: %s' % \
                 str(obj.REQUEST.form))
         raise Exception('Failure, possible fraud detection, an ' \
                         'administrator has been contacted.')
     # Create a nice object from the form.
     response = Object()
     for k, v in obj.REQUEST.form.items():
         setattr(response, k, v)
     # Call the field method that handles the response received from Ogone.
     url = self.responseMethod(obj.appy(), response)
     # Redirect the user to the correct page. If the field method returns
     # some URL, use it. Else, use the view page of p_obj.
     if not url: url = obj.absolute_url()
     obj.goto(url)
예제 #15
0
 def getValue(self,
              obj,
              name=None,
              template=None,
              format=None,
              result=None,
              queryData=None,
              customContext=None,
              noSecurity=False,
              executeAction=True):
     '''For a pod field, getting its value means computing a pod document or
        returning a frozen one. A pod field differs from other field types
        because there can be several ways to produce the field value (ie:
        self.template can hold various templates; output file format can be
        odt, pdf,.... We get those precisions about the way to produce the
        file, either from params, or from default values.
        * p_template is the specific template, among self.template, that must
          be used as base for generating the document;
        * p_format is the output format of the resulting document;
        * p_result, if given, must be the absolute path of the document that
          will be computed by pod. If not given, pod will produce a doc in
          the OS temp folder;
        * if the pod document is related to a query, the query parameters
          needed to re-trigger the query are given in p_queryData;
        * dict p_customContext may be specified and will override any other
          value available in the context, including values from the
          field-specific context.
     '''
     obj = obj.appy()
     template = template or self.template[0]
     format = format or 'odt'
     # Security check
     if not noSecurity and not queryData:
         if self.showTemplate and not self.showTemplate(obj, template):
             raise Exception(UNAUTHORIZED)
     # Return the possibly frozen document (not applicable for query-related
     # pods).
     if not queryData:
         frozen = self.isFrozen(obj, template, format)
         if frozen:
             fileName = self.getDownloadName(obj, template, format, False)
             return FileInfo(frozen, inDb=False, uploadName=fileName)
     # We must call pod to compute a pod document from "template"
     tool = obj.tool
     ztool = tool.o
     diskFolder = tool.getDiskFolder()
     # Get the path to the pod template
     templatePath = self.getTemplatePath(diskFolder, template)
     # Get or compute the specific POD context
     specificContext = None
     if callable(self.context):
         specificContext = self.callMethod(obj, self.context)
     else:
         specificContext = self.context
     # Compute the name of the result file
     if not result:
         result = '%s/%s_%f.%s' % (getOsTempFolder(), obj.id, time.time(),
                                   format)
     # Define parameters to give to the appy.pod renderer
     podContext = {
         'tool': tool,
         'user': obj.user,
         'self': obj,
         'field': self,
         'now': ztool.getProductConfig().DateTime(),
         '_': obj.translate,
         'projectFolder': diskFolder,
         'template': template,
         'request': tool.request
     }
     # If the pod document is related to a query, re-trigger it and put the
     # result in the pod context.
     if queryData:
         # Retrieve query params
         cmd = ', '.join(Pod.queryParams)
         cmd += " = queryData.split(';')"
         exec(cmd)
         # (re-)execute the query, but without any limit on the number of
         # results; return Appy objects.
         objs = ztool.executeQuery(obj.o.portal_type,
                                   searchName=search,
                                   sortBy=sortKey,
                                   sortOrder=sortOrder,
                                   filters=sutils.getDictFrom(filters),
                                   maxResults='NO_LIMIT')
         podContext['objects'] = [o.appy() for o in objs.objects]
         podContext['queryData'] = queryData.split(';')
     # Add the field-specific and custom contexts if present
     if specificContext: podContext.update(specificContext)
     if customContext: podContext.update(customContext)
     # Variable "_checked" can be expected by a template but absent (ie,
     # when generating frozen documents).
     if '_checked' not in podContext: podContext['_checked'] = Object()
     # Define a potential global styles mapping
     if callable(self.stylesMapping):
         stylesMapping = self.callMethod(obj, self.stylesMapping)
     else:
         stylesMapping = self.stylesMapping
     # Execute the "before" action when relevant
     if executeAction and self.beforeAction:
         self.beforeAction(obj, template, podContext, format)
     # Get the optional script to give to the renderer
     script = self.script
     if callable(script): script = script(obj, template, podContext)
     rendererParams = {
         'template': templatePath,
         'context': podContext,
         'result': result,
         'stylesMapping': stylesMapping,
         'imageResolver': ztool.getApp(),
         'overwriteExisting': True,
         'forceOoCall': self.forceOoCall,
         'raiseOnError': self.raiseOnError,
         'script': script
     }
     cfg = ztool.getProductConfig(True)
     if cfg.unoEnabledPython:
         rendererParams['pythonWithUnoPath'] = cfg.unoEnabledPython
     if cfg.libreOfficePort:
         rendererParams['ooPort'] = cfg.libreOfficePort
     # Launch the renderer
     try:
         renderer = Renderer(**rendererParams)
         renderer.run()
     except PodError as pe:
         if not os.path.exists(result):
             # In some (most?) cases, when OO returns an error, the result is
             # nevertheless generated.
             obj.log(str(pe).strip(), type='error')
             return POD_ERROR
     # Give a friendly name for this file
     fileName = self.getDownloadName(obj, template, format, queryData)
     # Execute the tied action when relevant
     if executeAction and self.action:
         self.action(obj, template, podContext, format)
     # Get a FileInfo instance to manipulate the file on the filesystem
     return FileInfo(result, inDb=False, uploadName=fileName)