t2ldap

Mit dem t2ldap Modul wird ein über LDAP durchsuchbares Kontakt Verzeichnis realisiert. Dabei werden Kontakte dynamisch aus externen Quellen über Importer eingelesen, durch Middleware manipuliert und als persönliche, gruppenbasierte oder globale kontakt Verzeichnisse bereit gestellt.

User

Jeder aktive Nutzeraccount kann via LDAP Suchanfragen stellen. Dabei kann individuell pro Nutzer konfiguriert werden, in welchen Adressbüchern gesucht werden kann.

Nutzer können

  • Besitzer eines Adressbuch sein

  • Mitglied in einer Adressbuchgruppe mit einem oder mehreren Adressbüchern sein

  • in als global markierten Adressbüchern suchen

Sucht ein Nutzer, sucht er auf der Gesamtmenge an Einträgen aller Adressbücher, auf die er Zugriff hat. Dabei ist wichtig, das alle auf diese Art zusammen gefassten Adressbücher das gleiche Schema benutzen und die gleichen Felder bereit stellen.

Adressbücher

Ein Adressbuch besteht aus beliebig vielen Quellen. Bei einem Synkronisierungslauf werden alle Einträge aller Quellen als Ergebnis, formatiert nach dem im Adressbuch eingestelltem Schema, in den Entrycache geschrieben.

Adressbuch Schema

Ein Adressbuch Schema definiert die Felder die bei einer Exporter des Adressbuchs in den EntryCache geschrieben werden. Damit wird erreicht, das ein definiertes Set an Feldnamen im EntryCache vorhanden ist und diese somit via LDAP Query abgefragt werden können.

Beispiel: Definiert ein Schema ein Feld „meta“, wird dieses Feld via LDAP Query als Feld in dessen Ergebnis vorhanden sein. Gefüllt werden wird dieses Feld mit Wert, der in dem gleichen Feld der Adressbuch Quelle steht, nachdem diese die Importerdaten mit ihren Middlewares formatiert oder erstellt hat. Sollte das Feld dort nicht vorhanden sein, wird das Feld im EntryCache leer gelassen.

Anders gesagt stellt das Schema sicher, das es alle Felder gibt. Das eine Quelle diese Felder auch liefert, ist Aufgabe der in der Quelle definierten Middleware.

Felder die in Adressbuch Quellen noch vorhanden sind, aber nicht im Schema aufgelistet sind, werden nicht in den EntryCache geschrieben.

Adressbuch Gruppen

Adressbücher können in einer oder mehreren Adressbuch Gruppen eingetragen werden. Solchen Gruppen hinzugefügte User benutzen alle Adressbücher der Gruppen zum Durchsuchen.

Adressbuch Quellen

Einem Adressbuch können beliebig viele Quellen zugewiesen werden und stellen die Verbindung zwischen einem Adressbuch und dem Importer dar.

Eine Adressbuchquelle liefert einem Adressbuch Einträge eines Importers, formatiert durch eine oder mehrere Middlewares.

Middleware werden sortiert nach dem Gewicht der Reihe nach angewendet. Die Middleware mit dem geringstem Gewicht zu erst.

Middleware

Middlewares werden zwischen die Adressbuch Quellen und ihre verknüpften Import geschaltet.

Middlewares dienen dazu, bei Synkronisierungslauf Felder der importer Quelldaten anhand von Middleware Modifiers zu verändern, zu erzeugen oder Feldinhalte zu verändern.

So kann aus einem Vorname und Nachname Feld im Importer Datensatz ein neues Feld Displayname mit Inhalt Nachname, Vorname erstellt werden.

Dazu verwendet die Middleware eine Template {{ row.last_name }}, {{ row.first_name }} und schreibt die übersetzte Ausgabe in das angegebene Feld.

Middlewares können in beliebig vielen Adressbüchern verwendet werden.

Middlewares können verkettet werden. Das heisst das in einer nachfolgend ausgeführten Middleware die Ergebnisse der vorher gehenden Middleware erhalten.

Ist ein Feld current_date mit dem aktuellen Datum {{ datetime }} gefüllt worden, kann die nachfolgende Middleware auf dieses Datum mit {{ row.current_date }} zugreifen.

Wird eine Middleware verändert, ändert sich ihr Verhalten automatisch an allen verwendeten Stellen.

Middlewares werden pro Satz/Zeile angewendet. Im SRC Feld steht eine Template Engine zu Verfügung (Jinja2).

