Blog

Start 1 2 3 4

01.06.2018 // Renée Bäcker

Ich habe es jetzt schon mehrfach gesehen, dass nach einem Update auf OTRS 6 das Systemprotokoll mit der Meldung Need GroupName geflutet wird. Wenn man sich den Stacktrace dazu anschaut, dann sieht man folgendes:


Message: Need GroupName!

RemoteAddress: 10.70.0.5
RequestURI: /otrs/index.pl?Action=Admin

Traceback (6278):
   Module: Kernel::System::Group::PermissionCheck Line: 945
   Module: Kernel::Output::HTML::NavBar::ModuleAdmin::Run Line: 76
   Module: Kernel::Output::HTML::Layout::NavigationBar Line: 3225
   Module: Kernel::Modules::Admin::Run Line: 35
   Module: Kernel::System::Web::InterfaceAgent::Run Line: 1116
   Module: ModPerl::ROOT::ModPerl::Registry::opt_otrs_bin_cgi_2dbin_index_2epl::handler Line: 40
   Module: (eval) (v1.99) Line: 207
   Module: ModPerl::RegistryCooker::run (v1.99) Line: 207
   Module: ModPerl::RegistryCooker::default_handler (v1.99) Line: 173
   Module: ModPerl::Registry::handler (v1.99) Line: 32

Es hat ein wenig gedauert, bis ich das mit manuellen Änderungen in der SysConfig nachstellen konnte. Jetzt habe ich ein kleines Skript geschrieben, mit dem sich die "Schuldigen" ausfindig machen lassen:

Auf der Kommandozeile sollte dann nach der Ausführung des Skripts so etwas stehen:

Permalink:

19.02.2018 // Renée Bäcker

In OTRS 6 wurde die Ticketansicht komplett überarbeitet. Für das Checklisten-Modul muss nun kein schwerfälliger Ausgabefilter mehr verwendet werden, vielmehr werden die zusätzlichen Widgets (wie auch die Kundeninformationen) über Plugins realisiert. Diese haben den Vorteil, dass sie auch asynchron nachgeladen werden können - was einen nicht unerheblichen Geschwindigkeitsvorteil z.B. bei dem Attachment-Modul bringt.

Ein kleiner Nachteil ist, dass man nicht mehr ganz so flexibel bei der Positionierung ist. In OTRS5 gab es bei dem Checklisten-Modul noch die Config-Option TicketChecklist::Position mit der die komplexe Ansicht direkt unter dem Artikelbaum angezeigt werden konnte.

Unter OTRS6 muss man in der SysConfig eine kleine Anpassung machen:

In der Option Ticket::Frontend::AgentTicketZoom###Widgets###002-TicketChecklist muss der Wert von Location auf Main gestellt werden. Das sorgt dafür, dass die Checkliste in dem großen Hauptbereich angezeigt wird.

Weiterhin muss über das "+" ein neuer Eintrag hinzugefügt werden. Als Schlüssel wird Top eingetragen und als Wert "1". Das weist das Addon an, die Checkliste unter den Artikelbaum zu verschieben.

So sieht die Option dann aus:

Permalink:

14.02.2018 // Renée Bäcker

Mit der JiraPackage-Erweiterung von catworkx ist es möglich, OTRS-Tickets nach Jira zu übertragen und umgekehrt. Über die grundsätzlichen Funktionen haben ich schon vor einiger Zeit gebloggt.

Heute zeige ich, wie man das Feldmapping so erweitern kann, dass Werte dynamisch berechnet werden. Als Beispiel soll es ein Feld "Genehmigt am" in Jira geben, in dem gespeichert wird, wann ein Feature freigegeben wurde. Aus OTRS heraus soll dieses Feld mit dem aktuellen Datum gefüllt werden.

Schritt 1: Erstellen des Benutzerdefinierten Feldes

Es wird ein Datumsfeld verwendet, die Uhrzeit soll hier keine Rolle spielen.

Noch beschreiben was in dem Feld gespeichert wird ...

... und für die entprechenden Seiten aktivieren.

Schritt 2: Erstellen des Perl-Moduls

Für dieses Beispiel reicht ein kleines Perl-Modul, das nur die Subroutine Today zur Verfügung stellt.

Hier benötigt die Subroutine keine Übergabeparameter. Vom Hauptmodul werden aber folgende Parameter übergeben:

  • Objekt von Kernel::System::TicketJira
  • Das Mapping
  • Artikelinformationen

Damit kann alles gemacht werden was man möchte.

Es ist natürlich von Vorteil, wenn man die API der OTRS-Klassen kennt. Denn dann kann man Informationen zu verknüpften Objekten (z.B. Tickets, FAQ, Config Items, ...) zu dem Ticket herausfinden oder einfach die Hilfsfunktionen aus verschiedenen Klassen nutzen. Man kann aber auch andere Perl-Module nutzen oder andere Programme aufrufen. Was in der Subroutine gemacht wird ist im Prinzip egal - man muss nur darauf achten, welches Format Jira haben möchte.

