OTRS

Software version2.4.14
Operating SystemDebian 6
WebsiteOTRS Website
Last Update31/10/2012

Introduction

Open-source Ticket Request System (OTRS, literally “open source ticket request system”), is an open source software for customer relationship management or support service management. A company, organization or institution can use it to assign “tickets” to requests made via the help desk or troubleshooting service. This system facilitates the processing of support or troubleshooting requests and any requests made by phone or email. OTRS is distributed under GNU Affero General Public License.1

For the implementation of this version, I used the official documentation2 and made some small adjustments.

Prerequisites

Check that your locales are correctly defined:

  dpkg-reconfigure locales
  

Installation

We will need these packages:

  aptitude install libapache2-mod-perl2 libdbd-pg-perl libnet-dns-perl libnet-ldap-perl libio-socket-ssl-perl libpdf-api2-perl libsoap-lite-perl libgd-text-perl libgd-graph-perl libapache-dbi-perl postgresql aspell aspell-en dbconfig-common dictionaries-common javascript-common libalgorithm-diff-perl libalgorithm-diff-xs-perl libaspell15 libauthen-sasl-perl libbit-vector-perl libcarp-clan-perl libcrypt-passwdmd5-perl libdate-pcalc-perl libemail-valid-perl libio-socket-inet6-perl libjs-prototype libjs-yui libmail-pop3client-perl libnet-domain-tld-perl libnet-imap-simple-perl libnet-imap-simple-ssl-perl libnet-smtp-ssl-perl libsocket6-per libtext-csv-perl libtext-csv-xs-perl libtext-diff-perl libxml-feedpp-perl libxml-treepp-perl procmail wwwconfig-common
  

Note that I’m using PostgreSQL and not MySQL. Next, we install OTRS (I deliberately didn’t take the latest version, but you can do it without any worries):

  useradd -r -d /opt/otrs/ -c 'OTRS user' otrs
usermod -g www-data otrs
cd /opt
wget http://ftp.otrs.org/pub/otrs/otrs-2.4.14.tar.gz
tar -xzf otrs-2.4.14.tar.gz
rm -f otrs-2.4.14.tar.gz
mv otrs-* otrs && cd otrs
cp Kernel/Config.pm.dist Kernel/Config.pm
cp Kernel/Config/GenericAgent.pm.dist Kernel/Config/GenericAgent.pm
perl bin/SetPermissions.pl --otrs-user=otrs --otrs-group=otrs --web-user=www-data --web-group=www-data /opt/otrs
  

Configuration

Apache

We’ll create this configuration in Apache:

  # --
# added for OTRS (http://otrs.org/)
# $Id: apache2-httpd-new.include.conf,v 1.5 2008/11/10 11:08:55 ub Exp $
# --

# agent, admin and customer frontend
ScriptAlias /otrs/ "/opt/otrs/bin/cgi-bin/"
Alias /otrs-web/ "/opt/otrs/var/httpd/htdocs/"

# if mod_perl is used
<IfModule mod_perl.c>

    # load all otrs modules
    Perlrequire /opt/otrs/scripts/apache2-perl-startup.pl

    # Apache::Reload - Reload Perl Modules when Changed on Disk
    PerlModule Apache2::Reload
    PerlInitHandler Apache2::Reload
    PerlModule Apache2::RequestRec

    # set mod_perl2 options
    <Location /otrs>
        ErrorDocument 403 /otrs/index.pl
        ErrorDocument 404 /otrs/index.pl
        SetHandler  perl-script
        PerlResponseHandler ModPerl::Registry
        Options +ExecCGI +FollowSymLinks
        PerlOptions +ParseHeaders
        PerlOptions +SetupEnv
        Order allow,deny
        Allow from all
       #<IfModule mod_rewrite.c>
       #   RewriteEngine On
       #   RewriteCond /usr/share/otrs/var/httpd/htdocs/maintenance.html -l
       #   RewriteRule ^.*$ /otrs-web/maintenance.html
       #</IfModule>
    </Location>

</IfModule>

# directory settings
<Directory "/opt/otrs/bin/cgi-bin/">
    AllowOverride None
    Options +ExecCGI -Includes
    Order allow,deny
    Allow from all
</Directory>
<Directory "/opt/otrs/var/httpd/htdocs/">
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>
  