Anhand von Variablen kann auf die Daten der Importerzeile zugegriffen werden über {{ row }} oder {{ datetime }}.

  • row: Liste der Felder der aktuellen Zeile

  • middlewaremodifier: Object des Modifier selbst

  • middleware: Object der derzeit ausgeführten Middleware

  • addressbooksource: Object der Quelle in das die Daten fliessen sollen

  • importer: Object des Importers der die Daten geladen hat

  • datetime: Python ‚datetime.now()‘ Object mit aktueller Zeit

Modifier Beipiele

Name: set fixed String to a Field
Description: set fixed String to Field 'country'
Modifier:
  - src: Canada
    dest: country
Name: combine two Fields to a new Field
Description: join the Fields 'last_name' and 'first_name' in a new Field 'displayname' where the Lastname is in upper Case
Modifier:
  - src: {{ row.last_name|upper }}, {{ row.first_name }}
    dest: displayname
Name: create a Meta Search Field
Description: create a new Field 'meta' with the '-' separeted List of all Values of all Fields
Modifier:
  - src: {% for field,value in row.items %}{{ value|safe }} - {% endfor %}
    dest: meta
Name: Example CSV Importer Data
Descriptions: formats the Fields from CSV File from Demo to a generic Format
Modifier:
  - src: {{ row.email }}
    dest: cn
  - src: {{ row.first_name }}
    dest: givenname
  - src: {{ row.last_name }}
    dest: sn
  - src: {{ row.company_name }}
    dest: company
  - src: Unknown
    dest: position
  - src: {{ row.address }}
    dest: street
  - src: {{ row.postal }}
    dest: postalcode
  - src: {{ row.city }}
    dest: city
  - src: {{ row.country }}
    dest: country
  - src: {{ row.phone1 }}
    dest: telephonenumber
  - src: {{ row.phone2 }}
    dest: mobile
  - src: {{ row.phone1 }}
    dest: homephone
  - src: {{ row.email}}
    dest: sip
  - src: {{ row.email}}
    dest: email
  - src: {{ row.web}}
    dest: url
Name: Example for Importer JSON Keys wich breaking Jinja2 Templates
Descriptions: Loops over all fields in the row and only prints the value of the wanted field 'adr_windows-1252' (the - breaks it in this case)
Modifier:
  - src: {% for key, value in row.items %}{% if key == "adr_windows-1252" %}{{value}}{% endif %}{% endfor %}
    dest: adr
Name: Apply a regex on a field
Description: the example looks for whitespace (\s) and '-' and 'search' in the field ´´row.tel_work´´, replaces each match with 'replaced' and puts it in the field ´´telephonenumber´´
Modifier:
  - src: {% load t2ldap_extras %}{{ row.tel_work|re_sub:"A\s|-|searchAreplaced"}}
    dest: telephonenumber

Importer

../../../../_images/t2core_t2ldap_importer_overview.png

Importer stellen die Verbindung zu externen Datenquellen bereit und werden einmal pro externer Quelle benötigt.

Eine Importer Instanz kann beliebig vielen Adressbüchern als Quelle dienen, jeweils über die Middleware entsprechend unterschiedlich aufbereitet.

Importer sind aufgeteil nach dem Datentyp den sie abfragen sollen. Ein Importer CSV kann CSV Daten aus einer lokalen Datei oder via HTTP lesen. Ein Importer ODBC kann SQL Abfragen an externe Server stellen und die Ergebnisse bereit stellen.

Importer laufen im Normalfall lokal als Docker Container, können aber auch extern gehostet werden und über eine HTTP Verbindung angeschaltet werden.

../../../../_images/t2core_t2ldap_importer_local_or_remote.png

Importer HTTP Schnittstelle

Jeder Importer besteht aus einem Docker Container und startet einen eigenen Webserver auf Port 8000 auf der Container IP Adresse.

Importer stellen die Daten ihrer original Quellen in einem gemeinsamen JSON Format in ihrem Webinterface unter /json bzw. unter /yaml bereit.

Lokale Importer sind anhand der Labels des Container automatisch über den EntryPoint importer:81 des Reverse Proxy unter einer individuellen URL erreichbar:

http://<host_or_ip>:81/importer/<importer id>/
http://192.168.2.219:81/importer/1001/

Bemerkung

t2ldap nutzt für diese Verbindung den Docker internen DNS Namen router und greift auf die Importer über http://router:81/importer/1001/ zu.