Im Fall von Datumsfeldern muss das Datum in dem Format YYYY-MM-ddThh::mm::ss.0+Offset angegeben werden. Bei anderen Feldern müsste man eine Hashreferenz zurückgeben. Da hilft dann aber auch die Fehlermeldung weiter, die Jira zurückliefert wenn man testweise ein Ticket von OTRS nach Jira überträgt.

Schritt 3: Anpassen des Feldmappings

Im Schlüssel ist das zu finden, was auf OTRS-Seite passieren soll: call:Kernel::System::JiraMapping,Today

Der Aufbau ist call:<Modul>,<Funktion>.

call ist das Schlüsselwort, dass eine Funktion aus einem Modul aufgerufen werden soll. Das Kernel::System::JiraMappingist der Paketname des Moduls und Today ist der Funktionsname.

Das war's.

Wenn jetzt das Ticket aus OTRS heraus an Jira übertragen wird, wird der Inhalt für das Benutzerdefinierte Feld berechnet:

Der erzeugte Vorgang

Sollten Sie noch Fragen zu dem Modul haben, nehmen Sie am besten Kontakt zu catworkx auf.

Permalink:

13.02.2018 // Renée Bäcker

Wenn Sie vor einem Upgrade auf OTRS6 stehen und die kostenlose Erweiterung QuickClose einsetzen, dann sollten Sie vor dem Update folgenden Befehl ausführen:

Ansonsten kommt eine Fehlermeldung bei der Nachbearbeitung der Artikel-Tabellen:

Cannot delete or update a parent row: a foreign key constraint fails

Permalink:

09.02.2018 // Renée Bäcker

Vor knapp zwei Jahren habe ich das Vorgehen schonmal beschrieben, mittlerweile ist aber OTRS 6 erschienen und es haben sich ein paar Änderungen ergeben.

Als erstes wird die Erweiterung TicketOverviewHooked benötigt.

Danach folgende Dateien anlegen:

Kernel/Config/Files/XML/OwnerHook.xml

(unter OTRS5 sah die Datei etwas anders aus und wurde an einem anderen Ort gespeichert)

Kernel/System/TicketOverview/Hooks/Owner.pm

In der SysConfig müssen dann die Besitzer eingepflegt werden. Bei der Option "Hook::Owners" muss als Schlüssel der Login des Agenten angegeben werden und als Wert der Hex-Code für die Farbe. Auf Wikipedia ist eine Farbtabelle zu finden.

Außerdem muss die Option TicketOverview::Hooks angepasst und das neue Plugin eingetragen werden:

Schlüssel: 1002
Wert: Kernel::System::TicketOverview::Hooks::Owner

Soll die Farbe nicht über die SysConfig sondern direkt aus den Agentendaten ausgelesen werden, so muss die Run()-Methode entsprechend angepasst werden.

Permalink:

02.02.2018 // Renée Bäcker

Im Otterhub-Forum, auf der Mailingliste und auch bei meinen Kunden tauchen immer wieder Fragen auf wie "Wie kann ich denn den Abteilungsleiter informieren wenn x Tage nichts mehr am Ticket gemacht wurde" oder "Wie kann ich dem Kunden eine Nachricht schicken zwei Tage nachdem das Ticket geschlossen wurde". Mit einfacher Konfiguration ist das nicht lösbar, da das OTRS nicht hellsehen kann und es auch nicht für alles ein Event geben kann.

An dieser Stelle kommt dann aber das nützliche Trio ins Spiel. Mit dynamischen Feldern kann man alle möglichen Informationen am Ticket oder am einzelnen Artikel speichern. Standardmäßig gibt es ein paar Basistypen wie Textfeld, Dropdown, Checkbox und Datum. Aber auf OPAR gibt es noch weitere Typen (z.B. Agenten, JsonAPI, Integer, MultiCheckbox, ConfigItem, RemoteDB) und wir haben auch noch andere Erweiterungen im Angebot zur Erweiterung der Dynamischen Felder (z.B. Multipart, Icons, ChildTickets, Tags, ...).

Es macht auch nichts wenn man einige Dutzend Dynamische Felder erstellt hat. Wenn für ein Ticket/Artikel kein Wert existiert, gibt es da auch keinen Eintrag in der Datenbank. Und man muss ja auch nicht alle Dynamischen Felder in der Oberfläche anzeigen lassen.

Mit dem GenericAgent kann man wunderbar nach Tickets suchen und dann Informationen am Ticket speichern und/oder ändern. Man kann auch eigene Kommandos schreiben. Typische Aufgaben beim GenericAgent ist z.B. das Löschen von Spam-Mails, das Verschieben von Tickets, das Setzen einer neuen Priorität und so weiter.