Then we restart Apache:

  service apache2 restart
  

PostgreSQL

We’ll configure the authentication part:

  [...]
# Database administrative login by UNIX sockets
local   all         postgres                          ident

# TYPE  DATABASE    USER        CIDR-ADDRESS          METHOD

# OTRS
local   otrs    otrs    md5
host    otrs    otrs    127.0.0.1/32    md5
# "local" is for Unix domain socket connections only
local   all         all                               ident
# IPv4 local connections:
host    all         all         127.0.0.1/32          md5
# IPv6 local connections:
host    all         all         ::1/128               md5
  

And create users, databases, grant access:

  su postgres
psql
create user otrs password 'otrs' nosuperuser;
create database otrs owner otrs;
  

Then we restart everything to ensure the new configuration is active:

  service postgresql restart
  

And finally, we import the schemas:

  psql -U otrs -W -f scripts/database/otrs-schema.postgresql.sql otrs
psql -U otrs -W -f scripts/database/otrs-initial_insert.postgresql.sql otrs
psql -U otrs -W -f scripts/database/otrs-schema-post.postgresql.sql otrs
  

OTRS

All that’s left is to configure OTRS. Here I’ve added LDAP:

  # --
# Kernel/Config.pm - Config file for OTRS kernel
# Copyright (C) 2001-2009 OTRS AG, http://otrs.org/
# --
# $Id: Config.pm.dist,v 1.21 2009/02/16 12:01:43 tr Exp $
# --
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --
#  Note:
#
#  -->> OTRS does have a lot of config settings. For more settings
#       (Notifications, Ticket::ViewAccelerator, Ticket::NumberGenerator,
#       LDAP, PostMaster, Session, Preferences, ...) see
#       Kernel/Config/Defaults.pm and copy your wanted lines into "this"
#       config file. This file will not be changed on update!
#
# --

package Kernel::Config;