Remote Importer nutzen für diese Verbindungen die Parameter url, username, password, verifiy SSL, Auth Method um die URL zusammen zu setzen.

Für die Verbindung zwischen t2ldap und den Importern besteht ein individuell konfigurierbares Timeout von 60 Sekunden.

Über den Parameter Primary Key wird definiert, welches Feld in den Ergebnissen des Importers einen einzigartigen Identifier enthält.

Als Beispiel das erfolgreiche Ergebnis einer Anfrage an einen CSV Importer, der zwei Datensätze aus der lokalen Datei /trizwo-csv-exporter/examples/ca-500.csv eingelesen hat.

{
    "error": false,
    "error_str": null,
    "file": "/trizwo-csv-exporter/examples/ca-500.csv",
    "num_results": 2,
    "results": [
        {
            "address": "2335 Canton Hwy #6",
            "city": "Windsor",
            "company_name": "Riebesell, H F Jr",
            "email": "francoise.rautenstrauch@rautenstrauch.com",
            "first_name": "Francoise",
            "last_name": "Rautenstrauch",
            "phone1": "519-569-8399",
            "phone2": "519-978-6179",
            "postal": "N8N 3N2",
            "province": "ON",
            "web": "http://www.riebesellhfjr.com"
        },
        {
            "address": "6 Arch St #9757",
            "city": "Alcida",
            "company_name": "Deloitte & Touche",
            "email": "kloud@gmail.com",
            "first_name": "Kendra",
            "last_name": "Loud",
            "phone1": "506-363-1526",
            "phone2": "506-932-4472",
            "postal": "E8J 2C4",
            "province": "NB",
            "web": "http://www.deloittetouche.com"
        }
    ]
}

Im Fehlerfall enthält das zurück gelieferte JSON den Fehlergrund.

{
    "error": true,
    "error_str": "this contains the Error Message as String",
    "file": "/trizwo-csv-exporter/examples/ca-500.csv",
    "num_results": 0,
    "results": []
}

In diesem Beispiel liefert der CSV Importer abhängig von der Spaltennamen in der CSV Datei die Feldnamen address,``city`` usw.. Eine zweite CSV Datei kann andere Spalten Namen enthalten und liefert daher andere Felder zurück. Fragt ein Importer SQL oder LDAP Server ab, setzen sich die Feldnamen entsprechend der Felder aus der SQL Resonse bzw. LDAP Query zusammen.

Importer Arten

Exporter

Custom Exporter Templates

To create a custom exporter template you can use the django command exec_exporter with the action test.

./manage.py exec_exporter test –ids 1 –with-template-file /data/csv_with_fixed_schema_fields.tpl

This loads the directory data of the Exporter with the ID 1, uses the template in the file given with --with-template-file to render a CSV and prints it out to the console again. To save the output of the rendered CSV to a file use the --output-file parameter.

./manage.py exec_exporter test –ids 1 –with-template-file /data/csv_with_fixed_schema_fields.tpl –output-file /data/csv1.csv

The files with --with-template-file uses the Django Template System. Details of the Models, Tags and Filters are listed at /admin/doc/ at the adminportal of your local instance.

Template to render a CSV File with all Schemafields:

{% load t2ldap_extras %}"extancor";{% for col in directory.schema.schemafield_set.all %}"{{ col.name }}"{% if not forloop.last %};{% endif %}{% endfor %}
{% for row in directory.entry_set.all %}"{{ row.primarykey }}";{% for col in directory.schema.schemafield_set.all %}"{% filter_queryset_by_field row.fields.all 'key' col.name 'value' %}"{% if not forloop.last %};{% endif %}{% endfor %}
{% endfor %}

Template to render a CSV File with distinct, fixed Schemafields and only the first 10 rows:

{% load t2ldap_extras %}"extancor";{% with "displayname email homephone" as colnames %}{% for colname in colnames.split %}"{{ colname }}"{% if not forloop.last %};{% endif %}{% endfor %}
{% for row in directory.entry_set.all|slice:10 %}"{{ row.primarykey }}";{% for colname in colnames.split %}"{% filter_queryset_by_field row.fields.all 'key' colname 'value' %}"{% if not forloop.last %};{% endif %}{% endfor %}
{% endfor %}{% endwith %}

Syncronisierung

../../../../_images/t2core_t2ldap_sync.png

Beispiele

Innovaphone v13

../../../../_images/t2core_t2ldap_example_innovaphone_v13.png

Innovaphone v12

../../../../_images/t2core_t2ldap_example_innovaphone_v12.png