Das dritte Puzzleteil in diesem Blogbeitrag sind die Ticketbenachrichtigungen. Seit OTRS5 ist das ziemlich mächtig, denn man kann auf Events reagieren, kann die Tickets noch genauer filtern und auch den Empfängerkreis kann man sehr genau bestimmen. Man kann E-Mails verschicken und in der Business Solution oder mit unserem Paket TicketSMSNotification können Sie auch SMS' verschicken.

Schauen wir uns die Fragestellungen nochmal genauer an: Der Abteilungsleiter soll eine Nachricht bekommen wenn das Ticket x Tage nicht mehr geändert wurde.

Der Abteilungsleiter soll jetzt eine bestimmte Person mit einer festen Mailadresse sein. Jetzt müssen wir überlegen wie wir die Benachrichtigung auslösen können. Benachrichtigungen werden durch Ereignisse/Events ausgelöst. Es gibt aber kein Event das ausgelöst wird wenn ein Ticket x Tage nicht geändert wurde. Also müssen wir dafür sorgen, dass es genau ein solches Event gibt. Dazu müssen wir die Tickets suchen, auf die das Suchkriterium "zuletzt vor mehr als x Tagen geändert" zutrifft. Wir wollen aber nicht selbst suchen, sondern das soll regelmäßig und automatisch gemacht werden.

Und was eignet sich für eine solche Aufgabe? Genau, der GenericAgent. Ein GenericAgent-Job kann auf zwei Arten ausgeführt werden: Eventbasiert, also wenn sich am Ticket etwas ändert, oder auf Basis eines "Kalenders". Die Eventbasierte Ausführung hat den Vorteil, dass etwas unmittelbar nach einer Änderung am Ticket gemacht werden kann. Das ist in unserem Fall aber nicht die Lösung. Wir brauchen die automatische Ausführung. Damit die Ticketbenachrichtigung ausgelöst wird, brauchen wir ein Event. Ein Event wird bei einer Änderung am Ticket ausgelöst. Also müssen wir irgendwas am Ticket verändern.

Da es aber die Information "Das Ticket wurde jetzt seit x Tagen nicht mehr geändert" standardmäßig nicht gibt, müssen wir am Ticket Platz für diese Information schaffen. Also brauchen wir ein Dynamisches Feld.

Fangen wir also damit an.

Ich nehme für solche Informationen ganz gerne ein Textfeld, da ich da sehr frei bin was ich da reinschreibe. Da es eine Information ist, die nur einmal am Ticket vorkommen kann, nehe ich als Objekt "Ticket"

Auswahl des Objektes und des Feldtyps

Dann müssen die "Stammdaten" ausgefüllt werden. Der Name ist wichtig, die Beschriftung nicht - da wir das Feld nirgends anzeigen möchten.

Stammdatenpflege für das Feld

Als nächstes müssen wir das Feld füllen wenn ein Ticket die x (hier: 25) Tage nicht geändert wurde. Dazu im Adminbereich einen neuen GenericAgent anlegen:

Da das regelmäßig ausgeführt werden soll, wählen wir alle Zeitpunkte - außer Samstag und Sonntag.

Wann soll der GenericAgent ausgeführt werden?

Da das nicht bei allen Tickets gefüllt werden soll, müssen wir die Tickets filtern. Die Information ist ja nur bei solchen Tickets interessant, die noch offen sind und eben die 25 Tage nicht geändert wurden. Genau das müssen wir beim Ticketfilter eintragen:

Filter für den GenericAgent

Anschließend speichern wir die Information am Ticket. Wir ändern den Inhalt des eben erstellten Dynamischen Feldes auf "1".

Setze Dynamisches Feld auf 1

Damit haben wir jetzt dafür gesorgt, dass ein Event gefeuert wird wenn ein Ticket 25 Tage nicht bearbeitet wurde. Jetzt müssen wir noch was mit dem Event anfangen. Nun kommen also die Ticketbenachrichtigungen ins Spiel. Diese werden durch Events ausgelöst. Unser Event wird durch die Änderung des einen Dynamischen Feldes ausgelöst. Also müssen wir genau darauf reagieren:

Stammdaten für Ticket-Benachrichtigung

Auch hier interessieren uns nicht alle Tickets, sondern nur die, bei denen der neue Wert des Dynamischen Feldes "1" ist.

Filter für Ticket-Benachrichtigung

Anschließend bestimmen wir noch den Empfänger der Nachricht. Das kann auf Gruppen oder Rollen basieren, auf bestimmten Eigenschaften wie "Schreibrechte auf die Queue" oder "Besitzer des Tickets". Man kann aber auch einfach eine Mailadresse eingeben:

Empfänger der Benachrichtigung

Abschließend müssen wir noch einen Text für die Benachrichtigung festlegen.

