Direkt zum Inhalt | Direkt zur Navigation

Benutzerspezifische Werkzeuge

Sie sind hier: Startseite / Tech-Blog

Tech-Blog

Technische Artikel zu Themen: Zope, Plone, Python, Pyramid, Django, Exim, Dovecot, Nagios, Shinken, Bacula und weiteren Open Source Themen...

Bibliotheken zur Konvertierung und Volltextindizierung von Dokumenten

Plone kann out of the box PDF-Dateien, Openoffice/Libreoffice und MSOffice Dokumente wie Dokumente und Tabellen sowie auch Impress und Powerpoint Presentationen konvertieren und für die Volltextsuche indizieren. Hierfür müssen auf dem Server ein paar Bibliotheken installiert werden.

Unter Debian Linux sind folgende Bibliotheken zu installieren

  • poppler-utils
  • libxslt1-dev
  • libxml2-dev
  • wv
  • xsltproc
  • unzip

Plone: den Owner (Besitzer) eines Objektes in Python ändern

Man kann den Owner in Plone auch per Python ändern, was z.B. nützlich ist, wenn man viele Objekte manipulieren möchte oder dies in einem event handler tun möchte.

Den Owner eines Objektes ändern

portal.plone_utils.changeOwnershipOf(obj, user_id)
print "change owner of %s to %s" % (obj.id, user_id)

AngularJS: In einem controller einer directive mit isolated scope auf Methoden im parent scope zugreifen

Man kann den scope einer directive vom Rest isolieren, was viele Vorteile hat, wenn man diese wiederverndbar machen möchte. Aber manchmal möchte man aus dieser directive oder dessen controller auf Methoden oder Variablen der parents zugreifen.

Um in einer directive auf Methoden und Variablen zuzugreifen, kann man für diese ein Mapping erstellen: http://www.undefinednull.com/2014/02/11/mastering-the-scope-of-a-directive-in-angularjs/

Will man aber in einem der directive zugewiesenen controller auf Methoden im parent scope zugreifen, kann man dies wie folgt machen.

Im controller der directive mappen wir unsere parent-Methode wie folgt:

$scope.toggleSomeThing =
   $scope.$parent.toggleSomeThing;

Nun können wir im Template der directive darauf zugreifen:

<button ng-click="toggleSomeThing(element)"></button

Quick Dexterity 2-Column-Edit-Form with Diazo

With Diazo Theming you have the power to do nice things like, converting one-column edit form into two-column edit form.

In the following we will separate the odd from the even fields into two div container.

Diazo rules and inline-XSLT to separate even from odd fields

In the main rules.xml file, we define a conditional include of our content type rules file my-contenttype.xml:

<rules css:if-content=".template-edit.portaltype-my-contenttype">
  <xi:include href="my-contenttype.xml" />
</rules>

Then we define our rules to do the real work:

<?xml version="1.0" encoding="UTF-8"?>
<rules xmlns="http://namespaces.plone.org/diazo"
    xmlns:css="http://namespaces.plone.org/diazo/css"
    xmlns:xi="http://www.w3.org/2001/XInclude"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <replace css:content="#content-core fieldset">
    <xsl:for-each select=".">
    <fieldset>
      <xsl:copy-of select="@*" />
      <xsl:copy-of css:select="> legend" />

      <div class="left-content-column">
      <xsl:for-each css:select="> div.field:nth-child(even)">
        <xsl:copy-of select="." />
      </xsl:for-each>
      </div>

      <div class="right-content-column">
      <xsl:for-each css:select="> div.field:nth-child(odd)">
        <xsl:copy-of select="." />
      </xsl:for-each>
      </div>

  </fieldset>
  </xsl:for-each>
</replace>
</rules>

CSS to show the two div container in two columns

body.template-edit.portaltype-my-contenttype{
  .left-content-column{
    width: 50%;
    float:left;
    .field{
      padding: 0.5em;
      &:nth-child(even){
        background: lightgray;
      }
    }
  }
  .right-content-column{
    width: 50%;
    float:left;
    .field{
      padding: 0.5em;
      &:nth-child(even){
        background: lightgray;
      }
    }
  }
}