sub Load {
    my $Self = shift;
    # ---------------------------------------------------- #
    # ---------------------------------------------------- #
    #                                                      #
    #         Start of your own config options!!!          #
    #                                                      #
    # ---------------------------------------------------- #
    # ---------------------------------------------------- #

    # ---------------------------------------------------- #
    # database settings                                    #
    # ---------------------------------------------------- #
    # DatabaseHost
    # (The database host.)
    $Self->{DatabaseHost} = 'localhost';
    # Database
    # (The database name.)
    $Self->{Database} = 'otrs';
    # DatabaseUser
    # (The database user.)
    $Self->{DatabaseUser} = 'otrs';
    # DatabasePw
    # (The password of database user. You also can use bin/CryptPassword.pl
    # for crypted passwords.)
    $Self->{DatabasePw} = 'otrs';
    # DatabaseDSN
    # (The database DSN for MySQL ==> more: "man DBD::mysql")
    #$Self->{DatabaseDSN} = "DBI:mysql:database=$Self->{Database};host=$Self->{DatabaseHost};";

    # (The database DSN for PostgreSQL ==> more: "man DBD::Pg")
    # if you want to use a local socket connection
    $Self->{DatabaseDSN} = "DBI:Pg:dbname=$Self->{Database};";
    # if you want to use a tcpip connection
#    $Self->{DatabaseDSN} = "DBI:Pg:dbname=$Self->{Database};host=$Self->{DatabaseHost};";

    # ---------------------------------------------------- #
    # fs root directory
    # ---------------------------------------------------- #
    $Self->{Home} = '/opt/otrs';

    # ---------------------------------------------------- #
    # insert your own config settings "here"               #
    # config settings taken from Kernel/Config/Defaults.pm #
    # ---------------------------------------------------- #
    # $Self->{SessionUseCookie} = 0;
    # $Self->{CheckMXRecord} = 0;

    # ---------------------------------------------------- #

    # ---------------------------------------------------- #
    # data inserted by installer                           #
    # ---------------------------------------------------- #
    # $DIBI$

    ##############
    # AGENT PART #
    ##############
    # Allows to define the Agent view (accessible via index.pl)

    $Self->{SecureMode} = 1;
    $Self->{FQDN} = 'ldap.deimos.fr';
    $Self->{AdminEmail} = 'xxx@mycompany.com';
    $Self->{ProductName} = 'Deimosfr';
    $Self->{DefaultLanguage} = 'fr';
    $Self->{DefaultCharset} = 'utf-8';
    $Self->{'LogModule::SysLog::Charset'} = 'utf-8';
    $Self->{'AuthModule::LDAP::Charset'} = 'utf-8';
    $Self->{'AuthSyncModule::LDAP::Charset'} = 'utf-8';

    $Self->{'AuthModule'} = 'Kernel::System::Auth::LDAP';
    $Self->{'AuthModule::LDAP::Host'} = 'ldap.deimos.fr';
    $Self->{'AuthModule::LDAP::BaseDN'} = 'ou=users,dc=deimos,dc=fr';
    $Self->{'AuthModule::LDAP::UID'} = 'uid';
    $Self->{'AuthModule::LDAP::UserLowerCase'} = 1;
    $Self->{'AuthModule::LDAP::Params'} = {
        port    => 389,
        timeout => 120,
        async   => 0,
        version => 3,
    };

    #############
    # SYNC PART #
    #############
    # Sync allows to synchronize customer information in the database once authentication is successful

    $Self->{'AuthSyncModule'} = 'Kernel::System::Auth::Sync::LDAP';
    $Self->{'AuthSyncModule::LDAP::Host'} = 'ldap.deimos.fr';
    $Self->{'AuthSyncModule::LDAP::BaseDN'} = 'ou=users,dc=deimos,dc=fr';
    $Self->{'AuthSyncModule::LDAP::UID'} = 'uid';
    $Self->{'AuthSyncModule::LDAP::UserSyncMap'} = {
        # DB -> LDAP
        UserFirstname => 'givenName',
        UserLastname  => 'sn',
        UserEmail     => 'mail',
    };
    $Self->{'AuthSyncModule::LDAP::Params'} = {
        port    => 389,
        timeout => 120,
        async   => 0,
        version => 3,
    };
    $Self->{'AuthSyncModule::LDAP::UserSyncInitialGroups'} = [
        'users',
    ];

    #################
    # CUSTOMER PART #
    #################
    # Allows to define the Customer view (accessible via customer.pl)

    $Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::LDAP';
    $Self->{'Customer::AuthModule::LDAP::Host'} = 'localhost';
    $Self->{'Customer::AuthModule::LDAP::BaseDN'} = 'dc=deimos,dc=fr';
    $Self->{'Customer::AuthModule::LDAP::UID'} = 'uid';

    $Self->{CustomerUser} = {
        Name => 'LDAP Backend',
        Module => 'Kernel::System::CustomerUser::LDAP',
        Params => {
            # ldap host
            Host => 'localhost',
            # ldap base dn
            BaseDN => 'dc=deimos,dc=fr',
            # search scope (one|sub)
            SSCOPE => 'sub',
            SourceCharset => 'utf-8',
            DestCharset => 'iso-8859-1',
            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 uniq id
        CustomerKey => 'uid',
        # customer #
        CustomerID => 'mail',
        CustomerUserListFields => ['cn', 'mail'],
        CustomerUserSearchFields => ['uid', 'cn', 'mail'],
        CustomerUserSearchPrefix => '',
        CustomerUserSearchSuffix => '*',
        CustomerUserSearchListLimit => 250,
        CustomerUserPostMasterSearchFields => ['mail'],
        CustomerUserNameFields => ['givenname', 'sn'],
        # show not 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 life in sec. - cache any ldap queris
        CacheTTL => 0,
        Map => [
            # note: Login, Email and CustomerID needed!
            # var, frontend, storage, shown (1=always,2=lite), required, storage-type, http-link, readonly
            [ '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 ],
            [ 'UserCustomerID', 'CustomerID', 'o',               0, 1, 'var', '', 0 ],
            [ 'UserCustomerIDs', 'CustomerIDs', 'customerids',   1, 0, 'var', '', 0 ],
            [ 'UserPhone',      'Phone',      'telephoneNumber', 1, 0, 'var', '', 0 ],
        ],
    };

    $Self->{'SendmailModule'} = 'Kernel::System::Email::SMTP';
    $Self->{'SendmailModule::Host'} = 'localhost';
    $Self->{'SendmailModule::Port'} = '25';
    $Self->{'CustomerGroupSupport'} = '1';

    # ---------------------------------------------------- #
    # ---------------------------------------------------- #
    #                                                      #
    #           End of your own config options!!!          #
    #                                                      #
    # ---------------------------------------------------- #
    # ---------------------------------------------------- #
}

# ---------------------------------------------------- #
# needed system stuff (don't edit this)                #
# ---------------------------------------------------- #
use strict;
use warnings;

use vars qw(@ISA $VERSION);
use Kernel::Config::Defaults;
push (@ISA, 'Kernel::Config::Defaults');

use vars qw(@ISA $VERSION);
$VERSION = qw($Revision: 1.21 $)[1];

# -----------------------------------------------------#
  

Make sure to configure the PostgreSQL part and comment out the MySQL part, as well as fill in all the fields correctly. We’ll also use Apache::DBI to boost performance. Edit this file to uncomment these lines:

  [...]
use Apache::DBI ();
Apache::DBI->connect_on_init('DBI:mysql:otrs', 'otrs', 'password');
use DBI ();

# enable this if you use mysql
#use DBD::mysql ();
#use Kernel::System::DB::mysql;

# enable this if you use postgresql
use DBD::Pg ();
use Kernel::System::DB::postgresql;
[...]
  

All that’s left is to initialize the crontab:

  /opt/otrs/bin/Cron.sh start otrs
  

Your OTRS server is accessible via: http://server-otrs/otrs :-)

API

You might want to use the API for various reasons. Here’s an example for creating a Ticket and an Article (used for ticket responses):

  #!/usr/bin/perl

use strict;
use warnings;

# Load lib folders from OTRS directory
use lib "/opt/otrs";

# Load modules
use Kernel::Config;
use Kernel::System::Encode;
use Kernel::System::Log;
use Kernel::System::Time;
use Kernel::System::Main;
use Kernel::System::DB;
use Kernel::System::Ticket;
use DBI;
use Encode ;

# Load objects
my $ConfigObject = Kernel::Config->new();
my $EncodeObject = Kernel::System::Encode->new( ConfigObject => $ConfigObject, );

my $LogObject = Kernel::System::Log->new(
    ConfigObject => $ConfigObject,
    EncodeObject => $EncodeObject,
);

my $TimeObject = Kernel::System::Time->new(
    ConfigObject => $ConfigObject,
    LogObject    => $LogObject,
);

my $MainObject = Kernel::System::Main->new(
    ConfigObject => $ConfigObject,
    EncodeObject => $EncodeObject,
    LogObject    => $LogObject,
);

my $DBObject = Kernel::System::DB->new(
    ConfigObject => $ConfigObject,
    EncodeObject => $EncodeObject,
    LogObject    => $LogObject,
    MainObject   => $MainObject,
);

my $TicketObject = Kernel::System::Ticket->new(
    ConfigObject => $ConfigObject,
    LogObject    => $LogObject,
    DBObject     => $DBObject,
    MainObject   => $MainObject,
    TimeObject   => $TimeObject,
    EncodeObject => $EncodeObject,
);

# Encoding to avoir errors
my $subject = "My subject:-)";
Encode::encode( 'UTF-8', $subject ) or die("Cannot encode subject into UTF-8");

# Create Ticket
my $TicketID = $TicketObject->TicketCreate(
    Title			=> $subject, # now encoded in UTF-8
    CustomerID		        => 'pmavro',
    Queue			=> 'queue',
    Lock			=> 'unlock',
    Priority		        => '1 demande d\'information',
    State			=> 'new',
    Type			=> 'default',
    CustomerUser	        => 'pmavro',
    OwnerID			=> 1,
    UserID			=> 1,
);

# Create Article
my $ArticleID = $TicketObject->ArticleCreate(
    TicketID    => $TicketID,
    ArticleType => 'note-internal',    # email-external|email-internal|phone|fax|...
    SenderType  => 'agent',                           # agent|system|customer4
    From        => 'Some Agent <email@example.com>',  # not required but useful
    To          => 'Some Customer A <customer-a@example.com>',  # not required but useful
    Subject     => $subject,           # required
    Body        => 'the message text',                 # required
    Charset     => 'UTF-8',
    MimeType    => 'text/plain',
    HistoryType => 'OwnerUpdate',
    HistoryComment => 'Some free text!',
    UserID         => 1,
);
  

References

Last updated 31 Oct 2012, 15:12 +0200. history