Und das war's. Über das Zusammenspiel dieser drei Komponenten kann man ganz viele nützliche Sachen umsetzen. Wenn Sie noch weitere Fragen haben, schreiben Sie uns doch bitte eine Nachricht.

Dadurch dass wir ein Textfeld genommen haben, können wir auch noch mehrere Eskalationen einbauen. Ein weiterer GenericAgent könnte z.B. prüfen, ob das Ticket mehr als 50 Tage nicht angefasst wurde und dann das Dynamische Feld auf "2" setzen. Eine weitere Ticketbenachrichtigung für das gleiche Event aber nur die Tickets nimmt, bei denen der neue Wert "2" ist, könnte eine Nachricht an andere Personen schicken.

Permalink:

28.12.2017 // Renée Bäcker

Wenn Code während der Installation von Addons ausgeführt werden soll, dann schreibt man in der Regel ein Perl-Modul. Ein Beispiel ist ArticleNotes mit seinem var/packagesetup/ArticleNotes.pm. In diesen Perl-Modulen kann man alles mögliche machen, von der Erstellung Dynamischer Felder bis hin zu Änderungen an der Datenbank.

Es gibt auch Tools, die bei der Entwicklung helfen. Leider kann es vorkommen, dass bei einem Fehler in dem Perl-Modul keine ordentliche Fehlermeldung kommt. In so einem Fall kann man einfach folgenden Perl-Code auf der Kommandozeile ausführen und man bekommt deutlich mehr Infos:


    #!/usr/bin/perl

    use Kernel::System::ObjectManager;

    $Kernel::OM = Kernel::System::ObjectManager->new;
    $Kernel::OM->Get('var::packagesetup::ArticleNotes')->CodeInstall();

Und dann einfach $ cd /opt/otrs && perl -IKernel/cpan-lib script.pl.

Permalink:

08.07.2017 // Renée Bäcker

Hat man seine Checklisten als Vorlagen vorbereitet, kann man diese mit dem GenericAgent an Tickets hängen. Das kann man in den unterschiedlichsten Situationen nutzen: Eine Checkliste für Rechenzentrumsrundgänge? Dann einfach die Checkliste an das Ticket hängen wenn es in der Queue RZ::Rundgang erstellt wird. Eine Checkliste die abgearbeitet werden muss wenn ein neuer Mitarbeiter anfängt? Dann die Checkliste an das Ticket hängen wenn es in der Queue HR::Inbound erstellt wird.

Aber nicht nur an Hand der Queue kann man eine Checkliste an ein Ticket hängen. Man kann alle Möglichkeiten des GenericAgent nutzen. So könnte man eine Checklisten-Vorlage erstellen, die bei bestimmten Services gelten soll:

Beispielcheckliste

Als nächstes muss der GenericAgent eingerichtet werden. Als auslösendes Ereignis nehmen wir TicketCreate und TicketServiceUpdate. Damit erfassen wir alle Fälle in denen der Service eines Tickets gesetzt wird.

Events, die den GenericAgent triggern

Natürlich wollen wir die Checkliste nicht bei allen Tickets, die irgendeinen Service haben, sondern nur bei einem bestimmten Service. Im Ticketfilter wählen wir genau diesen Service aus.

Ticketfilter: Service

Zum Schluss noch das Wichtigste: Die Checkliste erstellen. Dazu muss ein benutzerdefiniertes Kommando ausgeführt werden und TicketChecklist liefert dieses Kommando mit: Kernel::System::GenericAgent::AddChecklistToTicket . Als Parameter erwartet das Kommando zum Einen die UserID des Benutzers - der Einfachheit halber wird hier immer die UserID 1 genommen. Und zum Anderen wird die ID der Checklisten-Vorlage benötigt. Diese bekommt man in der Übersicht der Checklisten-Vorlagen: Einfach mit der Maus über den Link fahren und die ID raussuchen.

Kommando erstellt Liste

Haben wir Ihr Interesse an TicketChecklist geweckt? Dann nehmen Sie doch einfach Kontakt zu uns auf oder fordern Sie gleich Ihr Demosystem an.

Haben Sie noch weitere Ideen und Wünsche? Dann schreiben Sie uns bitte

Permalink:

07.07.2017 // Renée Bäcker

OTRS ist an vielen Stellen einfach durch Konfiguration an die eigenen Bedürfnisse anpassbar. So auch beim Einbinden unterschiedlichster Quellen für Kundendaten. Egal ob man LDAP oder eine relationale Datenbank wie MySQL, PostgreSQL nutzt - eine Änderung in der Konfiguration reicht, um eine oder mehrere dieser Quellen einzubinden.

Man sollte nur auf eines achten: Die Kernel/Config/Defaults.pm sollte nie geändert werden. Das macht ein OTRS-Upgrade nur unnötig umständlich. Für Änderungen sollte immer die Kernel/Config.pm angefasst werden.