New Markup Editor for Plone

With collective.markitup, we got a nice markup editor for Plone, which we can use if we want edit contents in reStructured Text or Markdown format, instead of HTML. collective.markitup brings us a seamless integration of MarkItUp Javascript Editor.

If we edit HTML we get a fallback to TinyMCE editor. So we can just set MarkItUp as default editor and edit everythink we want with the proper editor.

MarkItUp Editor with reStructured Text and preview on bottom

MarkItUp Editor with reStructured Text and preview on bottom

By now Markdown and ReStructuredText works fine. And it has nice integration Plone to put in images and links like in TinyMCE.

collective.markitup does not provide any additional markup languages. It is just a editor you can use to edit Markdown, ReStructuredText or possibly any other markup you can choose in Plone's Markup settings control panel. By now Markdown (text/x-web-markdown) and ReStructuredText (text/restructured) works fine. And it has nice integration Plone to put in images and links like in TinyMCE.

MarkItUp Editor with finder integration, to choose images from Plone.

MarkItUp Editor with finder integration, to choose images from Plone.

The new release of collective.markitup is out now: https://pypi.python.org/pypi/collective.markitup

Manage nodejs, grunt and bower with buildout

How you can manage nodejs, grunt and bower including npm and bower dependencies with zc.buildout.

Buildout config

We can use gp.recipe.node recipe, for details see: https://pypi.python.org/pypi/gp.recipe.node

[buildout]
parts +=
    nodejs
    bower
    node_modules

[nodejs]
recipe = gp.recipe.node
version = 0.10.22
npms = grunt-cli bower less jshint csslint blueimp-tmpl uglify-js
scripts = grunt bower lessc jshint csslint tmpl.js uglifyjs

[bower]
recipe = collective.recipe.cmd
shell = /bin/bash
on_install = true
on_update = true
cmds = ./bin/bower install --config.interactive=false; echo $'\nBower modules installed.\n'

[node_modules]
recipe = collective.recipe.cmd
shell = /bin/bash
on_install = true
on_update = true
cmds = NODE_PATH="" bin/npm install .; echo $'\nNodeJS modules installed.\n'

Plone: Mit Diazo eine HTML-Liste in eine Selection verwandeln

Wenn mann statt einer HTML-Liste (<ul>) eine Auswahlliste (<select>) benötigt, kann man dies leicht mit Diazo umwandeln, ohne tief ins System eingreifen zu müssen. Im folgenden wird die Aktion anhand eines Beispiels erläutert. Wir wandeln hier ein einfaches flaches Navigations-Portlet von Plone in eine Auswahl-Liste (<select>) um.

Ausgangsstruktur

Das HTML des Portlets, welches nur die Unterordner anzeigt, also aus einer Ebene besteht, sieht wie folgt aus:

<dl class="portlet portletNavigationTree">
  <dt class="portletHeader">
    <span class="portletTopLeft"></span>
    <a href="http://127.0.0.1:8081/Plone/sitemap" class="tile">SubNavi</a>
    <span class="portletTopRight"></span>
  </dt>

  <dd class="portletItem lastItem">
    <ul class="navTree navTreeLevel0">
      <li class="navTreeItem visualNoMarker navTreeFolderish section-etwas-ueber-plone">
        <a title="" class="state-published navTreeFolderish contenttype-folder"
          href="etwas-ueber-plone">
          <span>Etwas über Plone</span>
        </a>
      </li>
      <li class="navTreeItem visualNoMarker navTreeFolderish section-etwas-ueber-python">
        <a title="" class="state-published navTreeFolderish contenttype-folder"
          href="etwas-ueber-python">
          <span>Etwas über Python</span>
        </a>
      </li>
      <li class="navTreeItem visualNoMarker navTreeFolderish section-etwas-ueber-zope">
        <a title="" class="state-published navTreeFolderish contenttype-folder"
          href="etwas-ueber-zope">
          <span>Etwas über Zope</span>
        </a>
      </li>
    </ul>
     <span class="portletBottomLeft"></span>
     <span class="portletBottomRight"></span>
  </dd>