Jetzt soll ein LDAP-Backend angebunden werden. Dazu kopieren wir einfach den Teil aus der Kernel/Config/Defaults.pm, der dafür verantwortlich und auskommentiert ist:


    $Self->{CustomerUser} = {
        Name => 'LDAP Backend',
        Module => 'Kernel::System::CustomerUser::LDAP',
        Params => {
            # ldap host
            Host => 'test.example',
            # ldap base dn
            BaseDN => 'ou=seas,o=csuh',
            # search scope (one|sub)
            SSCOPE => 'sub',
            # The following is valid but would only be necessary if the
            # anonymous user does NOT have permission to read from the LDAP tree
            UserDN => '',
            UserPw => '',
            # in case you want to add always one filter to each ldap query, use
            # this option. e. g. AlwaysFilter => '(mail=*)' or AlwaysFilter => '(objectclass=user)'
            AlwaysFilter => '',
            # if the charset of your ldap server is iso-8859-1, use this:
            # SourceCharset => 'iso-8859-1',
            # die if backend can't work, e. g. can't connect to server
            Die => 0,
            # Net::LDAP new params (if needed - for more info see perldoc Net::LDAP)
            Params => {
                port    => 389,
                timeout => 120,
                async   => 0,
                version => 3,
            },
        },
        # customer unique id
        CustomerKey => 'uid',
        # customer #
        CustomerID => 'mail',
        CustomerUserListFields => ['cn', 'mail'],
        CustomerUserSearchFields => ['uid', 'cn', 'mail'],
        CustomerUserSearchPrefix => '',
        CustomerUserSearchSuffix => '*',
        CustomerUserSearchListLimit => 250,
        CustomerUserPostMasterSearchFields => ['mail'],
        CustomerUserNameFields => ['givenname', 'sn'],
        # show now own tickets in customer panel, CompanyTickets
        CustomerUserExcludePrimaryCustomerID => 0,
        # add a ldap filter for valid users (expert setting)
        # CustomerUserValidFilter => '(!(description=gesperrt))',
        # admin can't change customer preferences
        AdminSetPreferences => 0,
        # cache time to live in sec. - cache any ldap queries
        CacheTTL => 0,
        Map => [
            # note: Login, Email and CustomerID needed!
            # var, frontend, storage, shown (1=always,2=lite), required, storage-type, http-link, readonly
            [ 'UserTitle',      'Title',      'title',           1, 0, 'var', '', 0 ],
            [ 'UserFirstname',  'Firstname',  'givenname',       1, 1, 'var', '', 0 ],
            [ 'UserLastname',   'Lastname',   'sn',              1, 1, 'var', '', 0 ],
            [ 'UserLogin',      'Username',   'uid',             1, 1, 'var', '', 0 ],
            [ 'UserEmail',      'Email',      'mail',            1, 1, 'var', '', 0 ],
            [ 'UserCustomerID', 'CustomerID', 'mail',            0, 1, 'var', '', 0 ],
            # [ 'UserCustomerIDs', 'CustomerIDs', 'second_customer_ids', 1, 0, 'var', '', 0 ],
            [ 'UserPhone',      'Phone',      'telephonenumber', 1, 0, 'var', '', 0 ],
            [ 'UserAddress',    'Address',    'postaladdress',   1, 0, 'var', '', 0 ],
            [ 'UserComment',    'Comment',    'description',     1, 0, 'var', '', 0 ],
            # this is needed, if "SMIME::FetchFromCustomer" is active
            # [ 'UserSMIMECertificate', 'SMIMECertificate', 'userSMIMECertificate',      0, 1, 'var', '', 0 ],
        ],
    };  

Einstellungen testen

Bevor man gleich das Kundenbackend in OTRS einträgt, sollte man die Einstellungen testen. Ich habe es nicht nur einmal erlebt, dass die Daten die mir als Zugangsdaten zum LDAP gegeben wurden nicht gepasst haben. Entweder war der LDAP-Server nicht erreichbar oder der User für die Verbindung hatte gar keine Rechte. Oder er war noch gar nicht angelegt.

Es gibt einige Tools, mit denen man die Einstellungen testen kann. Ich persönlich nutze ganz gerne die Kommandozeilentools.

otrsvm@otrs5s:~$ ldapsearch -H ldaps://ldap.jumpcloud.com:636 -x \
    -b "ou=Users,o=<id>,dc=jumpcloud,dc=com" \
    -D "uid=otrs_user,ou=Users,o=<id>,dc=jumpcloud,dc=com" -w "<passwd>"
# extended LDIF
#
# LDAPv3
# base <ou=Users,o=<id>,dc=jumpcloud,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# Users, <id>, jumpcloud.com
dn: ou=Users,o=<id>,dc=jumpcloud,dc=com
ou: Users
objectClass: organizationalUnit
objectClass: top