</dl>

Zielstruktur

Die HTML-Zielstruktur sieht wie folgt aus:

<div id="subNavWrapper">
  <form action="" method="get">
    <select name="subNavSel" size="1">
      <option value="etwas-ueber-plone"Etwas über Plone</option>
      <option value="etwas-ueber-python">Etwas über Python</option>
      <option value="etwas-ueber-zope">Etwas über Zope</option>
    </select>
  </form>
</div>

Diazo-Rules

Diazo-Rules (Regeln) zum umwandeln in die Zielstruktur:

<replace
  content-children="//dl[contains(@class, 'portletNavigationTree') and ./dt/a/text() = 'SubNavi']">

  <select name="subNavSel" size="1">
  <xsl:for-each select=".//ul[contains(@class, 'navTree')]/li/a">
    <option><xsl:attribute
        name="value"><xsl:value-of
          select="./@href" /></xsl:attribute><xsl:copy-of
          select="./span/text()" /></option>
  </xsl:for-each>
  </select>

</replace>

Plone: ContentType mit NamedBlobFile in tests erzeugen

Im folgenden wird beschrieben, wie man einen ContentType mit einen NamedBlobFile field, in einem Unitest erzeugen kann.

Wir benötigen dazu eine Datei z.B. eine PDF-Datei, die wir programmatisch in unseren ContentType einsetzen können. Diese legen wir einfach in unserem tests-Verzeichniss, parallel zu unserem test ab.

Der folgende Code liest die Datei file.pdf ein und fügt sie in das Feld file des Objektes MyContentTypeObj

def getTestFile(filename):
    """ return contents of the file with the given name """
    filename = os.path.join(os.path.dirname(__file__), filename)
    return open(filename, 'r')

self.portal.invokeFactory(
    "MyContentType",
    id="mycontenttypeobj",
    title="My Content Type Obj",
)
MyContentTypeObj = self.portal.get('mycontenttypeobj')

data = getTestFile('file.pdf').read()
MyContentTypeObj.file = NamedBlobFile(
    data=data,
    contentType='',
    filename=u'file.pdf')

Plone: Javascript Links in Texten erlauben

Plone filter unsichere Inhalte aus volltexten. Wenn man aber alle Nutzer seines Portals kennt, kann man diese Regeln aus praktischen Gründen etwas lockern. z.B. ist es manchmal nützlich Links mit Javascript Funktionalität im Text platzieren zu können. Wie dies möglich gemacht wird, wird nachfolgend erklärt.

Das filtern von Javascript deaktivieren

Dazu müssen wir unter die Motorhaube, ins ZMI in /portal_transforms/safe_html gehen. Dort können wir den Wert für remove_javascript von 1 auf 0 ändern.

Danach am besten Plone neu starten, damit die Änderung wirklich sichtbar wird.

Plone: Kontakt-Link (site-action) für 2 Sprachen konfigurieren

Es ist etwas umständlich eine site-action wie die für das Kontaktformular für mehrere Sprachen auf das entsprechende Kontaktformular verweisen zu lassen. Daher sei es hier nochmal anhand eines mit PloneFormGen erstellten Formulares erleutert.

Wir legen uns mit PloneFormGen ein Kontaktformular an und übersetzen dies, so dass wir nun 2 Formulare mit unterschiedlichem Namen (kontakt und contact) haben.

site-action URL Expression

Die folgende URL-Expression tragen wir in die entsprechende site-action in portal_actions ein.

python: plone_portal_state.language() == 'de' and globals_view.navigationRootUrl() + '/kontakt' or globals_view.navigationRootUrl() + '/contact'

Wenn es mehr als 2 Sprachen werden sollten, empfiehlt es sich hier ein ScriptPython zu verwenden welches den entsprechenden String dann zurück gibt.