# otrs_user, Users, <id>, jumpcloud.com
# ... user information ...

Auf SourceForge gibt es das Tool OTRS ActiveDirectory config creator. Das habe ich allerdings noch nie genutzt, kann daher keine Aussage dazu treffen, wie gut das Tool ist.

Konfiguration anpassen

Nachdem die Einstellungen getestet wurden, können diese in die Konfiguration eingetragen werden.

Wird ein ActiveDirectory verwendet, müssen mehrere Sachen angepasst werden, weil die Standardattribute von denen im LDAP abweichen. Statt uid als UserLogin zu verwenden, muss z.B. sAMAccountName verwendet werden.

Weiterhin muss das Mapping angepasst werden. Dazu muss man sich überlegen, welche Eigenschaften eines Kunden sollen im OTRS genutzt werden. Das Beispiel-Mapping nennt nur die grundlegenden Stammdaten, aber eventuell möchte man noch die Mobilnummer anzeigen oder - gerade wenn es unternehmensinterne Kunden sind - die Abteilung und die Kostenstelle.

Wer vom Standardmapping abweichen will, muss sich als erstes die Attribute im LDAP raussuchen.

Für jedes Attribut wird eine Zeile im Mapping angelegt:

[ 'UserPhone',      'Phone',      'telephonenumber', 1, 0, 'var', '', 0 ],

Diese Angaben bedeuten:

  1. Attribut im CustomerUser-Objekt - z.B. zur Verwendung in Benachrichtigungen über <OTRS_CUSTOMER_DATA_UserPhone>
  2. Anzeige in der Oberfläche (wird übersetzt)
  3. Attribut im LDAP/AD
  4. Angabe, ob das Attribut angezeigt werden soll oder nicht
  5. Angabe, ob das Attribut ein Pflichtfeld ist
  6. Legt fest, ob das Attribut eine Zahl oder ein String ist
  7. Template für eine Verlinkung des Attributs (siehe auch [diesen Blogpost](https://blog.feature-addons.de/2017-03-23-callto-tel-link-in-kundendaten))
  8. Angabe, ob nur lesend auf das Attribut zugegriffen wird

Da auf LDAP-Backends nur lesend zugegriffen wird und keine Änderungen der Daten über OTRS möglich ist, sind die Angaben in den Spalten 5, 6 und 8 irrelevant.

JumpCloud

Für alle Entwickler: Um nicht ein eigenes LDAP installieren und warten zu müssen, habe ich mir einen kostenlosen Account bei JumpCloud einen kostenlosen Account geholt und ein paar Beispieldaten eingespielt.

Dann ist es einfach, in Demosystemen oder zu Testzwecken ein LDAP-Backend einzubinden.

LDAPS

Standardmäßig wird eine ungesicherte Verbindung zum LDAP aufgebaut. Wer eine Verbindung über SSL aufbauen möchte, kann das mit nur kleinen Änderungen erreichen.

Als Schema muss ldaps eingetragen und der Port muss angepasst werden. Standardmäßig ist der Port für ldaps der 636.

Der geändert Ausschnitt aus der Konfiguration:


    Params => {
        scheme  => 'ldaps',
        port    => 636,
        timeout => 120,
        async   => 0,
        version => 3,
    },

Zertifikate

Müssen Zertifikate angegeben werden, sind weitergehende Änderungen in der Konfiguration notwendig. Dazu ist es ganz praktisch, dass das LDAP-Authentifizierungsmodul von OTRS einige Parameter aus der Konfiguration direkt an das Modul Net::LDAP weitergibt.

Sobald das Schema ldaps eingetragen ist, können diese Parameter übergeben werden:

  • cafile
  • capath
  • clientcert
  • clientkey
  • ciphers
  • sslversion
  • sslserver

also z.B.


    Params => {
        scheme  => 'ldaps',
        port    => 636,
        timeout => 120,
        async   => 0,
        version => 3,
        clientcert => '/path/to/cert.pem',
        clientkey  => '/path/to/key.pem',
    },

Mehrere Backends nutzen

Möchte man nicht nur LDAP als Kundenbackend nutzen, sondern auch die Datenbank, dann ist das kein Problem. In OTRS kann man mehrere Kundenbackends eintragen - aktuell (OTRS 5.0.20) sind es bis zu 11 Backends. Wer mehr braucht, muss das an vielen Stellen im Code anpassen.

Aber ob die große Zahl an Kundendatenbackends sinnvoll ist, steht wieder auf einem anderen Blatt. Jedes Backend frisst natürlich etwas Performanz, da ggf. Daten über das Netzwerk geschoben werden, evtl. sind auch die LDAP-Hosts oder die Datenbanken nicht erreichbar.

Ich tendiere immer dazu, die Kundenbackends weitestgehend zusammenzufassen - wenn es geht.

Bei zwei Backends lohnt sich das Zusammenführen meist noch nicht, aber wenn es mal mehr als vier Backends werden, sollte man sich mal Gedanken dazu machen.

Die verschiedenen Backends werden durch eine fortlaufende Nummerierung unterschieden:


    $Self->{CustomerUser} = {
        Name => 'LDAP Backend',
        Module => 'Kernel::System::CustomerUser::LDAP',
        # weitere Parameter
    };

    $Self->{CustomerUser1} = {
        Name => 'OTRS DB Backend',
        Module => 'Kernel::System::CustomerUser::DB',
        # weitere Parameter
    };

    $Self->{CustomerUser2} = {
        Name => 'Supplier LDAP Backend',
        Module => 'Kernel::System::CustomerUser::LDAP',
        # weitere Parameter
    };

Authentifizierung

Bisher hat dieser Blogpost nur die Datenhaltung der Kundenbenutzer betrachtet. Wird das Kundenfrontend benutzt, muss ggf. noch die Authentifizierung über das LDAP bzw. über die Datenbank laufen. Auch hierfür gibt es eigene Konfigurationseinstellungen, die in der Kernel/Config.pmgemacht werden müssen.


    #Enable LDAP authentication for Customers / Users
    $Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::LDAP';
    $Self->{'Customer::AuthModule::LDAP::Host'} = 'host.example.com';
    $Self->{'Customer::AuthModule::LDAP::BaseDN'} = 'ou=BaseOU,dc=example,dc=com';
    $Self->{'Customer::AuthModule::LDAP::UID'} = 'sAMAccountName';

    #The following is valid but would only be necessary if the
    #anonymous user do NOT have permission to read from the LDAP tree
    $Self->{'Customer::AuthModule::LDAP::SearchUserDN'} = 'otrs_ldap';
    $Self->{'Customer::AuthModule::LDAP::SearchUserPw'} = 'PASSWORD';

    # Second auth-backend: The OTRS DB
    $Self->{'Customer::AuthModule1'}                       = 'Kernel::System::CustomerAuth::DB';
    $Self->{'Customer::AuthModule::DB::Table1'}            = 'customer_user';
    $Self->{'Customer::AuthModule::DB::CustomerKey1'}      = 'login';
    $Self->{'Customer::AuthModule::DB::CustomerPassword1'} = 'pw';

Genauso wie bei den Backends für die Kundenbenutzerdaten, kann man mehrere Authentifizierungsbackends angeben. Die Parameter, die zusammengehören, müssen auch den einheitlichen Suffix haben. So wie hier bei allen Parametern für die OTRS-Datenbank den Suffix "1" haben.

Welche Reihenfolge?!

Geht es um mehrere Backends stellt sich die Frage, welche Reihenfolge die Einträge haben sollten.

Das ist nicht ganz einfach pauschal zu beantworten. Ich würde mir Gedanken dazu machen, welche Backends am häufigsten benötigt werden und wie diese Backends angebunden sind. OTRS geht die Backends der Reihe nach durch, also zu erst "CustomerUser", dann "CustomerUser1", anschließend "CustomerUser2" und so weiter.

Ich würde die langsamsten Backends ans Ende stellen - außer es ist ein Backend dabei, aus dem der Großteil der abgerufenen Kundendaten stammt. Dann würde ich das weiter nach vorne einsortieren (und schauen ob ich nicht an der Perfomanz etwas drehen kann).

Die Dokumentation zum Thema "Kundenbenutzerbackends" ist auf github zu finden: http://otrs.github.io/doc/manual/admin/stable/en/html/external-backends.html#customer-user-backend.

Permalink:

12.06.2017 // Renée Bäcker

Im Standard AdvancedTicketCalendar können Tickets auf Basis der Erinnerungszeit und auf Basis von Dynamischen Feldern angezeigt werden.

In diesem Blogpost soll gezeigt werden, wie man weitere Regeln für die Anzeige von Tickets einrichtet. Als Beispiele sollen Entwicklungstickets erstellt werden. Zum einen sollen der Beginn der Entwicklung und die Übergabe als Termine im Kalender angezeigt werden und zum anderen soll es einen Testzeitraum geben.

Dazu werden vier dynamische Felder benötigt:

  • StartDevelopment
  • StartTest
  • EndTest
  • GoingLive

Alle vier Felder müssen vom Typ Date oder DateTime sein. Exemplarisch ist hier das Feld StartDevelopment gezeigt:

Außerdem wird für das Beispiel mit dem Testzeitraum noch ein weiteres dynamisches Feld angelegt und zwar vom Typ Agent. Damit wird in dem Ticket der Testverantwortliche festgelegt.

Dieses dynamische Feld wird später noch von Bedeutung sein wenn es um die Farbgebung der Kalendereinträge geht.

Anschließend wird eine eigene .xml-Datei unter Kernel/Config/Files benötigt. Darin werden drei "ConfigItems" definiert.

Das erste ConfigItem definiert die Termine für den Start der Entwicklung:

<ConfigItem Name="AdvancedTicketCalendar::Fields###StartDevelopment" Required="0" Valid="1">
    <Description Translatable="1">...</Description>
    <Group>AdvancedTicketCalendar</Group>
    <SubGroup>OwnFilters</SubGroup>
    <Setting>
        <Hash>
            <Item Key="Start">DynamicField_StartDevelopment</Item>
            <Item Key="Duration">1</Item>
            <Item Key="Color">#32cd32</Item>
            <Item Key="Icon">calendar</Item>
        </Hash>
    </Setting>
</ConfigItem>

Der Name der Konfig-Option muss mit AdvancedTicketCalendar::Fields### beginnen.

Folgende Einstellungen werden hier vorgenommen:

  • Start
  • Duration
  • Color
  • Icon

Bei Start wird das Feld eingetragen, das den Startzeitpunkt im Kalender bestimmt. In diesem Fall wird das von dem Dynamischen Feld StartDevelopmentbestimmt. Ist es kein ganztägiges Ereigniss und man hat keinen Endzeitpunkt angegeben, kann mit Duration festgelegt werden, wie viele Stunden der Termin im Kalender vereinnahmt.

Gibt es den Color-Eintrag, haben alle Kalendereinträge für diese Gruppe genau diese Farbe. Hier muss eine HTML-Farbe in HEX-Schreibweise eingetragen werden.

Bei jedem Kalendereintrag erscheint ein kleines Icon. Darüber können die Agenten schon auf den ersten Blick erkennen, welche Art von Termin der Eintrag ist. Unterstützt werden die Fontawesome-Icons.

Die zweite Option konfiguriert die Einträge für den Testzeitraum:

</ConfigItem>
<ConfigItem Name="AdvancedTicketCalendar::Fields###Testing" Required="0" Valid="1">
    <Description Translatable="1">...</Description>
    <Group>AdvancedTicketCalendar</Group>
    <SubGroup>OwnFilters</SubGroup>
    <Setting>
        <Hash>
            <Item Key="Start">DynamicField_StartTest</Item>
            <Item Key="Stop">DynamicField_EndTest</Item>
            <Item Key="Color">#00FFFF</Item>
            <Item Key="Icon">bug</Item>
            <Item Key="ColorBy">DynamicField_TestAgent</Item>
        </Hash>
    </Setting>
</ConfigItem>

Zusätzlich zu der Start-Angabe wird das Ende im Kalender über ein weiteres Dynamisches Feld bestimmt: EndTest. Auch haben hier die Kalendereinträge nicht alle die gleiche Farbe. Die Farbe des Termins wird über den Testagenten gesteuert. Deshalb auch das fünfte Dynamische Feld.

Um die Farbgebung zu steuern wird eine zusätzliche Option benötigt:

<ConfigItem Name="AdvancedTicketCalendar::ColorBy###DynamicField_TestAgent" Required="0" Valid="0">
    <Description Translatable="1">If enabled in the fieldconfig the color is defined by the testagent.</Description>
    <Group>AdvancedTicketCalendar</Group>
    <SubGroup>OwnFilters</SubGroup>
    <Setting>
        <Hash>
            <Item Key="ownerlogin">#d8d8d8</Item>
        </Hash>
    </Setting>
</ConfigItem>

Jeder Agent bekommt hier eine Farbe zugeteilt. So kann jeder Testagent gleich erkennen, wann der nächste Zeitraum für ihn/sie beginnt.

Die komplette .xml ist unter http://blog.feature-addons.de/downloads/AdvancedTicketCalendarOwnRules.xml zu finden.

Nachdem die Datei im Kernel/Config/Files-Verzeichnis angelegt wurde, muss der Admin über die Weboberfläche in die SysConfig gehen, die Gruppe "AdvancedTicketCalendar" anwählen und in die Subgrouppe "OwnFilters" gehen. Das sieht dann folgendermaßen aus:

Ist alles eingerichtet, kann man die Dynamischen Felder bei den Tickets füllen:

Dann werden die Einträge entsprechend im Kalender dargestellt.

Und bei einem Update darf man nicht vergessen, diese .xml-Datei mit in das neue OTRS zu übernehmen. Daher empfehlen wir immer, auch eigene kleine Anpassungen in ein Paket zu packen, so dass man nicht immer nach geänderten Dateien suchen muss. Das ist besser als jede Dokumentation. Wenn Sie Fragen dazu haben, dürfen Sie uns gerne kontaktieren.

Sollten Sie Interesse an AdvancedTicketCalendar können wir gerne ein Demo-System für Sie einrichten.

Permalink: