Az OTRS nagyszámú úgynevezett „modulréteggel” rendelkezik, amely nagyon egyszerűvé teszi a rendszer kibővítését a meglévő kód foltozása nélkül. Egy példa erre a számelőállító mechanizmus a jegyeknél. Ez egy csatlakoztatható modulokkal rendelkező „modulréteg”, és ha szeretné, hozzáadhatja a saját egyéni számelőállító moduljait is. Nézzük meg részletesen a különböző rétegeket!
Számos ügyintézői hitelesítő modul létezik (DB, LDAP és HTTPBasicAuth),
amelyek az OTRS keretrendszerrel érkeznek. Lehetőség van saját hitelesítő
modulok fejlesztésére is. Az ügyintézői hitelesítő modulok a
Kernel/System/Auth/*.pm
alatt találhatók. Ezek
beállításáról további információkért nézze meg az adminisztrátori
kézikönyvet. Ezt követően egy egyszerű ügyintézői hitelesítő modul példája
található. Mentse el a Kernel/System/Auth/Simple.pm
helyre. Mindössze három függvényre van szüksége: new()
,
GetOption()
és Auth()
. Adja vissza az uid-t, és
ezután a hitelesítés rendben van.
A felületosztály neve Kernel::System::Auth
. A példa
ügyintézői hitelesítés hívható
Kernel::System::Auth::CustomAuth
néven. Lent találhat egy
példát.
# -- # Kernel/System/Auth/CustomAuth.pm - provides the CustomAuth authentication # based on Martin Edenhofer's Kernel::System::Auth::DB # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # ID: CustomAuth.pm,v 1.1 2010/05/10 15:30:34 fk Exp $ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::Auth::CustomAuth; use strict; use warnings; use Authen::CustomAuth; sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # check needed objects for (qw(LogObject ConfigObject DBObject)) { $Self->{$_} = $Param{$_} || die "No $_!"; } # Debug 0=off 1=on $Self->{Debug} = 0; # get config $Self->{Die} = $Self->{ConfigObject}->Get( 'AuthModule::CustomAuth::Die' . $Param{Count} ); # get user table $Self->{CustomAuthHost} = $Self->{ConfigObject}->Get( 'AuthModule::CustomAuth::Host' . $Param{Count} ) || die "Need AuthModule::CustomAuth::Host$Param{Count}."; $Self->{CustomAuthSecret} = $Self->{ConfigObject}->Get( 'AuthModule::CustomAuth::Password' . $Param{Count} ) || die "Need AuthModule::CustomAuth::Password$Param{Count}."; return $Self; } sub GetOption { my ( $Self, %Param ) = @_; # check needed stuff if ( !$Param{What} ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need What!" ); return; } # module options my %Option = ( PreAuth => 0, ); # return option return $Option{ $Param{What} }; } sub Auth { my ( $Self, %Param ) = @_; # check needed stuff if ( !$Param{User} ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need User!" ); return; } # get params my $User = $Param{User} || ''; my $Pw = $Param{Pw} || ''; my $RemoteAddr = $ENV{REMOTE_ADDR} || 'Got no REMOTE_ADDR env!'; my $UserID = ''; my $GetPw = ''; # just in case for debug! if ( $Self->{Debug} > 0 ) { $Self->{LogObject}->Log( Priority => 'notice', Message => "User: '$User' tried to authenticate with Pw: '$Pw' ($RemoteAddr)", ); } # just a note if ( !$User ) { $Self->{LogObject}->Log( Priority => 'notice', Message => "No User given!!! (REMOTE_ADDR: $RemoteAddr)", ); return; } # just a note if ( !$Pw ) { $Self->{LogObject}->Log( Priority => 'notice', Message => "User: $User authentication without Pw!!! (REMOTE_ADDR: $RemoteAddr)", ); return; } # Create a RADIUS object my $CustomAuth = Authen::CustomAuth->new( Host => $Self->{CustomAuthHost}, Secret => $Self->{CustomAuthecret}, ); if ( !$CustomAuth ) { if ( $Self->{Die} ) { die "Can't connect to $Self->{CustomAuthHost}: $@"; } else { $Self->{LogObject}->Log( Priority => 'error', Message => "Can't connect to $Self->{CustomAuthHost}: $@", ); return; } } my $AuthResult = $CustomAuth->check_pwd( $User, $Pw ); # login note if ( defined($AuthResult) && $AuthResult == 1 ) { $Self->{LogObject}->Log( Priority => 'notice', Message => "User: $User authentication ok (REMOTE_ADDR: $RemoteAddr).", ); return $User; } # just a note else { $Self->{LogObject}->Log( Priority => 'notice', Message => "User: $User authentication with wrong Pw!!! (REMOTE_ADDR: $RemoteAddr)" ); return; } } 1;
Szükség van az egyéni ügyintézői hitelesítés modul bekapcsolására. Ezt a lenti Perl beállítás használatával lehet megtenni. Nem ajánlott az XML beállítás használata, mert kizárhatja magát a rendszerbeállításokon keresztül.
$Self->{'AuthModule'} = 'Kernel::System::Auth::CustomAuth';
Létezik egy LDAP hitelesítés szinkronizációs modul, amely az OTRS
keretrendszerrel érkezik. Lehetőség van saját hitelesítés modulok
fejlesztésére is. A hitelesítés szinkronizációs modulok a
Kernel/System/Auth/Sync/*.pm
alatt találhatók. A
beállításaikkal kapcsolatban további információkért nézze meg az
adminisztrációs kézikönyvet. A következőkben egy hitelesítés szinkronizációs
modul példája található. Mentse el a
Kernel/System/Auth/Sync/CustomAuthSync.pm
fájlba. Mindössze két függvényre van szüksége: new()
és
Sync()
. Adjon vissza 1-et, és ezután a szinkronizáció rendben
van.
A felületosztály neve Kernel::System::Auth
. A példa
ügyintézői hitelesítés hívható
Kernel::System::Auth::Sync::CustomAuthSync
néven. Lent
találhat egy példát.
# -- # Kernel/System/Auth/Sync/CustomAuthSync.pm - provides the CustomAuthSync # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # Id: CustomAuthSync.pm,v 1.9 2010/03/25 14:42:45 martin Exp $ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::Auth::Sync::CustomAuthSync; use strict; use warnings; use Net::LDAP; sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # check needed objects for (qw(LogObject ConfigObject DBObject UserObject GroupObject EncodeObject)) { $Self->{$_} = $Param{$_} || die "No $_!"; } # Debug 0=off 1=on $Self->{Debug} = 0; ... return $Self; } sub Sync { my ( $Self, %Param ) = @_; # check needed stuff for (qw(User)) { if ( !$Param{$_} ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" ); return; } } ... return 1; }
Be kell kapcsolnia az egyéni szinkronizációs modult. Ezt a lenti Perl beállítás használatával lehet megtenni. Nem ajánlott az XML beállítás használata, mert az lehetővé teheti, hogy kizárja magát a rendszerbeállításokon keresztül.
$Self->{'AuthSyncModule'} = 'Kernel::System::Auth::Sync::LDAP';
Hasznos szinkronizációs megvalósítás lehet egy SOAP vagy egy RADIUS háttérprogram.
Számos ügyfél hitelesítő modul létezik (DB, LDAP és HTTPBasicAuth), amelyek
az OTRS keretrendszerrel érkeznek. Lehetőség van saját hitelesítő modulok
fejlesztésére is. Az ügyfél hitelesítő modulok a
Kernel/System/CustomerAuth/*.pm
alatt találhatók. Ezek
beállításáról további információkért nézze meg az adminisztrátori
kézikönyvet. Ezt követően egy egyszerű ügyfél hitelesítő modul példája
található. Mentse el a
Kernel/System/CustomerAuth/Simple.pm
helyre. Mindössze
három függvényre van szüksége: new()
, GetOption()
és Auth()
. Adja vissza az uid-t, és ezután a hitelesítés
rendben van.
A felületosztály neve Kernel::System::CustomerAuth
. A
példa ügyfél hitelesítés hívható
Kernel::System::CustomerAuth::CustomAuth
néven. Lent
találhat egy példát.
# -- # Kernel/System/CustomerAuth/CustomAuth.pm - provides the custom Authentication # based on Martin Edenhofer's Kernel::System::Auth::DB # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # Id: CustomAuth.pm,v 1.11 2009/09/22 15:16:05 mb Exp $ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::CustomerAuth::CustomAuth; use strict; use warnings; use Authen::CustomAuth; sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # check needed objects for (qw(LogObject ConfigObject DBObject)) { $Self->{$_} = $Param{$_} || die "No $_!"; } # Debug 0=off 1=on $Self->{Debug} = 0; # get config $Self->{Die} = $Self->{ConfigObject}->Get( 'Customer::AuthModule::CustomAuth::Die' . $Param{Count} ); # get user table $Self->{CustomAuthHost} = $Self->{ConfigObject}->Get( 'Customer::AuthModule::CustomAuth::Host' . $Param{Count} ) || die "Need Customer::AuthModule::CustomAuth::Host$Param{Count} in Kernel/Config.pm"; $Self->{CustomAuthSecret} = $Self->{ConfigObject}->Get( 'Customer::AuthModule::CustomAuth::Password' . $Param{Count} ) || die "Need Customer::AuthModule::CustomAuth::Password$Param{Count} in Kernel/Config.pm"; return $Self; } sub GetOption { my ( $Self, %Param ) = @_; # check needed stuff if ( !$Param{What} ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need What!" ); return; } # module options my %Option = ( PreAuth => 0, ); # return option return $Option{ $Param{What} }; } sub Auth { my ( $Self, %Param ) = @_; # check needed stuff if ( !$Param{User} ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need User!" ); return; } # get params my $User = $Param{User} || ''; my $Pw = $Param{Pw} || ''; my $RemoteAddr = $ENV{REMOTE_ADDR} || 'Got no REMOTE_ADDR env!'; my $UserID = ''; my $GetPw = ''; # just in case for debug! if ( $Self->{Debug} > 0 ) { $Self->{LogObject}->Log( Priority => 'notice', Message => "User: '$User' tried to authentificate with Pw: '$Pw' ($RemoteAddr)", ); } # just a note if ( !$User ) { $Self->{LogObject}->Log( Priority => 'notice', Message => "No User given!!! (REMOTE_ADDR: $RemoteAddr)", ); return; } # just a note if ( !$Pw ) { $Self->{LogObject}->Log( Priority => 'notice', Message => "User: $User Authentication without Pw!!! (REMOTE_ADDR: $RemoteAddr)", ); return; } # Create a custom object my $CustomAuth = Authen::CustomAuth->new( Host => $Self->{CustomAuthHost}, Secret => $Self->{CustomAuthSecret}, ); if ( !$CustomAuth ) { if ( $Self->{Die} ) { die "Can't connect to $Self->{CustomAuthHost}: $@"; } else { $Self->{LogObject}->Log( Priority => 'error', Message => "Can't connect to $Self->{CustomAuthHost}: $@", ); return; } } my $AuthResult = $CustomAuth->check_pwd( $User, $Pw ); # login note if ( defined($AuthResult) && $AuthResult == 1 ) { $Self->{LogObject}->Log( Priority => 'notice', Message => "User: $User Authentication ok (REMOTE_ADDR: $RemoteAddr).", ); return $User; } # just a note else { $Self->{LogObject}->Log( Priority => 'notice', Message => "User: $User Authentication with wrong Pw!!! (REMOTE_ADDR: $RemoteAddr)" ); return; } } 1;
Szükség van az egyéni ügyfél hitelesítő modul bekapcsolására. Ezt a lenti XML beállítás használatával lehet megtenni.
<ConfigItem Name="AuthModule" Required="1" Valid="1"> <Description Lang="en">Module to authenticate customers.</Description> <Description Lang="hu">Egy modul az ügyfelek hitelesítéséhez.</Description> <Group>Framework</Group> <SubGroup>Frontend::CustomerAuthAuth</SubGroup> <Setting> <Option Location="Kernel/System/CustomerAuth/*.pm" SelectedID="Kernel::System::CustomerAuth::CustomAuth"></Option> </Setting> </ConfigItem>
Létezik egy DB ügyfél-felhasználó beállítások modul, amely az OTRS
keretrendszerrel érkezik. Lehetőség van saját ügyfél-felhasználó beállítási
modulok fejlesztésére is. Az ügyfél-felhasználó beállítási modulok a
Kernel/System/CustomerUser/Preferences/*.pm
alatt
találhatók. Ezek beállításáról további információkért nézze meg az
adminisztrátori kézikönyvet. A következőkben egy ügyfél-felhasználó
beállítások modul példája található. Mentse el a
Kernel/System/CustomerUser/Preferences/Custom.pm
helyre. Mindössze négy függvényre van szüksége: new()
,
SearchPreferences()
, SetPreferences()
és
GetPreferences()
.
A felületosztály neve Kernel::System::CustomerUser
. A
példa ügyfél-felhasználó beállítások hívhatók
Kernel::System::CustomerUser::Preferences::Custom
néven. Lent találhat egy példát.
# -- # Kernel/System/CustomerUser/Preferences/Custom.pm - some customer user functions # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # Id: Custom.pm,v 1.20 2009/10/07 20:41:50 martin Exp $ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::CustomerUser::Preferences::Custom; use strict; use warnings; use vars qw(@ISA $VERSION); sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # check needed objects for my $Object (qw(DBObject ConfigObject LogObject)) { $Self->{$Object} = $Param{$Object} || die "Got no $Object!"; } # preferences table data $Self->{PreferencesTable} = $Self->{ConfigObject}->Get('CustomerPreferences')->{Params}->{Table} || 'customer_preferences'; $Self->{PreferencesTableKey} = $Self->{ConfigObject}->Get('CustomerPreferences')->{Params}->{TableKey} || 'preferences_key'; $Self->{PreferencesTableValue} = $Self->{ConfigObject}->Get('CustomerPreferences')->{Params}->{TableValue} || 'preferences_value'; $Self->{PreferencesTableUserID} = $Self->{ConfigObject}->Get('CustomerPreferences')->{Params}->{TableUserID} || 'user_id'; return $Self; } sub SetPreferences { my ( $Self, %Param ) = @_; my $UserID = $Param{UserID} || return; my $Key = $Param{Key} || return; my $Value = defined( $Param{Value} ) ? $Param{Value} : ''; # delete old data return if !$Self->{DBObject}->Do( SQL => "DELETE FROM $Self->{PreferencesTable} WHERE " . " $Self->{PreferencesTableUserID} = ? AND $Self->{PreferencesTableKey} = ?", Bind => [ \$UserID, \$Key ], ); $Value .= 'Custom'; # insert new data return if !$Self->{DBObject}->Do( SQL => "INSERT INTO $Self->{PreferencesTable} ($Self->{PreferencesTableUserID}, " . " $Self->{PreferencesTableKey}, $Self->{PreferencesTableValue}) " . " VALUES (?, ?, ?)", Bind => [ \$UserID, \$Key, \$Value ], ); return 1; } sub GetPreferences { my ( $Self, %Param ) = @_; my $UserID = $Param{UserID} || return; my %Data; # get preferences return if !$Self->{DBObject}->Prepare( SQL => "SELECT $Self->{PreferencesTableKey}, $Self->{PreferencesTableValue} " . " FROM $Self->{PreferencesTable} WHERE $Self->{PreferencesTableUserID} = ?", Bind => [ \$UserID ], ); while ( my @Row = $Self->{DBObject}->FetchrowArray() ) { $Data{ $Row[0] } = $Row[1]; } # return data return %Data; } sub SearchPreferences { my ( $Self, %Param ) = @_; my %UserID; my $Key = $Param{Key} || ''; my $Value = $Param{Value} || ''; # get preferences my $SQL = "SELECT $Self->{PreferencesTableUserID}, $Self->{PreferencesTableValue} " . " FROM " . " $Self->{PreferencesTable} " . " WHERE " . " $Self->{PreferencesTableKey} = '" . $Self->{DBObject}->Quote($Key) . "'" . " AND " . " LOWER($Self->{PreferencesTableValue}) LIKE LOWER('" . $Self->{DBObject}->Quote( $Value, 'Like' ) . "')"; return if !$Self->{DBObject}->Prepare( SQL => $SQL ); while ( my @Row = $Self->{DBObject}->FetchrowArray() ) { $UserID{ $Row[0] } = $Row[1]; } # return data return %UserID; } 1;
Szükség van az egyéni ügyfél-felhasználó beállítások modul bekapcsolására. Ezt a lenti XML beállítás használatával lehet megtenni.
<ConfigItem Name="CustomerPreferences" Required="1" Valid="1"> <Description Lang="en">Parameters for the customer preference table.</Description> <Description Lang="hu">Paraméterek az ügyfél beállításainak táblájához.</Description> <Group>Framework</Group> <SubGroup>Frontend::Customer::Preferences</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::System::CustomerUser::Preferences::Custom</Item> <Item Key="Params"> <Hash> <Item Key="Table">customer_preferences</Item> <Item Key="TableKey">preferences_key</Item> <Item Key="TableValue">preferences_value</Item> <Item Key="TableUserID">user_id</Item> </Hash> </Item> </Hash> </Setting> </ConfigItem>
Létezik egy DB várólista beállítások modul, amely az OTRS keretrendszerrel
érkezik. Lehetőség van saját várólista beállítási modulok fejlesztésére
is. A várólista beállítási modulok a
Kernel/System/Queue/*.pm
alatt találhatók. Ezek
beállításáról további információkért nézze meg az adminisztrátori
kézikönyvet. A következőkben egy várólista beállítások modul példája
található. Mentse el a
Kernel/System/Queue/PreferencesCustom.pm
helyre. Mindössze három függvényre van szüksége: new()
,
QueuePreferencesSet()
és
QueuePreferencesGet()
. Adjon vissza 1-et, és ezután a
szinkronizáció rendben van.
A felületosztály neve Kernel::System::Queue
. A példa
várólista beállítások hívhatók
Kernel::System::Queue::PreferencesCustom
néven. Lent
találhat egy példát.
# -- # Kernel/System/Queue/PreferencesCustom.pm - some user functions # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # Id: PreferencesCustom.pm,v 1.5 2009/02/16 11:47:34 tr Exp $ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::Queue::PreferencesCustom; use strict; use warnings; use vars qw(@ISA $VERSION); sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # check needed objects for (qw(DBObject ConfigObject LogObject)) { $Self->{$_} = $Param{$_} || die "Got no $_!"; } # preferences table data $Self->{PreferencesTable} = 'queue_preferences'; $Self->{PreferencesTableKey} = 'preferences_key'; $Self->{PreferencesTableValue} = 'preferences_value'; $Self->{PreferencesTableQueueID} = 'queue_id'; return $Self; } sub QueuePreferencesSet { my ( $Self, %Param ) = @_; # check needed stuff for (qw(QueueID Key Value)) { if ( !defined( $Param{$_} ) ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" ); return; } } # delete old data return if !$Self->{DBObject}->Do( SQL => "DELETE FROM $Self->{PreferencesTable} WHERE " . "$Self->{PreferencesTableQueueID} = ? AND $Self->{PreferencesTableKey} = ?", Bind => [ \$Param{QueueID}, \$Param{Key} ], ); $Self->{PreferencesTableValue} .= 'PreferencesCustom'; # insert new data return $Self->{DBObject}->Do( SQL => "INSERT INTO $Self->{PreferencesTable} ($Self->{PreferencesTableQueueID}, " . " $Self->{PreferencesTableKey}, $Self->{PreferencesTableValue}) " . " VALUES (?, ?, ?)", Bind => [ \$Param{QueueID}, \$Param{Key}, \$Param{Value} ], ); } sub QueuePreferencesGet { my ( $Self, %Param ) = @_; # check needed stuff for (qw(QueueID)) { if ( !$Param{$_} ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" ); return; } } # check if queue preferences are available if ( !$Self->{ConfigObject}->Get('QueuePreferences') ) { return; } # get preferences return if !$Self->{DBObject}->Prepare( SQL => "SELECT $Self->{PreferencesTableKey}, $Self->{PreferencesTableValue} " . " FROM $Self->{PreferencesTable} WHERE $Self->{PreferencesTableQueueID} = ?", Bind => [ \$Param{QueueID} ], ); my %Data; while ( my @Row = $Self->{DBObject}->FetchrowArray() ) { $Data{ $Row[0] } = $Row[1]; } # return data return %Data; } 1;
Szükség van az egyéni várólista beállítások modul bekapcsolására. Ezt a lenti XML beállítás használatával lehet megtenni.
<ConfigItem Name="Queue::PreferencesModule" Required="1" Valid="1"> <Description Lang="en">Default queue preferences module.</Description> <Description Lang="hu">Alapértelmezett várólista beállítások modul.</Description> <Group>Ticket</Group> <SubGroup>Frontend::Queue::Preferences</SubGroup> <Setting> <String Regex="">Kernel::System::Queue::PreferencesCustom</String> </Setting> </ConfigItem>
Hasznos beállítások megvalósítás lehet egy SOAP vagy egy RADIUS háttérprogram.
Létezik egy DB szolgáltatás beállítások modul, amely az OTRS
keretrendszerrel érkezik. Lehetőség van saját szolgáltatás beállítási
modulok fejlesztésére is. A szolgáltatás beállítási modulok a
Kernel/System/Service/*.pm
alatt találhatók. Ezek
beállításáról további információkért nézze meg az adminisztrátori
kézikönyvet. A következőkben egy szolgáltatás beállítások modul példája
található. Mentse el a
Kernel/System/Service/PreferencesCustom.pm
helyre. Mindössze három függvényre van szüksége: new()
,
ServicePreferencesSet()
és
ServicePreferencesGet()
. Adjon vissza 1-et, és ezután a
szinkronizáció rendben van.
A felületosztály neve Kernel::System::Service
. A példa
szolgáltatás beállítások hívhatók
Kernel::System::Service::PreferencesCustom
néven. Lent
találhat egy példát.
# -- # Kernel/System/Service/PreferencesCustom - some user functions # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # Id: PreferencesCustom.pm,v 1.2 2009/02/16 11:47:34 tr Exp $ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::Service::PreferencesCustom; use strict; use warnings; use vars qw(@ISA $VERSION); sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # check needed objects for (qw(DBObject ConfigObject LogObject)) { $Self->{$_} = $Param{$_} || die "Got no $_!"; } # preferences table data $Self->{PreferencesTable} = 'service_preferences'; $Self->{PreferencesTableKey} = 'preferences_key'; $Self->{PreferencesTableValue} = 'preferences_value'; $Self->{PreferencesTableServiceID} = 'service_id'; return $Self; } sub ServicePreferencesSet { my ( $Self, %Param ) = @_; # check needed stuff for (qw(ServiceID Key Value)) { if ( !defined( $Param{$_} ) ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" ); return; } } # delete old data return if !$Self->{DBObject}->Do( SQL => "DELETE FROM $Self->{PreferencesTable} WHERE " . "$Self->{PreferencesTableServiceID} = ? AND $Self->{PreferencesTableKey} = ?", Bind => [ \$Param{ServiceID}, \$Param{Key} ], ); $Self->{PreferencesTableValue} .= 'PreferencesCustom'; # insert new data return $Self->{DBObject}->Do( SQL => "INSERT INTO $Self->{PreferencesTable} ($Self->{PreferencesTableServiceID}, " . " $Self->{PreferencesTableKey}, $Self->{PreferencesTableValue}) " . " VALUES (?, ?, ?)", Bind => [ \$Param{ServiceID}, \$Param{Key}, \$Param{Value} ], ); } sub ServicePreferencesGet { my ( $Self, %Param ) = @_; # check needed stuff for (qw(ServiceID)) { if ( !$Param{$_} ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" ); return; } } # check if service preferences are available if ( !$Self->{ConfigObject}->Get('ServicePreferences') ) { return; } # get preferences return if !$Self->{DBObject}->Prepare( SQL => "SELECT $Self->{PreferencesTableKey}, $Self->{PreferencesTableValue} " . " FROM $Self->{PreferencesTable} WHERE $Self->{PreferencesTableServiceID} = ?", Bind => [ \$Param{ServiceID} ], ); my %Data; while ( my @Row = $Self->{DBObject}->FetchrowArray() ) { $Data{ $Row[0] } = $Row[1]; } # return data return %Data; } 1;
Szükség van az egyéni szolgáltatás beállítások modul bekapcsolására. Ezt a lenti XML beállítás használatával lehet megtenni.
<ConfigItem Name="Service::PreferencesModule" Required="1" Valid="1"> <Description Lang="en">Default service preferences module.</Description> <Description Lang="hu">Alapértelmezett szolgáltatás beállítások modul.</Description> <Group>Ticket</Group> <SubGroup>Frontend::Service::Preferences</SubGroup> <Setting> <String Regex="">Kernel::System::Service::PreferencesCustom</String> </Setting> </ConfigItem>
Hasznos beállítások megvalósítás lehet egy SOAP vagy egy RADIUS háttérprogram.
Létezik egy DB SLA beállítások modul, amely az OTRS keretrendszerrel
érkezik. Lehetőség van saját SLA beállítási modulok fejlesztésére is. Az SLA
beállítási modulok a Kernel/System/SLA/*.pm
alatt
találhatók. Ezek beállításáról további információkért nézze meg az
adminisztrátori kézikönyvet. A következőkben egy SLA beállítások modul
példája található. Mentse el a
Kernel/System/SLA/PreferencesCustom.pm
helyre. Mindössze három függvényre van szüksége: new()
,
SLAPreferencesSet()
és
SLAPreferencesGet()
. Győződjön meg arról, hogy a függvény 1-et
adjon vissza.
A felületosztály neve Kernel::System::SLA
. A példa SLA
beállítások hívhatók
Kernel::System::SLA::PreferencesCustom
néven. Lent
találhat egy példát.
# -- # Kernel/System/SLA/PreferencesCustom.pm - some user functions # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::SLA::PreferencesCustom; use strict; use warnings; use vars qw(@ISA); sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # check needed objects for (qw(DBObject ConfigObject LogObject)) { $Self->{$_} = $Param{$_} || die "Got no $_!"; } # preferences table data $Self->{PreferencesTable} = 'sla_preferences'; $Self->{PreferencesTableKey} = 'preferences_key'; $Self->{PreferencesTableValue} = 'preferences_value'; $Self->{PreferencesTableSLAID} = 'sla_id'; return $Self; } sub SLAPreferencesSet { my ( $Self, %Param ) = @_; # check needed stuff for (qw(SLAID Key Value)) { if ( !defined( $Param{$_} ) ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" ); return; } } # delete old data return if !$Self->{DBObject}->Do( SQL => "DELETE FROM $Self->{PreferencesTable} WHERE " . "$Self->{PreferencesTableSLAID} = ? AND $Self->{PreferencesTableKey} = ?", Bind => [ \$Param{SLAID}, \$Param{Key} ], ); $Self->{PreferencesTableValue} .= 'PreferencesCustom'; # insert new data return $Self->{DBObject}->Do( SQL => "INSERT INTO $Self->{PreferencesTable} ($Self->{PreferencesTableSLAID}, " . " $Self->{PreferencesTableKey}, $Self->{PreferencesTableValue}) " . " VALUES (?, ?, ?)", Bind => [ \$Param{SLAID}, \$Param{Key}, \$Param{Value} ], ); } sub SLAPreferencesGet { my ( $Self, %Param ) = @_; # check needed stuff for (qw(SLAID)) { if ( !$Param{$_} ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need $_!" ); return; } } # check if SLA preferences are available if ( !$Self->{ConfigObject}->Get('SLAPreferences') ) { return; } # get preferences return if !$Self->{DBObject}->Prepare( SQL => "SELECT $Self->{PreferencesTableKey}, $Self->{PreferencesTableValue} " . " FROM $Self->{PreferencesTable} WHERE $Self->{PreferencesTableSLAID} = ?", Bind => [ \$Param{SLAID} ], ); my %Data; while ( my @Row = $Self->{DBObject}->FetchrowArray() ) { $Data{ $Row[0] } = $Row[1]; } # return data return %Data; } 1;
Szükség van az egyéni SLA beállítások modul bekapcsolására. Ezt a lenti XML beállítás használatával lehet megtenni.
<ConfigItem Name="SLA::PreferencesModule" Required="1" Valid="1"> <Description Translatable="1">Default SLA preferences module.</Description> <Group>Ticket</Group> <SubGroup>Frontend::SLA::Preferences</SubGroup> <Setting> <String Regex="">Kernel::System::SLA::PreferencesCustom</String> </Setting> </ConfigItem>
Létezik egy globális naplózó felület az OTRS-hez, amely a saját naplózó háttérprogramok létrehozásának lehetőségét biztosítja.
Egy saját naplózó háttérprogram írása olyan egyszerű, mint újra
megvalósítani a Kernel::System::Log::Log()
metódust.
Ebben a kis példában írni fogunk egy kicsi fájl naplózó háttérprogramot,
amely hasonlóan működik mint a Kernel::System::Log::File
,
de egy szöveget fűz minden naplóbejegyzés elé.
# -- # Kernel/System/Log/CustomFile.pm - file log backend # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::Log::CustomFile; use strict; use warnings; umask "002"; sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # get needed objects for (qw(ConfigObject EncodeObject)) { if ( $Param{$_} ) { $Self->{$_} = $Param{$_}; } else { die "Got no $_!"; } } # get logfile location $Self->{LogFile} = '/var/log/CustomFile.log'; # set custom prefix $Self->{CustomPrefix} = 'CustomFileExample'; # Fixed bug# 2265 - For IIS we need to create a own error log file. # Bind stderr to log file, because IIS do print stderr to web page. if ( $ENV{SERVER_SOFTWARE} && $ENV{SERVER_SOFTWARE} =~ /^microsoft\-iis/i ) { if ( !open STDERR, '>>', $Self->{LogFile} . '.error' ) { print STDERR "ERROR: Can't write $Self->{LogFile}.error: $!"; } } return $Self; } sub Log { my ( $Self, %Param ) = @_; my $FH; # open logfile if ( !open $FH, '>>', $Self->{LogFile} ) { # print error screen print STDERR "\n"; print STDERR " >> Can't write $Self->{LogFile}: $! <<\n"; print STDERR "\n"; return; } # write log file $Self->{EncodeObject}->SetIO($FH); print $FH '[' . localtime() . ']'; if ( lc $Param{Priority} eq 'debug' ) { print $FH "[Debug][$Param{Module}][$Param{Line}] $Self->{CustomPrefix} $Param{Message}\n"; } elsif ( lc $Param{Priority} eq 'info' ) { print $FH "[Info][$Param{Module}] $Self->{CustomPrefix} $Param{Message}\n"; } elsif ( lc $Param{Priority} eq 'notice' ) { print $FH "[Notice][$Param{Module}] $Self->{CustomPrefix} $Param{Message}\n"; } elsif ( lc $Param{Priority} eq 'error' ) { print $FH "[Error][$Param{Module}][$Param{Line}] $Self->{CustomPrefix} $Param{Message}\n"; } else { # print error messages to STDERR print STDERR "[Error][$Param{Module}] $Self->{CustomPrefix} Priority: '$Param{Priority}' not defined! Message: $Param{Message}\n"; # and of course to logfile print $FH "[Error][$Param{Module}] $Self->{CustomPrefix} Priority: '$Param{Priority}' not defined! Message: $Param{Message}\n"; } # close file handle close $FH; return 1; } 1;
Az egyéni naplózómodul bekapcsolásához az adminisztrátor beállíthatja kézzel
a meglévő LogModule
konfigurációs elemet a
Kernel::System::Log::CustomFile
osztályhoz. Ennek
automatikus megvalósításához megadhat egy XML beállítófájlt, amely
felülbírálja az alapértelmezett beállítást.
<ConfigItem Name="LogModule" Required="1" Valid="1"> <Description Translatable="1">Set Kernel::System::Log::CustomFile as default logging backend.</Description> <Group>Framework</Group> <SubGroup>Core::Log</SubGroup> <Setting> <Option Location="Kernel/System/Log/*.pm" SelectedID="Kernel::System::Log::CustomFile"></Option> </Setting> </ConfigItem>
Hasznos naplózó háttérprogram lehet egy webszolgáltatásba vagy egy titkosított fájlba történő naplózás.
A kimenetszűrők lehetővé teszik a HTML módosítását röptében. A bevált
gyakorlat a kimenetszűrők használata a .tt
fájlok
közvetlen módosítása helyett. Három jó ok létezik erre. Amikor ugyanazt az
átdolgozást kell alkalmazni számos előtétprogram modulon, akkor az
átdolgozást csak egyszer kell megvalósítani. A második előnye, hogy amikor
az OTRS-t frissítik, akkor megvan az esély arra, hogy a szűrőt nem kell
frissíteni, ha a hozzá tartozó minta nem változott. Amikor két kiterjesztés
ugyanazt a fájlt módosítja, akkor ütközés lép fel a második csomag
telepítése során. Ez az ütközés feloldható két kimenetszűrő használatával,
amelyek ugyanazt az előtétprogram modult módosítják.
Három különböző fajta kimenetszűrő létezik. Ezek a HTML tartalom előállításának különböző szakaszaiban aktívak.
Ezek a szűrők lehetővé teszik egy sablon kimenetének módosítást, miután az megjelenítésre került.
A tartalom lefordításához futtathatja közvetlenül a
$LayoutObject->Translate()
függvényt. Ha egyéb
sablonszolgáltatásokra van szüksége, akkor egyszerűen határozzon meg egy kis
sablonfájlt a kimenetszűrőhöz, és használja azt a tartalom megjelenítéséhez,
mielőtt beültetné azt a fő adatokba. Néhány esetben hasznos lehet a jQuery
DOM műveletek használata is a képernyőn lévő tartalom sorrendjének
megváltoztatásához vagy cseréjéhez a reguláris kifejezések használata
helyett. Ebben az esetben láthatatlan tartalomként kellene beültetnie az új
kódot valahova az oldalba (például a Hidden
osztállyal),
majd ezután áthelyezni a jQuery használatával a megfelelő helyre a DOM-ban,
és megjeleníteni azt.
Az utó-kimenetszűrők használatának megkönnyítéséhez létezik egy mechanizmus is a HTML megjegyzéshorgok lekéréséhez bizonyos sablonoknál vagy blokkoknál. Hozzáadhatja a modulbeállító XML-be a következőhöz hasonlóan:
<ConfigItem Name="Frontend::Template::GenerateBlockHooks###100-OTRSBusiness-ContactWithData" Required="1" Valid="1"> <Description Translatable="1">Generate HTML comment hooks for the specified blocks so that filters can use them.</Description> <Group>OTRSBusiness</Group> <SubGroup>Core</SubGroup> <Setting> <Hash> <Item Key="AgentTicketZoom"> <Array> <Item>CustomerTable</Item> </Array> </Item> </Hash> </Setting> </ConfigItem>
Ez azt fogja okozni, hogy az AgentTicketZoom.tt
fájlban
lévő CustomerTable
blokk át lesz alakítva a HTML
megjegyzésekben minden alkalommal, amikor megjelenítésre kerül:
<!--HookStartCustomerTable--> ... blokk kimenet ... <!--HookEndCustomerTable-->
Ezzel a mechanizmussal minden csomag csak azokat a blokkhorgokat kérheti, amelyekre szüksége van, és következetesen kerülnek megjelenítésre. Ezek a HTML megjegyzések használhatók ezután a kimenetszűrőben az egyszerű reguláris kifejezés illesztéshez.
Ez a fajta szűrő lehetővé teszi a teljes HTML kimenet feldolgozását a kérésnél közvetlenül azelőtt, hogy kiküldésre kerül a böngészőnek. Ez globális átalakításokhoz használható.
Ez a fajta kimenetszűrő egy bővítmény a
Kernel::Output::HTML::Layout::Ascii2HTML()
metódushoz, és
csak akkor aktív, amikor a LinkFeature
paraméter 1-re van
állítva. Így a FilterText
kimenetszűrők jelenleg csak az
egyszerű szöveges bejegyzések törzsének megjelenítésénél aktívak. Az
egyszerű szöveges bejegyzéseket a bejövő nem HTML levelek állítják elő,
illetve amikor az OTRS úgy van beállítva, hogy ne használja a Rich Text
szolgáltatást az előtétprogramon.
Ez egy FilterElementPost
kimenetszűrővel valósítható meg.
Használjon egy FilterElementPost
szűrőt ehhez a
szolgáltatáshoz. A választható szolgáltatások listája a feldolgozott
sablonkimenetből dolgozható fel. A többszintű választás a
szolgáltatáslistából építhető fel, és szúrható be a sablontartalomba. Egy
FilterElementPost
kimenetszűrőt kell használni ehhez.
Egy biotechnológiai vállalat IPI00217472 formátumú génneveket használ az
egyszerű szöveges bejegyzésekben. Egy FilterText
kimenetszűrő használható a szekvencia-adatbázisra mutató hivatkozások
létrehozásához a génneveknél, például
http://srs.ebi.ac.uk/srsbin/cgi-bin/wgetz?-e+[IPI-acc:IPI00217472]+-vn+2
formában.
Minden FilterElementPost
kimenetszűrő felépítésre és
futtatásra kerül minden olyan beállított sablonnál, amely szükséges az
aktuális kéréshez. Így a kimenetszűrő alacsony teljesítménye vagy a szűrők
nagy száma komolyan csökkentheti a teljesítményt.
A rugalmasság növelésének érdekében az érintett sablonok listáját be kell állítani a rendszerbeállításokban.
A belső statisztikamoduloknak két különböző típusa létezik - dinamikus és statikus. Ez a szakasz azt írja le, hogy az ilyen statisztikamodulok hogyan fejleszthetők.
A statikus statisztikamodulokkal ellentétben a dinamikus statisztikák beállíthatók az OTRS webes felületén keresztül. Ebben a szakaszban egy egyszerű statisztikamodul kerül fejlesztésre. Minden egyes dinamikus statisztikamodulnak meg kell valósítania ezeket a szubrutinokat:
new
GetObjectName
GetObjectAttributes
ExportWrapper
ImportWrapper
Továbbá a modulnak meg kell valósítania vagy a
GetStatElement
, vagy a GetStatTable
rutint. És ha az eredménytábla fejlécsorát is meg kell változtatni, akkor
egy úgynevezett GetHeaderLine
szubrutint is fejleszteni
kell.
Ebben a szakaszban egy minta statisztikamodul lesz megjelenítve, és minden szubrutin elmagyarázásra kerül.
# -- # Kernel/System/Stats/Dynamic/DynamicStatsTemplate.pm - all advice functions # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::Stats::Dynamic::DynamicStatsTemplate; use strict; use warnings; use Kernel::System::Queue; use Kernel::System::State; use Kernel::System::Ticket;
Ez egy gyakori sabloncsomag, amely megtalálható a szokásos OTRS
modulokban. Az osztály/csomag neve a package
kulcsszón
keresztül van deklarálva. Ezután a szükséges modulok használatának megadása
következik a use
kulcsszóval.
sub new { my ( $Type, %Param ) = @_; # új kivonat lefoglalása az objektumhoz my $Self = {}; bless( $Self, $Type ); # a szükséges objektumok ellenőrzése for my $Object ( qw(DBObject ConfigObject LogObject UserObject TimeObject MainObject EncodeObject) ) { $Self->{$Object} = $Param{$Object} || die "Nincs $Object!"; } # a létrehozott szükséges objektumok $Self->{QueueObject} = Kernel::System::Queue->new( %{$Self} ); $Self->{TicketObject} = Kernel::System::Ticket->new( %{$Self} ); $Self->{StateObject} = Kernel::System::State->new( %{$Self} ); return $Self; }
A new
a statisztikamodul konstruktora. Ez hozza létre az
osztály új példányát. A kódolási irányelveknek megfelelően az ebben a
modulban szükséges más osztályok objektumait is a new
konstruktorban kell létrehozni. A 27-29. sorban van létrehozva a
statisztikák modul objektuma. A 31-37. sorban azt ellenőrzik, hogy az ebben
a kódban szükséges objektumok - vagy más objektumok létrehozásánál, vagy
ebben a modulban - át vannak-e adva. Ezután a többi objektum kerül
létrehozásra.
sub GetObjectName { my ( $Self, %Param ) = @_; return 'Minta statisztikák'; }
A GetObjectName
visszaad egy nevet a statisztikák
modulhoz. Ez az a címke, amely a lenyíló menüben jelenik meg a
beállításokban, valamint a meglévő statisztikák listájában (az „objektum”
oszlopban).
sub GetObjectAttributes { my ( $Self, %Param ) = @_; # állapotlista lekérése my %StateList = $Self->{StateObject}->StateList( UserID => 1, ); # várólisták listájának lekérése my %QueueList = $Self->{QueueObject}->GetAllQueues(); # a jelenlegi idő lekérése a 3830. hiba javításához my $TimeStamp = $Self->{TimeObject}->CurrentTimestamp(); my ($Date) = split /\s+/, $TimeStamp; my $Today = sprintf "%s 23:59:59", $Date; my @ObjectAttributes = ( { Name => 'Állapot', UseAsXvalue => 1, UseAsValueSeries => 1, UseAsRestriction => 1, Element => 'StateIDs', Block => 'MultiSelectField', Values => \%StateList, }, { Name => 'Létrehozva várólistában', UseAsXvalue => 1, UseAsValueSeries => 1, UseAsRestriction => 1, Element => 'CreatedQueueIDs', Block => 'MultiSelectField', Translation => 0, Values => \%QueueList, }, { Name => 'Létrehozás ideje', UseAsXvalue => 1, UseAsValueSeries => 1, UseAsRestriction => 1, Element => 'CreateTime', TimePeriodFormat => 'DateInputFormat', # 'DateInputFormatLong', Block => 'Time', TimeStop => $Today, Values => { TimeStart => 'TicketCreateTimeNewerDate', TimeStop => 'TicketCreateTimeOlderDate', }, }, ); return @ObjectAttributes; }
Ebben a minta statisztikák modulban három olyan attribútumot szeretnénk
szolgáltatni, amelyből a felhasználó választhat: a várólisták listáját, az
állapotok listáját és egy idő legördülőt. A legördülőben megjelenített
értékek lekéréséhez szükséges néhány művelet. Ebben az esetben a
StateList
és a GetAllQueues
kerül
meghívásra.
Ezután az attribútumok listája kerül létrehozásra. Minden egyes attribútum egy kivonathivatkozáson keresztül van meghatározva. Ezeket a kulcsokat használhatja:
Name
A címke a webes felületen.
UseAsXvalue
Ez az attribútum használható az X-tengelyen.
UseAsValueSeries
Ez az attribútum használható az Y-tengelyen.
UseAsRestriction
Ez az attribútum használható a korlátozásokhoz.
Element
A HTML mező neve.
Block
A blokknév a sablonfájlban (például
<OTRS_HOME>/Kernel/Output/HTML/Standard/AgentStatsEditXaxis.tt
).
Values
Az attribútumban megjelenített értékek.
Tipp: Ha telepíti ezt a mintát, és beállít egy statisztikát néhány
várólistával (mondjuk „A várólista” és „B várólista”), akkor ezek a
várólisták az egyetlenek, amelyek láthatóak lesznek a felhasználónak, amikor
elindítja a statisztikát. Néha egy dinamikus legördülő vagy többválasztós
mező szükséges. Ebben az esetben beállíthatja a
SelectedValues
kulcsot az attribútum meghatározásában:
{ Name => 'Létrehozva várólistában', UseAsXvalue => 1, UseAsValueSeries => 1, UseAsRestriction => 1, Element => 'CreatedQueueIDs', Block => 'MultiSelectField', Translation => 0, Values => \%QueueList, SelectedValues => [ @SelectedQueues ], },
sub GetStatElement { my ( $Self, %Param ) = @_; # jegyek keresése return $Self->{TicketObject}->TicketSearch( UserID => 1, Result => 'COUNT', Permission => 'ro', Limit => 100_000_000, %Param, ); }
A GetStatElement
kerül meghívásra minden egyes cellánál
az eredménytáblában. Így annak számszerű értéknek kell lennie. Ebben a
mintában egy egyszerű jegykeresést hajt végre. A %Param
kivonat tartalmaz információkat a „jelenlegi” X-értékről és Y-értékről,
valamint bármely korlátozásról. Így egy olyan cellánál, amelynek össze kell
számolnia a „nyitott” állapotban lévő létrehozott jegyeket a „Misc”
várólistánál, az átadott paraméter kivonat valahogy így néz ki:
'CreatedQueueIDs' => [ '4' ], 'StateIDs' => [ '2' ]
Ha a „cellánkénti” számítást el kellene kerülni, akkor a
GetStatTable
egy alternatíva. A
GetStatTable
visszaadja a sorok listáját, amely ezentúl
egy tömbhivatkozások tömbje. Ez ugyanahhoz az eredményhez vezet mint a
GetStatElement
használata.
sub GetStatTable { my ( $Self, %Param ) = @_; my @StatData; for my $StateName ( keys %{ $Param{TableStructure} } ) { my @Row; for my $Params ( @{ $Param{TableStructure}->{$StateName} } ) { my $Tickets = $Self->{TicketObject}->TicketSearch( UserID => 1, Result => 'COUNT', Permission => 'ro', Limit => 100_000_000, %{$Params}, ); push @Row, $Tickets; } push @StatData, [ $StateName, @Row ]; } return @StatData; }
A GetStatTable
az összes olyan információt lekéri a
statisztikák lekérdezéssel kapcsolatban, amelyek szükségesek. Az átadott
paraméterek információkat tartalmaznak az attribútumokról
(Restrictions
, olyan attribútumok, amelyek az
X/Y-tengelynél vannak használva) és a táblaszerkezetről. A táblaszerkezet
egy olyan kivonathivatkozás, ahol a kulcsok az Y-tengely értékei, és azok
értékei kivonathivatkozások a GetStatElement
szubrutinokhoz használt paraméterekkel.
'Restrictions' => {}, 'TableStructure' => { 'closed successful' => [ { 'CreatedQueueIDs' => [ '3' ], 'StateIDs' => [ '2' ] }, ], 'closed unsuccessful' => [ { 'CreatedQueueIDs' => [ '3' ], 'StateIDs' => [ '3' ] }, ], }, 'ValueSeries' => [ { 'Block' => 'MultiSelectField', 'Element' => 'StateIDs', 'Name' => 'Állapot', 'SelectedValues' => [ '5', '3', '2', '1', '4' ], 'Translation' => 1, 'Values' => { '1' => 'new', '10' => 'closed with workaround', '2' => 'closed successful', '3' => 'closed unsuccessful', '4' => 'open', '5' => 'removed', '6' => 'pending reminder', '7' => 'pending auto close+', '8' => 'pending auto close-', '9' => 'merged' } } ], 'XValue' => { 'Block' => 'MultiSelectField', 'Element' => 'CreatedQueueIDs', 'Name' => 'Létrehozva várólistában', 'SelectedValues' => [ '3', '4', '1', '2' ], 'Translation' => 0, 'Values' => { '1' => 'Postmaster', '2' => 'Raw', '3' => 'Junk', '4' => 'Misc' } }
Néha a táblázat fejléceit meg kell változtatni. Ebben az esetben egy
GetHeaderLine
nevű szubrutint kell megvalósítani. Ennek a
szubrutinnak egy tömbhivatkozást kell visszaadnia az oszlopfejlécekkel mint
elemekkel. Ez információkat kap az átadott X-értékekkel kapcsolatban.
sub GetHeaderLine { my ( $Self, %Param ) = @_; my @HeaderLine = (''); for my $SelectedXValue ( @{ $Param{XValue}->{SelectedValues} } ) { push @HeaderLine, $Param{XValue}->{Values}->{$SelectedXValue}; } return \@HeaderLine; }
sub ExportWrapper { my ( $Self, %Param ) = @_; # azonosítók átalakítása a használt helyesíráshoz for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) { ELEMENT: for my $Element ( @{ $Param{$Use} } ) { next ELEMENT if !$Element || !$Element->{SelectedValues}; my $ElementName = $Element->{Element}; my $Values = $Element->{SelectedValues}; if ( $ElementName eq 'QueueIDs' || $ElementName eq 'CreatedQueueIDs' ) { ID: for my $ID ( @{$Values} ) { next ID if !$ID; $ID->{Content} = $Self->{QueueObject}->QueueLookup( QueueID => $ID->{Content} ); } } elsif ( $ElementName eq 'StateIDs' || $ElementName eq 'CreatedStateIDs' ) { my %StateList = $Self->{StateObject}->StateList( UserID => 1 ); ID: for my $ID ( @{$Values} ) { next ID if !$ID; $ID->{Content} = $StateList{ $ID->{Content} }; } } } } return \%Param; }
A beállított statisztikák exportálhatók XML-formátumba. De ahogy a várólistáknál, ahol ugyanazok a várólistanevek rendelkezhetnek különböző azonosítókkal a különböző OTRS példányoknál, különösen fájdalmas lehet az azonosítók exportálása (a statisztikák ekkor rossz számokat számítanának ki). Ezért egy exportálási átalakítót kell írni, hogy az azonosítók helyett neveket használjon. Ezt a statisztikák modul minden egyes „dimenziójánál” el kell végezni (X-tengely, Y-tengely és korlátozások).
Az ImportWrapper
fordítva működik - átalakítja a nevet az
azonosítóra abban a példányban, ahova a beállítások importálásra kerülnek.
Ez egy minta exportálás:
<?xml version="1.0" encoding="utf-8"?> <otrs_stats> <Cache>0</Cache> <Description>Minta statisztikák modul</Description> <File></File> <Format>CSV</Format> <Format>Print</Format> <Object>DeveloperManualSample</Object> <ObjectModule>Kernel::System::Stats::Dynamic::DynamicStatsTemplate</ObjectModule> <ObjectName>Sample Statistics</ObjectName> <Permission>stats</Permission> <StatType>dynamic</StatType> <SumCol>0</SumCol> <SumRow>0</SumRow> <Title>Sample 1</Title> <UseAsValueSeries Element="StateIDs" Fixed="1"> <SelectedValues>removed</SelectedValues> <SelectedValues>closed unsuccessful</SelectedValues> <SelectedValues>closed successful</SelectedValues> <SelectedValues>new</SelectedValues> <SelectedValues>open</SelectedValues> </UseAsValueSeries> <UseAsXvalue Element="CreatedQueueIDs" Fixed="1"> <SelectedValues>Junk</SelectedValues> <SelectedValues>Misc</SelectedValues> <SelectedValues>Postmaster</SelectedValues> <SelectedValues>Raw</SelectedValues> </UseAsXvalue> <Valid>1</Valid> </otrs_stats>
Most, hogy az összes szubrutin elmagyarázásra került, itt a teljes minta statisztikák modul.
# -- # Kernel/System/Stats/Dynamic/DynamicStatsTemplate.pm - all advice functions # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::Stats::Dynamic::DynamicStatsTemplate; use strict; use warnings; use Kernel::System::Queue; use Kernel::System::State; use Kernel::System::Ticket; sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # check needed objects for my $Object ( qw(DBObject ConfigObject LogObject UserObject TimeObject MainObject EncodeObject) ) { $Self->{$Object} = $Param{$Object} || die "Got no $Object!"; } # created needed objects $Self->{QueueObject} = Kernel::System::Queue->new( %{$Self} ); $Self->{TicketObject} = Kernel::System::Ticket->new( %{$Self} ); $Self->{StateObject} = Kernel::System::State->new( %{$Self} ); return $Self; } sub GetObjectName { my ( $Self, %Param ) = @_; return 'Sample Statistics'; } sub GetObjectAttributes { my ( $Self, %Param ) = @_; # get state list my %StateList = $Self->{StateObject}->StateList( UserID => 1, ); # get queue list my %QueueList = $Self->{QueueObject}->GetAllQueues(); # get current time to fix bug#3830 my $TimeStamp = $Self->{TimeObject}->CurrentTimestamp(); my ($Date) = split /\s+/, $TimeStamp; my $Today = sprintf "%s 23:59:59", $Date; my @ObjectAttributes = ( { Name => 'State', UseAsXvalue => 1, UseAsValueSeries => 1, UseAsRestriction => 1, Element => 'StateIDs', Block => 'MultiSelectField', Values => \%StateList, }, { Name => 'Created in Queue', UseAsXvalue => 1, UseAsValueSeries => 1, UseAsRestriction => 1, Element => 'CreatedQueueIDs', Block => 'MultiSelectField', Translation => 0, Values => \%QueueList, }, { Name => 'Create Time', UseAsXvalue => 1, UseAsValueSeries => 1, UseAsRestriction => 1, Element => 'CreateTime', TimePeriodFormat => 'DateInputFormat', # 'DateInputFormatLong', Block => 'Time', TimeStop => $Today, Values => { TimeStart => 'TicketCreateTimeNewerDate', TimeStop => 'TicketCreateTimeOlderDate', }, }, ); return @ObjectAttributes; } sub GetStatElement { my ( $Self, %Param ) = @_; # search tickets return $Self->{TicketObject}->TicketSearch( UserID => 1, Result => 'COUNT', Permission => 'ro', Limit => 100_000_000, %Param, ); } sub ExportWrapper { my ( $Self, %Param ) = @_; # wrap ids to used spelling for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) { ELEMENT: for my $Element ( @{ $Param{$Use} } ) { next ELEMENT if !$Element || !$Element->{SelectedValues}; my $ElementName = $Element->{Element}; my $Values = $Element->{SelectedValues}; if ( $ElementName eq 'QueueIDs' || $ElementName eq 'CreatedQueueIDs' ) { ID: for my $ID ( @{$Values} ) { next ID if !$ID; $ID->{Content} = $Self->{QueueObject}->QueueLookup( QueueID => $ID->{Content} ); } } elsif ( $ElementName eq 'StateIDs' || $ElementName eq 'CreatedStateIDs' ) { my %StateList = $Self->{StateObject}->StateList( UserID => 1 ); ID: for my $ID ( @{$Values} ) { next ID if !$ID; $ID->{Content} = $StateList{ $ID->{Content} }; } } } } return \%Param; } sub ImportWrapper { my ( $Self, %Param ) = @_; # wrap used spelling to ids for my $Use (qw(UseAsValueSeries UseAsRestriction UseAsXvalue)) { ELEMENT: for my $Element ( @{ $Param{$Use} } ) { next ELEMENT if !$Element || !$Element->{SelectedValues}; my $ElementName = $Element->{Element}; my $Values = $Element->{SelectedValues}; if ( $ElementName eq 'QueueIDs' || $ElementName eq 'CreatedQueueIDs' ) { ID: for my $ID ( @{$Values} ) { next ID if !$ID; if ( $Self->{QueueObject}->QueueLookup( Queue => $ID->{Content} ) ) { $ID->{Content} = $Self->{QueueObject}->QueueLookup( Queue => $ID->{Content} ); } else { $Self->{LogObject}->Log( Priority => 'error', Message => "Import: Can' find the queue $ID->{Content}!" ); $ID = undef; } } } elsif ( $ElementName eq 'StateIDs' || $ElementName eq 'CreatedStateIDs' ) { ID: for my $ID ( @{$Values} ) { next ID if !$ID; my %State = $Self->{StateObject}->StateGet( Name => $ID->{Content}, Cache => 1, ); if ( $State{ID} ) { $ID->{Content} = $State{ID}; } else { $Self->{LogObject}->Log( Priority => 'error', Message => "Import: Can' find state $ID->{Content}!" ); $ID = undef; } } } } } return \%Param; } 1;
<?xml version="1.0" encoding="utf-8" ?> <otrs_config version="1.0" init="Config"> <ConfigItem Name="Stats::DynamicObjectRegistration###DynamicStatsTemplate" Required="0" Valid="1"> <Description Lang="en">Here you can decide if the common stats module may generate stats about the number of default tickets a requester created.</Description> <Group>Framework</Group> <SubGroup>Core::Stats</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::System::Stats::Dynamic::DynamicStatsTemplate</Item> </Hash> </Setting> </ConfigItem> </otrs_config>
Ha nagyon sok cellája van az eredménytáblázatban és a
GetStatElement
meglehetősen összetett, akkor a kérés
eltarthat egy ideig.
A következő bekezdések a statikus statisztikákat írják le. A statikus statisztikákat nagyon könnyű létrehozni, mivel ezeknek a moduloknak csak három szubrutint kell megvalósítaniuk.
new
Param
Run
A következő bekezdések a statikus statisztikákban szükséges szubrutinokat mutatják be.
sub new { my ( $Type, %Param ) = @_; # új kivonat lefoglalása az objektumhoz my $Self = {%Param}; bless( $Self, $Type ); # az összes szükséges objektum ellenőrzése for my $Needed ( qw(DBObject ConfigObject LogObject TimeObject MainObject EncodeObject) ) { $Self->{$Needed} = $Param{$Needed} || die "Nincs $Needed"; } # a szükséges objektumok létrehozása $Self->{TypeObject} = Kernel::System::Type->new( %{$Self} ); $Self->{TicketObject} = Kernel::System::Ticket->new( %{$Self} ); $Self->{QueueObject} = Kernel::System::Queue->new( %{$Self} ); return $Self; }
A new
hozza létre a statikus statisztikák osztályának egy
új példányát. Először létrehoz egy új objektumot, és azután ellenőrzi a
szükséges objektumokat.
sub Param { my $Self = shift; my %Queues = $Self->{QueueObject}->GetAllQueues(); my %Types = $Self->{TypeObject}->TypeList( Valid => 1, ); my @Params = ( { Frontend => 'Type', Name => 'TypeIDs', Multiple => 1, Size => 3, Data => \%Types, }, { Frontend => 'Queue', Name => 'QueueIDs', Multiple => 1, Size => 3, Data => \%Queues, }, ); return @Params; }
A Param
metódus biztosítja az összes olyan paraméter és
attribútum listáját, amelyek kiválaszthatók egy statikus statisztika
létrehozásához. Megkap néhány átadott paramétert: az értékeket egy kérésben
szolgáltatott statisztikák attribútumaihoz, a statisztikák formátumát és az
objektum nevét (a modul nevét).
A paramétereknek és az attribútumoknak kivonathivatkozásoknak kell lenniük ezekkel a kulcs-érték párokkal:
Frontend
A címke a webes felületen.
Name
A HTML mező neve.
Data
Az attribútumban megjelenített értékek.
Egyéb paraméterek is használhatók a LayoutObject
BuildSelection
metódusánál, ahogy az a
Size
és Multiple
paraméterekkel
történik ebben a minta modulban.
sub Run { my ( $Self, %Param ) = @_; # a szükséges dolgok ellenőrzése for my $Needed (qw(TypeIDs QueueIDs)) { if ( !$Param{$Needed} ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Szükséges: $Needed!", ); return; } } # a jelentés címének beállítása my $Title = 'Jegyek várólistánként'; # táblázat címsorok my @HeadData = ( 'Jegyszám', 'Várólista', 'Típus', ); my @Data; my @TicketIDs = $Self->{TicketObject}->TicketSearch( UserID => 1, Result => 'ARRAY', Permission => 'ro', %Param, ); for my $TicketID ( @TicketIDs ) { my %Ticket = $Self->{TicketObject}->TicketGet( UserID => 1, TicketID => $TicketID, ); push @Data, [ $Ticket{TicketNumber}, $Ticket{Queue}, $Ticket{Type} ]; } return ( [$Title], [@HeadData], @Data ); }
Tulajdonképpen a Run
metódus állítja elő a táblázat
adatait a statisztikákhoz. Megkapja az ennél a statisztikánál átadott
attribútumokat. Ebben a mintában a %Param
paraméterben
egy TypeIDs
kulcs és egy QueueIDs
kulcs létezik (lásd a Param
metódusban lévő
attribútumokat), és ezek értékei tömbhivatkozások. A visszaadott adatok
három részből állnak: két tömbhivatkozásból és egy tömbből. Az első
tömbhivatkozásban a statisztika címe van eltárolva, a második tömbhivatkozás
tartalmazza a táblázatban lévő oszlopok címsorait. És ezután a táblázattörzs
adatai következnek.
# -- # Kernel/System/Stats/Static/StaticStatsTemplate.pm # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::Stats::Static::StaticStatsTemplate; use strict; use warnings; use Kernel::System::Type; use Kernel::System::Ticket; use Kernel::System::Queue; =head1 NAME StaticStatsTemplate.pm - the module that creates the stats about tickets in a queue =head1 SYNOPSIS All functions =head1 PUBLIC INTERFACE =over 4 =cut =item new() create an object use Kernel::Config; use Kernel::System::Encode; use Kernel::System::Log; use Kernel::System::Main; use Kernel::System::Time; use Kernel::System::DB; use Kernel::System::Stats::Static::StaticStatsTemplate; my $ConfigObject = Kernel::Config->new(); my $EncodeObject = Kernel::System::Encode->new( ConfigObject => $ConfigObject, ); my $LogObject = Kernel::System::Log->new( ConfigObject => $ConfigObject, ); my $MainObject = Kernel::System::Main->new( ConfigObject => $ConfigObject, LogObject => $LogObject, ); my $TimeObject = Kernel::System::Time->new( ConfigObject => $ConfigObject, LogObject => $LogObject, ); my $DBObject = Kernel::System::DB->new( ConfigObject => $ConfigObject, LogObject => $LogObject, MainObject => $MainObject, ); my $StatsObject = Kernel::System::Stats::Static::StaticStatsTemplate->new( ConfigObject => $ConfigObject, LogObject => $LogObject, MainObject => $MainObject, TimeObject => $TimeObject, DBObject => $DBObject, EncodeObject => $EncodeObject, ); =cut sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {%Param}; bless( $Self, $Type ); # check all needed objects for my $Needed ( qw(DBObject ConfigObject LogObject TimeObject MainObject EncodeObject) ) { $Self->{$Needed} = $Param{$Needed} || die "Got no $Needed"; } # create needed objects $Self->{TypeObject} = Kernel::System::Type->new( %{$Self} ); $Self->{TicketObject} = Kernel::System::Ticket->new( %{$Self} ); $Self->{QueueObject} = Kernel::System::Queue->new( %{$Self} ); return $Self; } =item Param() Get all parameters a user can specify. my @Params = $StatsObject->Param(); =cut sub Param { my $Self = shift; my %Queues = $Self->{QueueObject}->GetAllQueues(); my %Types = $Self->{TypeObject}->TypeList( Valid => 1, ); my @Params = ( { Frontend => 'Type', Name => 'TypeIDs', Multiple => 1, Size => 3, Data => \%Types, }, { Frontend => 'Queue', Name => 'QueueIDs', Multiple => 1, Size => 3, Data => \%Queues, }, ); return @Params; } =item Run() generate the statistic. my $StatsInfo = $StatsObject->Run( TypeIDs => [ 1, 2, 4 ], QueueIDs => [ 3, 4, 6 ], ); =cut sub Run { my ( $Self, %Param ) = @_; # check needed stuff for my $Needed (qw(TypeIDs QueueIDs)) { if ( !$Param{$Needed} ) { $Self->{LogObject}->Log( Priority => 'error', Message => "Need $Needed!", ); return; } } # set report title my $Title = 'Tickets per Queue'; # table headlines my @HeadData = ( 'Ticket Number', 'Queue', 'Type', ); my @Data; my @TicketIDs = $Self->{TicketObject}->TicketSearch( UserID => 1, Result => 'ARRAY', Permission => 'ro', %Param, ); for my $TicketID ( @TicketIDs ) { my %Ticket = $Self->{TicketObject}->TicketGet( UserID => 1, TicketID => $TicketID, ); push @Data, [ $Ticket{TicketNumber}, $Ticket{Queue}, $Ticket{Type} ]; } return ( [$Title], [@HeadData], @Data ); } 1;
Nincs szükség beállításokra. Közvetlenül telepítés után a modul elérhető egy statisztika létrehozásához ennél a modulnál.
A szabványos 1.3-as és 2.0-ás OTRS verziók már megkönnyítették a statisztikák előállítását. Az OTRS 1.3-as és 2.0-ás verzióinak különféle statisztikái, amelyek különlegesen lettek kifejlesztve, hogy kielégítsék az ügyfelek követelményeit, használhatók az újabb verziókban is.
A fájlokat pusztán csak át kell helyezni a
Kernel/System/Stats/
útvonalról a
Kernel/System/Stats/Static/
könyvtárba. Továbbá a
megfelelő parancsfájl csomagnevét ::Static
névre kell
módosítani.
A következő példa azt mutatja be, hogy hogyan kell az első útvonalat módosítani.
package Kernel::System::Stats::AccountedTime;
package Kernel::System::Stats::Static::AccountedTime;
A jegyszám előállítókat elkülönülő azonosítók létrehozásához használják az új jegyekhez, amelyeket jegyszámnak neveznek. Bármilyen metódus lehetséges a számok karakterláncainak létrehozásához, de a józan ész határain belül kell maradnia az eredményül kapott szöveg hosszával kapcsolatban (irányelv: 5-10).
Egy jegyszám létrehozásakor győződjön meg arról, hogy az eredmény megkapta-e
a SystemID
rendszerbeállítási változót előtagként annak
érdekében, hogy engedélyezze a jegyszámok felismerését a bejövő e-mail
válaszoknál. Egy jegyszám előállító modulnak a következő két függvényre van
szüksége: TicketCreateNumber()
és GetTNByString()
.
A TicketCreateNumber()
metódus paraméterek nélkül kerül
meghívásra, és az új jegyszámot adja vissza.
A GetTNByString()
metódus egy olyan szöveg paraméterrel kerül
meghívásra, amely a feldolgozandó szöveget tartalmazza a jegyszámnál, és
visszaadja a jegyszámot, ha megtalálta.
Nézze meg a
Kernel/Config/Files/TicketNumberGenerator.xml
fájlt a
TemplateModule
csomagban.
Ragaszkodnia kell a meglévő jegyszám előállítókban használt
GetTNByString()
kódjához, hogy megelőzze a jegyszám
feldolgozással kapcsolatos problémákat. A TicketCreateNumber()
metódusban lévő hurok felismeréséhez használt rutint is érintetlenül kell
hagynia a kettőzött jegyszámok megelőzéséhez.
A jegyesemény modulok közvetlenül azután futnak le, amikor egy jegyművelet
megtörténik. Megegyezés szerint ezek a modulok a
Kernel/System/Ticket/Event
könyvtárban találhatók. Egy
jegyesemény modulnak mindössze két függvényre van szüksége:
new()
és Run()
. A Run()
metódus
legalább az Event
, a UserID
és a
Data
paramétereket fogadja. A Data
a
jegy adatait tartalmazó kivonathivatkozás, és a bejegyzésre vonatkozó
események esetében a bejegyzés adatait is tartalmazza.
Nézze meg a
Kernel/System/Ticket/Event/EventModulePostTemplate.pm
fájlt a TemplateModule
csomagban.
Nézze meg a
Kernel/Config/Files/EventModulePostTemplate.xml
fájlt a
TemplateModule
csomagban.
Ez a szabványos funkció a
Kernel::System::Ticket::Event::ForceUnlock
jegyesemény
modullal lett megvalósítva. Amikor erre a funkcióra nincs szükség, akkor az
kikapcsolható a
Ticket::EventModulePost###910-ForceUnlockOnMove
rendszerbeállítási bejegyzés beállításának törlésével.
Egy személyre szabott OTRS tarthat nem szabványos adatokat további
adatbázistáblákban. Amikor egy jegyet törölnek, akkor ezeket a további
adatokat is törölni kell. Ez a funkcionalitás elérhető egy olyan jegyesemény
modullal, amely a TicketDelete
eseményekre figyel.
A jegyesemények az OTRS 2.0 óta lettek elérhetők az OTRS-ben.
Ticket events available in OTRS 5.0:
TicketCreate
TicketDelete
TicketTitleUpdate
TicketUnlockTimeoutUpdate
TicketQueueUpdate
TicketTypeUpdate
TicketServiceUpdate
TicketSLAUpdate
TicketCustomerUpdate
TicketPendingTimeUpdate
TicketLockUpdate
TicketArchiveFlagUpdate
TicketStateUpdate
TicketOwnerUpdate
TicketResponsibleUpdate
TicketPriorityUpdate
HistoryAdd
HistoryDelete
TicketAccountTime
TicketMerge
TicketSubscribe
TicketUnsubscribe
TicketFlagSet
TicketFlagDelete
TicketSlaveLinkAdd
TicketSlaveLinkDelete
TicketMasterLinkDelete
EscalationResponseTimeNotifyBefore
EscalationUpdateTimeNotifyBefore
EscalationSolutionTimeNotifyBefore
EscalationResponseTimeStart
EscalationUpdateTimeStart
EscalationSolutionTimeStart
EscalationResponseTimeStop
EscalationUpdateTimeStop
EscalationSolutionTimeStop
NotificationNewTicket
NotificationFollowUp
NotificationLockTimeout
NotificationOwnerUpdate
NotificationResponsibleUpdate
NotificationAddNote
NotificationMove
NotificationPendingReminder
NotificationEscalation
NotificationEscalationNotifyBefore
NotificationServiceUpdate
Article events available in OTRS 5.0:
ArticleCreate
ArticleUpdate
ArticleSend
ArticleBounce
ArticleAgentNotification
ArticleCustomerNotification
ArticleAutoResponse
ArticleFlagSet
ArticleFlagDelete
ArticleAgentNotification
ArticleCustomerNotification
Vezérlőpult modul statisztikák megjelenítéséhez vonaldiagram formájában.
# -- # Kernel/Output/HTML/DashboardTicketStatsGeneric.pm - message of the day # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::Output::HTML::DashboardTicketStatsGeneric; use strict; use warnings; sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {%Param}; bless( $Self, $Type ); # get needed objects for ( qw(Config Name ConfigObject LogObject DBObject LayoutObject ParamObject TicketObject UserID) ) { die "Got no $_!" if !$Self->{$_}; } return $Self; } sub Preferences { my ( $Self, %Param ) = @_; return; } sub Config { my ( $Self, %Param ) = @_; my $Key = $Self->{LayoutObject}->{UserLanguage} . '-' . $Self->{Name}; return ( %{ $Self->{Config} }, CacheKey => 'TicketStats' . '-' . $Self->{UserID} . '-' . $Key, ); } sub Run { my ( $Self, %Param ) = @_; my %Axis = ( '7Day' => { 0 => { Day => 'Sun', Created => 0, Closed => 0, }, 1 => { Day => 'Mon', Created => 0, Closed => 0, }, 2 => { Day => 'Tue', Created => 0, Closed => 0, }, 3 => { Day => 'Wed', Created => 0, Closed => 0, }, 4 => { Day => 'Thu', Created => 0, Closed => 0, }, 5 => { Day => 'Fri', Created => 0, Closed => 0, }, 6 => { Day => 'Sat', Created => 0, Closed => 0, }, }, ); my @Data; my $Max = 1; for my $Key ( 0 .. 6 ) { my $TimeNow = $Self->{TimeObject}->SystemTime(); if ($Key) { $TimeNow = $TimeNow - ( 60 * 60 * 24 * $Key ); } my ( $Sec, $Min, $Hour, $Day, $Month, $Year, $WeekDay ) = $Self->{TimeObject}->SystemTime2Date( SystemTime => $TimeNow, ); $Data[$Key]->{Day} = $Self->{LayoutObject}->{LanguageObject}->Get( $Axis{'7Day'}->{$WeekDay}->{Day} ); my $CountCreated = $Self->{TicketObject}->TicketSearch( # cache search result 20 min CacheTTL => 60 * 20, # tickets with create time after ... (ticket newer than this date) (optional) TicketCreateTimeNewerDate => "$Year-$Month-$Day 00:00:00", # tickets with created time before ... (ticket older than this date) (optional) TicketCreateTimeOlderDate => "$Year-$Month-$Day 23:59:59", CustomerID => $Param{Data}->{UserCustomerID}, Result => 'COUNT', # search with user permissions Permission => $Self->{Config}->{Permission} || 'ro', UserID => $Self->{UserID}, ); $Data[$Key]->{Created} = $CountCreated; if ( $CountCreated > $Max ) { $Max = $CountCreated; } my $CountClosed = $Self->{TicketObject}->TicketSearch( # cache search result 20 min CacheTTL => 60 * 20, # tickets with create time after ... (ticket newer than this date) (optional) TicketCloseTimeNewerDate => "$Year-$Month-$Day 00:00:00", # tickets with created time before ... (ticket older than this date) (optional) TicketCloseTimeOlderDate => "$Year-$Month-$Day 23:59:59", CustomerID => $Param{Data}->{UserCustomerID}, Result => 'COUNT', # search with user permissions Permission => $Self->{Config}->{Permission} || 'ro', UserID => $Self->{UserID}, ); $Data[$Key]->{Closed} = $CountClosed; if ( $CountClosed > $Max ) { $Max = $CountClosed; } } @Data = reverse @Data; my $Source = $Self->{LayoutObject}->JSONEncode( Data => \@Data, ); my $Content = $Self->{LayoutObject}->Output( TemplateFile => 'AgentDashboardTicketStats', Data => { %{ $Self->{Config} }, Key => int rand 99999, Max => $Max, Source => $Source, }, ); return $Content; } 1;
Ezen modul használatához adja hozzá a következőket a
Kernel/Config.pm
fájlhoz, és indítsa újra a
webkiszolgálóját (ha a mod_perl
modult használja).
<ConfigItem Name="DashboardBackend###0250-TicketStats" Required="0" Valid="1"> <Description Lang="en">Parameters for the dashboard backend. "Group" are used to restricted access to the plugin (e. g. Group: admin;group1;group2;). "Default" means if the plugin is enabled per default or if the user needs to enable it manually. "CacheTTL" means the cache time in minutes for the plugin.</Description> <Description Lang="hu">Paraméterek a vezérlőpult háttérprogramhoz. A „Csoport” használható a hozzáférés korlátozásához a bővítményre (például Csoport: admin;csoport1;csoport2;). Az „Alapértelmezett” azt jelenti, hogy a bővítmény alapértelmezetten engedélyezve van, vagy hogy a felhasználónak kézzel kell engedélyeznie azt. A „CacheTTL” a bővítmény gyorsítótár lejárati időtartamát jelenti percben.</Description> <Group>Ticket</Group> <SubGroup>Frontend::Agent::Dashboard</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::Output::HTML::DashboardTicketStatsGeneric</Item> <Item Key="Title">7 Day Stats</Item> <Item Key="Created">1</Item> <Item Key="Closed">1</Item> <Item Key="Permission">rw</Item> <Item Key="Block">ContentSmall</Item> <Item Key="Group"></Item> <Item Key="Default">1</Item> <Item Key="CacheTTL">45</Item> </Hash> </Setting> </ConfigItem>
A napok vagy az önálló sorok túlzott száma teljesítmény-csökkenéshez vezethet.
Az értesítési modulokat egy értesítés megjelenítéséhez használják a fő navigáció alatt. Megírhatja és regisztrálhatja a saját értesítési modulját. Jelenleg 5 jegymenü van az OTRS keretrendszerben.
AgentOnline
AgentTicketEscalation
CharsetCheck
CustomerOnline
UIDCheck
Az értesítési modulok a
Kernel/Output/HTML/TicketNotification*.pm
alatt
találhatók. Ezt követően egy értesítőmodul példája található. Mentse el a
Kernel/Output/HTML/TicketNotificationCustom.pm
fájlba. Mindössze két függvényre van szüksége: new()
és
Run()
.
# -- # Kernel/Output/HTML/NotificationCustom.pm # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::Output::HTML::NotificationCustom; use strict; use warnings; use Kernel::System::Custom; sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # get needed objects for my $Object (qw(ConfigObject LogObject DBObject LayoutObject TimeObject UserID)) { $Self->{$Object} = $Param{$Object} || die "Got no $Object!"; } $Self->{CustomObject} = Kernel::System::Custom->new(%Param); return $Self; } sub Run { my ( $Self, %Param ) = @_; # get session info my %CustomParam = (); my @Customs = $Self->{CustomObject}->GetAllCustomIDs(); my $IdleMinutes = $Param{Config}->{IdleMinutes} || 60 * 2; for (@Customs) { my %Data = $Self->{CustomObject}->GetCustomIDData( CustomID => $_, ); if ( $Self->{UserID} ne $Data{UserID} && $Data{UserType} eq 'User' && $Data{UserLastRequest} && $Data{UserLastRequest} + ( $IdleMinutes * 60 ) > $Self->{TimeObject}->SystemTime() && $Data{UserFirstname} && $Data{UserLastname} ) { $CustomParam{ $Data{UserID} } = "$Data{UserFirstname} $Data{UserLastname}"; if ( $Param{Config}->{ShowEmail} ) { $CustomParam{ $Data{UserID} } .= " ($Data{UserEmail})"; } } } for ( sort { $CustomParam{$a} cmp $CustomParam{$b} } keys %CustomParam ) { if ( $Param{Message} ) { $Param{Message} .= ', '; } $Param{Message} .= "$CustomParam{$_}"; } if ( $Param{Message} ) { return $Self->{LayoutObject}->Notify( Info => 'Custom Message: %s", "' . $Param{Message} ); } else { return ''; } } 1;
Szükség van az egyéni értesítési modul bekapcsolására. Ezt a lenti XML beállítás használatával lehet megtenni. Lehetnek további paraméterek is a beállítás kivonatában az értesítési moduljánál.
<ConfigItem Name="Frontend::NotifyModule###3-Custom" Required="0" Valid="0"> <Description Lang="en">Module to show custom message in the agent interface.</Description> <Description Lang="hu">Egy modul egyéni üzenet megjelenítéséhez az ügyintézői felületen.</Description> <Group>Framework</Group> <SubGroup>Frontend::Agent::ModuleNotify</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::Output::HTML::NotificationCustom</Item> <Item Key="Key1">1</Item> <Item Key="Key2">2</Item> </Hash> </Setting> </ConfigItem>
Hasznos jegymenü megvalósítás lehet egy hivatkozás egy külső eszközre, ha a
paraméterek (például FreeTextField
) be lettek állítva.
A jegymenü modulokat egy további hivatkozás megjelenítéséhez használják a jegy fölött lévő menüben. Megírhatja és regisztrálhatja a saját jegymenü moduljait. Négy jegymenü létezik (Általános, Zárolás, Felelős és Jegymegfigyelő), amely az OTRS keretrendszerrel érkezik. További információkért nézzen bele az OTRS adminisztrációs kézikönyvébe.
A jegymenü modulok a Kernel/Output/HTML/TicketMenu*.pm
fájlokban találhatók. A következőkben egy jegymenü modul példája
található. Mentse el a
Kernel/Output/HTML/TicketMenuCustom.pm
helyre. Mindössze két függvényre van szüksége: new()
és
Run()
.
# -- # Kernel/Output/HTML/TicketMenuCustom.pm # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # Id: TicketMenuCustom.pm,v 1.17 2010/04/12 21:34:06 martin Exp $ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::Output::HTML::TicketMenuCustom; use strict; use warnings; sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # get needed objects for my $Object (qw(ConfigObject LogObject DBObject LayoutObject UserID TicketObject)) { $Self->{$Object} = $Param{$Object} || die "Got no $Object!"; } return $Self; } sub Run { my ( $Self, %Param ) = @_; # check needed stuff if ( !$Param{Ticket} ) { $Self->{LogObject}->Log( Priority => 'error', Message => 'Need Ticket!' ); return; } # check if frontend module registered, if not, do not show action if ( $Param{Config}->{Action} ) { my $Module = $Self->{ConfigObject}->Get('Frontend::Module')->{ $Param{Config}->{Action} }; return if !$Module; } # check permission my $AccessOk = $Self->{TicketObject}->Permission( Type => 'rw', TicketID => $Param{Ticket}->{TicketID}, UserID => $Self->{UserID}, LogNo => 1, ); return if !$AccessOk; # check permission if ( $Self->{TicketObject}->CustomIsTicketCustom( TicketID => $Param{Ticket}->{TicketID} ) ) { my $AccessOk = $Self->{TicketObject}->OwnerCheck( TicketID => $Param{Ticket}->{TicketID}, OwnerID => $Self->{UserID}, ); return if !$AccessOk; } # check acl return if defined $Param{ACL}->{ $Param{Config}->{Action} } && !$Param{ACL}->{ $Param{Config}->{Action} }; # if ticket is customized if ( $Param{Ticket}->{Custom} eq 'lock' ) { # if it is locked for somebody else return if $Param{Ticket}->{OwnerID} ne $Self->{UserID}; # show custom action return { %{ $Param{Config} }, %{ $Param{Ticket} }, %Param, Name => 'Custom', Description => 'Custom to give it back to the queue!', Link => 'Action=AgentTicketCustom;Subaction=Custom;TicketID=$QData{"TicketID"}', }; } # if ticket is customized return { %{ $Param{Config} }, %{ $Param{Ticket} }, %Param, Name => 'Custom', Description => 'Custom it to work on it!', Link => 'Action=AgentTicketCustom;Subaction=Custom;TicketID=$QData{"TicketID"}', }; } 1;
Szükség van az egyéni jegymenü modul bekapcsolására. Ezt a lenti XML beállítás használatával lehet megtenni. Lehetnek további paraméterek is a beállítás kivonatában a jegymenü moduljánál.
<ConfigItem Name="Ticket::Frontend::MenuModule###110-Custom" Required="0" Valid="1"> <Description Lang="en">Module to show custom link in menu.</Description> <Description Lang="hu">Egy modul egyéni hivatkozás megjelenítéséhez a menüben.</Description> <Group>Ticket</Group> <SubGroup>Frontend::Agent::Ticket::MenuModule</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::Output::HTML::TicketMenuCustom</Item> <Item Key="Name">Custom</Item> <Item Key="Action">AgentTicketCustom</Item> </Hash> </Setting> </ConfigItem>
Hasznos jegymenü megvalósítás lehet egy hivatkozás egy külső eszközre, ha a
paraméterek (például FreeTextField
) be lettek állítva.
A jegymenü egy olyan URL-re irányít, amely kezelhető. Ha ezt a kérést az OTRS keretrendszeren keresztül szeretné kezelni, akkor meg kell írnia a saját előtétprogram modulját.
A hálózati átvitelt használják az információk küldésének és fogadásának módszereként az OTRS és egy távoli rendszer között. Az általános felület beállításai lehetővé teszik egy webszolgáltatásnak, hogy különböző hálózati átviteli modulokat használjon a szolgáltatónál és a kérelmezőnél, de a leggyakoribb forgatókönyv az, hogy ugyanazt az átviteli modult használják mindkettőnél.
OTRS mint szolgáltató:
Az OTRS arra használja a hálózati átviteli modulokat, hogy lekérje az adatokat a távoli rendszertől, valamint lekérje a végrehajtandó műveleteket. A művelet végrehajtása után az OTRS ismét azokat használja a válasz visszaküldéséhez a távoli rendszernek.
OTRS mint kérelmező:
Az OTRS arra használja a hálózati átviteli modulokat, hogy kérelmeket küldjön a távoli rendszernek egy távoli művelet végrehajtásához a szükséges adatok mellett. Az OTRS várakozik a távoli rendszer válaszára, és visszaküldi azt a kérelmező modulnak.
Mindkét irányban a hálózati átviteli modulok foglalkoznak a távoli rendszer formátumában lévő adatokkal. Nem ajánlott semmilyen adatátalakítás végrehajtása sem ezekben a modulokban, mivel a leképező réteg felelős a kommunikáció során szükséges bármilyen adatátalakítás végrehajtásáért. Egy kivétel erre az olyan adatátalakítás, amely kifejezetten az átvitelnél szükséges, például XML vagy JSON és Perl átalakítások.
Ezután be fogjuk mutatni, hogy hogyan kell egy új átviteli háttérprogramot kifejleszteni. Minden egyes átviteli háttérprogramnak meg kell valósítania ezeket a szubrutinokat:
new
ProviderProcessRequest
ProviderGenerateResponse
RequesterPerformRequest
Meg kell valósítanunk ezen metódusok mindegyikét azért, hogy képesek legyünk
mindkét irányban helyesen kommunikálni egy távoli rendszerrel. Az összes
átviteli háttérprogramot az átviteli modul kezeli
(Kernel/GenericInterface/Transport.pm
).
Jelenleg az általános felület megvalósítja a HTTP SOAP és a HTTP REST átviteleket. Ha a tervezett webszolgáltatás használhat HTTP SOAP vagy HTTP SOAP átviteleket, akkor nincs szükség egy új hálózati átviteli modul létrehozására, hanem ahelyett azt ajánljuk, hogy vessen egy pillantást a HTTP SOAP vagy HTTP REST konfigurációira a beállításaik ellenőrzéséhez, valamint hogy hogyan hangolhatók a távoli rendszernek megfelelően.
Abban az esetben, ha a biztosított hálózati átvitelek nem illeszkednek a
webszolgáltatás igényeire, akkor ebben a szakaszban egy minta hálózati
átviteli modul van bemutatva, és minden egyes szubrutin elmagyarázásra
kerül. Normális esetben az átviteli modulok CPAN modulokat használnak
háttérprogramokként. Például a HTTP SOAP átviteli modulok a
SOAP::Lite
modult használják háttérprogramként.
Ennél a példánál egy egyéni csomagot használnak az adatok visszaadásához anélkül, hogy valódi hálózati kérést intéznének egy távoli rendszerhez, ehelyett ez az egyéni modul működik visszacsatolási felületként.
# -- # Kernel/GenericInterface/Transport/HTTP/Test.pm - GenericInterface network transport interface for testing # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::GenericInterface::Transport::HTTP::Test; use strict; use warnings; use HTTP::Request::Common; use LWP::UserAgent; use LWP::Protocol; # prevent 'Used once' warning for Kernel::OM use Kernel::System::ObjectManager; our $ObjectManagerDisabled = 1;
Ez egy gyakori fejléc, amely megtalálható a szokásos OTRS modulokban. Az
osztály/csomag neve a package
kulcsszón keresztül van
deklarálva. Az átvitelek nem példányosíthatók az objektumkezelővel.
sub new { my ( $Type, %Param ) = @_; my $Self = {}; bless( $Self, $Type ); for my $Needed (qw( DebuggerObject TransportConfig)) { $Self->{$Needed} = $Param{$Needed} || return { Success => 0, ErrorMessage => "Nincs $Needed!" }; } return $Self; }
A new
konstruktor hozza létre az osztály új példányát. A
kódolási irányelvek szerint az objektumkezelő által nem kezelt más
osztályoknak csak azon objektumait kell a new
konstruktorban létrehozni, amelyek ebben a modulban szükségesek.
sub ProviderProcessRequest { my ( $Self, %Param ) = @_; if ( $Self->{TransportConfig}->{Config}->{Fail} ) { return { Success => 0, ErrorMessage => "HTTP állapotkód: 500", Data => {}, }; } my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request'); my %Result; for my $ParamName ( $ParamObject->GetParamNames() ) { $Result{$ParamName} = $ParamObject->GetParam( Param => $ParamName ); } # különleges kezelés az üres POST kérésnél if ( scalar keys %Result == 1 && exists $Result{POSTDATA} && !$Result{POSTDATA} ) { %Result = (); } if ( !%Result ) { return $Self->{DebuggerObject}->Error( Summary => 'Nem található kért adat.', ); } return { Success => 1, Data => \%Result, Operation => 'test_operation', }; }
A ProviderProcessRequest
függvény megkapja a kérést a
távoli kiszolgálótól (ebben az esetben ugyanaz az OTRS), és kibontja az
adatokat és a műveletet a kérésből a végrehajtáshoz. Ennél a példánál a
művelet mindig a test_operation
.
Annak a módja, ahogy ez a függvény feldolgozza a kérést az adatok és a művelet nevének lekéréséhez, az teljes egészében a megvalósítandó protokolltól és azon külső moduloktól függ, amelyekhez használják azokat.
sub ProviderGenerateResponse { my ( $Self, %Param ) = @_; if ( $Self->{TransportConfig}->{Config}->{Fail} ) { return { Success => 0, ErrorMessage => 'A tesztválasz előállítása sikertelen.', }; } my $Response; if ( !$Param{Success} ) { $Response = HTTP::Response->new( 500 => ( $Param{ErrorMessage} || 'Internal Server Error' ) ); $Response->protocol('HTTP/1.0'); $Response->content_type("text/plain; charset=UTF-8"); $Response->date(time); } else { # egy kérésszöveg előállítása az adatokból my $Request = HTTP::Request::Common::POST( 'http://testhost.local/', Content => $Param{Data} ); $Response = HTTP::Response->new( 200 => "OK" ); $Response->protocol('HTTP/1.0'); $Response->content_type("text/plain; charset=UTF-8"); $Response->add_content_utf8( $Request->content() ); $Response->date(time); } $Self->{DebuggerObject}->Debug( Summary => 'HTTP-válasz küldése', Data => $Response->as_string(), ); # a válasz elküldése a kliensnek most print STDOUT $Response->as_string(); return { Success => 1, }; }
Ez a függvény visszaküldi a választ a távoli rendszernek a kért művelethez.
Ennél a bizonyos példánál minden esetben egy szabványos sikeres HTTP-választ adunk vissza (200) vagy nem (500) a szükséges adatok mellett.
sub RequesterPerformRequest { my ( $Self, %Param ) = @_; if ( $Self->{TransportConfig}->{Config}->{Fail} ) { return { Success => 0, ErrorMessage => "HTTP állapotkód: 500", Data => {}, }; } # egyéni protokollkezelő használata a valódi hálózati kérések kiküldésének elkerüléséhez LWP::Protocol::implementor( testhttp => 'Kernel::GenericInterface::Transport::HTTP::Test::CustomHTTPProtocol' ); my $UserAgent = LWP::UserAgent->new(); my $Response = $UserAgent->post( 'testhttp://localhost.local/', Content => $Param{Data} ); return { Success => 1, Data => { ResponseContent => $Response->content(), }, }; }
Ez az egyetlen olyan függvény, amelyet az OTRS mint kérelmező használ. Elküldi a kérést a távoli rendszernek, és várakozik annak válaszára.
Ennél a példánál egy egyéni protokollkezelőt használunk a valódi hálózatra történő kérésküldés elkerüléséhez. Ez az egyéni protokoll az alábbiakban van megadva.
package Kernel::GenericInterface::Transport::HTTP::Test::CustomHTTPProtocol; use base qw(LWP::Protocol); sub new { my $Class = shift; return $Class->SUPER::new(@_); } sub request { ## nem kritikus my $Self = shift; my ( $Request, $Proxy, $Arg, $Size, $Timeout ) = @_; my $Response = HTTP::Response->new( 200 => "OK" ); $Response->protocol('HTTP/1.0'); $Response->content_type("text/plain; charset=UTF-8"); $Response->add_content_utf8( $Request->content() ); $Response->date(time); #print $Request->as_string(); #print $Response->as_string(); return $Response; }
Ez a kód ahhoz az egyéni protokollhoz van, amelyet használunk. Ez a megközelítés csak gyakorlásnál vagy olyan tesztelési környezeteknél hasznos, ahol a távoli rendszerek nem érhetők el.
Egy új modul kifejlesztéséhez nem ajánljuk ezen megközelítés használatát, egy valódi protokollt kell megvalósítani.
Szükség van ezen hálózati átviteli modul regisztrálására, hogy elérhető legyen az OTRS grafikus felhasználói felületén. Ezt a lenti XML beállítás használatával lehet megtenni.
<ConfigItem Name="GenericInterface::Transport::Module###HTTP::Test" Required="0" Valid="1"> <Description Translatable="1">GenericInterface module registration for the transport layer.</Description> <Group>GenericInterface</Group> <SubGroup>GenericInterface::Transport::ModuleRegistration</SubGroup> <Setting> <Hash> <Item Key="Name">Test</Item> <Item Key="Protocol">HTTP</Item> <Item Key="ConfigDialog">AdminGenericInterfaceTransportHTTPTest</Item> </Hash> </Setting> </ConfigItem>
A leképezést adatok átalakításához használják az OTRS és a távoli rendszer között, illetve fordítva. Ezek az adatok kulcs => érték párokként vannak ábrázolva. Leképező modulok fejleszthetők ki nem csak az értékek, hanem a kulcsok átalakításához is.
Például:
Erről | Erre |
---|---|
Prio => Warning | PriorityID => 3 |
A leképező réteg nem feltétlenül szükséges, egy webszolgáltatás teljesen kihagyhatja azt a webszolgáltatás beállításaitól, valamint a meghívók és műveletek megvalósításának módjától függően. De ha egy kis átalakítás szükséges, akkor erősen ajánlott egy meglévő leképezőmodul használata, vagy egy új létrehozása.
A leképező modulok egynél több alkalommal is meghívhatók egy normál kommunikáció közben. Vessen egy pillantást a következő példákra.
OTRS mint szolgáltató példa:
A távoli rendszer elküldi a kérést az adatokkal a távoli rendszer formátumában
Az adatok leképezésre kerülnek a távoli rendszer formátumáról az OTRS formátumára
Az OTRS végrehajtja a műveletet, és visszaadja a választ az OTRS formátumában
Az adatok leképezésre kerülnek az OTRS formátumáról a távoli rendszer formátumára
A válasz a távoli rendszer formátumában lévő adatokkal elküldésre kerül a távoli rendszernek
OTRS mint kérelmező példa:
Az OTRS előkészíti a kérést a távoli rendszerhez az OTRS formátumában lévő adatokkal
Az adatok leképezésre kerülnek az OTRS formátumáról a távoli rendszer formátumára
A kérés elküldésre kerül a távoli rendszernek, amely végrehajtja a műveletet, és visszaküldi a választ az OTRS-nek a távoli rendszer formátumában lévő adatokkal
Az adatok (ismét) leképezésre kerülnek a távoli rendszer formátumáról az OTRS formátumára
Az OTRS feldolgozza a választ
Az általános felület biztosít egy Simple nevű leképezőmodult. Ezzel a modullal a legtöbb adatátalakítás (beleértve a kulcs és érték leképezést) elvégezhető, és szabályokat is meghatároz az alapértelmezett leképezések kezeléséhez mind a kulcsoknál, mind az értékeknél.
Ezért erősen valószínű, hogy nem lesz szüksége egy egyéni leképezőmodul
kifejlesztésére. A folytatás előtt nézze meg a Simple
leképezőmodult
(Kernel/GenericInterface/Mapping/Simple.pm
) és annak
internetes dokumentációját.
Ha a Simple leképezőmodul nem felel meg az igényeinek, akkor meg fogjuk mutatni, hogy hogyan lehet kifejleszteni egy új leképező háttérprogramot. Minden egyes leképező háttérprogramnak meg kell valósítania ezeket a szubrutinokat:
new
Map
Meg kell valósítanunk ezen metódusok mindegyikét azért, hogy képesek legyünk
az adatok leképezésére a kommunikációban, amelyet vagy a kérelmező, vagy a
szolgáltató kezel. Az összes leképező háttérprogramot a leképezőmodul kezeli
(Kernel/GenericInterface/Mapping.pm
).
Ebben a szakaszban egy minta leképezőmodul lesz megjelenítve, és minden szubrutin elmagyarázásra kerül.
# -- # Kernel/GenericInterface/Mapping/Test.pm - GenericInterface test data mapping backend # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::GenericInterface::Mapping::Test; use strict; use warnings; use Kernel::System::VariableCheck qw(IsHashRefWithData IsStringWithData); our $ObjectManagerDisabled = 1;
Ez egy gyakori fejléc, amely megtalálható a szokásos OTRS modulokban. Az
osztály/csomag neve a package
kulcsszón keresztül van
deklarálva.
Felveszünk egy VariableCheck
modult is bizonyos
ellenőrzések végrehajtásához néhány változón. A leképezések nem
példányosíthatók az objektumkezelővel.
sub new { my ( $Type, %Param ) = @_; # új kivonat lefoglalása az objektumhoz my $Self = {}; bless( $Self, $Type ); # a szükséges paraméterek ellenőrzése for my $Needed (qw(DebuggerObject MappingConfig)) { if ( !$Param{$Needed} ) { return { Success => 0, ErrorMessage => "Nincs $Needed!" }; } $Self->{$Needed} = $Param{$Needed}; } # leképezési beállítás ellenőrzése if ( !IsHashRefWithData( $Param{MappingConfig} ) ) { return $Self->{DebuggerObject}->Error( Summary => 'Nincs MappingConfig objektum kivonathivatkozásként tartalommal!', ); } # beállítás ellenőrzése - ha van leképezési beállításunk, akkor annak # nem üres kivonathivatkozásnak kell lennie if ( defined $Param{MappingConfig}->{Config} && !IsHashRefWithData( $Param{MappingConfig}->{Config} ) ) { return $Self->{DebuggerObject}->Error( Summary => 'Van MappingConfig adatokkal, de az adat nem kivonathivatkozás tartalommal!', ); } return $Self; }
A new
konstruktor hozza létre az osztály új példányát. A
kódolási irányelvek szerint az objektumkezelő által nem kezelt más
osztályoknak csak azon objektumait kell a new
konstruktorban létrehozni, amelyek ebben a modulban szükségesek.
sub Map { my ( $Self, %Param ) = @_; # adatok ellenőrzése - csak meghatározatlant vagy kivonathivatkozást fogad el if ( defined $Param{Data} && ref $Param{Data} ne 'HASH' ) { return $Self->{DebuggerObject}->Error( Summary => 'Van adat, de az nem kivonathivatkozás a leképezésteszt háttérprogramban!' ); } # visszatérés, ha az adat üres if ( !defined $Param{Data} || !%{ $Param{Data} } ) { return { Success => 1, Data => {}, }; } # ha nincs beállítás, akkor az azt jelenti, hogy egyszerűen visszaadjuk a bemeneti adatot if ( !defined $Self->{MappingConfig}->{Config} || !defined $Self->{MappingConfig}->{Config}->{TestOption} ) { return { Success => 1, Data => $Param{Data}, }; } # a TestOption formátum ellenőrzése if ( !IsStringWithData( $Self->{MappingConfig}->{Config}->{TestOption} ) ) { return $Self->{DebuggerObject}->Error( Summary => 'Nincs TestOption szövegként értékkel!', ); } # adatok feldolgozása a beállítások szerint my $ReturnData = {}; if ( $Self->{MappingConfig}->{Config}->{TestOption} eq 'ToUpper' ) { $ReturnData = $Self->_ToUpper( Data => $Param{Data} ); } elsif ( $Self->{MappingConfig}->{Config}->{TestOption} eq 'ToLower' ) { $ReturnData = $Self->_ToLower( Data => $Param{Data} ); } elsif ( $Self->{MappingConfig}->{Config}->{TestOption} eq 'Empty' ) { $ReturnData = $Self->_Empty( Data => $Param{Data} ); } else { $ReturnData = $Param{Data}; } # az eredmény visszaadása return { Success => 1, Data => $ReturnData, }; }
A Map
függvény az egyes leképezőmodulok fő része. Fogadja
a leképezési beállításokat (szabályokat) és az eredeti formátumban lévő
adatokat (vagy az OTRS vagy a távoli rendszer formátumában lévőket), és
átalakítja azokat egy új formátumra még akkor is, ha az adatok szerkezete
megváltozhat a leképezési folyamat során.
Ebben a bizonyos példában három szabály van az értékek leképezéséhez. Ezek a
szabályok a leképezési beállítások TestOption
kulcsában
vannak beállítva, és a következők: ToUpper
,
ToLower
és Empty
.
ToUpper
: nagybetűsre alakít át minden egyes adatértéket.
ToLower
: kisbetűsre alakít át minden egyes adatértéket.
Empty
: egy üres szövegre alakít át minden egyes
adatértéket.
Ebben a példában nem lettek adatkulcs átalakítások megvalósítva.
sub _ToUpper { my ( $Self, %Param ) = @_; my $ReturnData = {}; for my $Key ( sort keys %{ $Param{Data} } ) { $ReturnData->{$Key} = uc $Param{Data}->{$Key}; } return $ReturnData; } sub _ToLower { my ( $Self, %Param ) = @_; my $ReturnData = {}; for my $Key ( sort keys %{ $Param{Data} } ) { $ReturnData->{$Key} = lc $Param{Data}->{$Key}; } return $ReturnData; } sub _Empty { my ( $Self, %Param ) = @_; my $ReturnData = {}; for my $Key ( sort keys %{ $Param{Data} } ) { $ReturnData->{$Key} = ''; } return $ReturnData; }
Ezek azok a segédfüggvények, amelyek ténylegesen végrehajtják a szövegátalakításokat.
Szükség van ezen leképezőmodul regisztrálására, hogy elérhető legyen az OTRS grafikus felhasználói felületén. Ezt a lenti XML beállítás használatával lehet megtenni.
<ConfigItem Name="GenericInterface::Mapping::Module###Test" Required="0" Valid="1"> <Description Translatable="1">GenericInterface module registration for the mapping layer.</Description> <Group>GenericInterface</Group> <SubGroup>GenericInterface::Mapping::ModuleRegistration</SubGroup> <Setting> <Hash> <Item Key="ConfigDialog"></Item> </Hash> </Setting> </ConfigItem>
A meghívót arra használják, hogy egy kérést hozzon létre az OTRS-ből egy távoli rendszerhez. Az általános ügyintéző ezen része felelős a szükséges feladatok végrehajtásáért az OTRS oldalán, illetve a szükséges adatok begyűjtéséért a kérés felépítésének érdekében.
Ezután be fogjuk mutatni, hogy hogyan kell egy új meghívót kifejleszteni. Minden egyes meghívónak meg kell valósítania ezeket a szubrutinokat:
new
PrepareRequest
HandleResponse
Meg kell valósítanunk ezen metódusok mindegyikét azért, hogy képesek legyünk
végrehajtani egy kérést a kéréskezelő használatával
(Kernel/GenericInterface/Requester.pm
).
Ebben a szakaszban egy minta meghívómodul lesz megjelenítve, és minden szubrutin elmagyarázásra kerül.
# -- # Kernel/GenericInterface/Invoker/Test.pm - GenericInterface test data Invoker backend # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::GenericInterface::Invoker::Test::Test; use strict; use warnings; use Kernel::System::VariableCheck qw(IsString IsStringWithData); # prevent 'Used once' warning for Kernel::OM use Kernel::System::ObjectManager; our $ObjectManagerDisabled = 1;
Ez egy gyakori fejléc, amely megtalálható a szokásos OTRS modulokban. Az
osztály/csomag neve a package
kulcsszón keresztül van
deklarálva. A meghívók nem példányosíthatók az objektumkezelővel.
sub new { my ( $Type, %Param ) = @_; # új kivonat lefoglalása az objektumhoz my $Self = {}; bless( $Self, $Type ); # a szükséges paraméterek ellenőrzése if ( !$Param{DebuggerObject} ) { return { Success => 0, ErrorMessage => "Nem sikerült lekérni a hibakezelő objektumot!" }; } $Self->{DebuggerObject} = $Param{DebuggerObject}; return $Self; }
A new
konstruktor hozza létre az osztály új példányát. A
kódolási irányelvek szerint az objektumkezelő által nem kezelt más
osztályoknak csak azon objektumait kell a new
konstruktorban létrehozni, amelyek ebben a modulban szükségesek.
sub PrepareRequest { my ( $Self, %Param ) = @_; # szükségünk van egy jegyszámra if ( !IsStringWithData( $Param{Data}->{TicketNumber} ) ) { return $Self->{DebuggerObject}->Error( Summary => 'Nem kaptunk jegyszámot' ); } my %ReturnData; $ReturnData{TicketNumber} = $Param{Data}->{TicketNumber}; # a művelet ellenőrzése if ( IsStringWithData( $Param{Data}->{Action} ) ) { $ReturnData{Action} = $Param{Data}->{Action} . 'Test'; } # a rendszeridő kérésének ellenőrzése if ( IsStringWithData( $Param{Data}->{GetSystemTime} ) && $Param{Data}->{GetSystemTime} ) { $ReturnData{SystemTime} = $Kernel::OM->Get('Kernel::System::Time')->SystemTime(); } return { Success => 1, Data => \%ReturnData, }; }
A PrepareRequest
függvényt használják a kérésbe küldendő
összes szükséges adat kezeléséhez és összegyűjtéséhez. Itt fogadhatunk
adatokat a kéréskezelőtől, használhatjuk azokat, kiterjeszthetjük azokat, új
adatokat állíthatunk elő, és ezután átvihetjük az eredményeket a leképező
réteghez.
Ennél a példánál azt várjuk, hogy kapunk egy jegyszámot. Ha nem, akkor az
Error()
hibakeresési metódust használjuk, amely létrehoz egy
bejegyzést a hibakeresési naplóban, és visszaad egy szerkezetet is a
Success
paraméterrel 0-ként, és egy hibaüzenetet az
átadott Summary
értékként.
Ez a példa hozzáfűzi a „Test” szót is az Action
paraméterhez, és ha a GetSystemTime
kérve volt, akkor ki
fogja tölteni a SystemTime
paramétert az aktuális
rendszeridővel. A kód ezen része azért van, hogy előkészítse az elküldendő
adatokat. Egy valódi meghívónál itt kell elvégezni néhány hívást az
alapmodulokhoz (Kernel/System/*.pm
).
Ha a kérést a PrepareRequest
függvény bármely része
közben le kell állítani a hibakeresési naplóba való bejegyzés előállítása és
hibajelzése nélkül, akkor a következő kód használható:
# a kérelmező kommunikációjának leállítása return { Success => 1, StopCommunication => 1, };
Ennek használatával a kérelmező meg foga érteni, hogy a kérést nem szabad folytatni (nem kerül elküldésre a leképező réteghez, és nem kerül elküldésre a hálózati átvitelhez sem). A kérelmező nem fog hibát küldeni a hibakeresési naplóba, hanem csak csendben le fog állni.
sub HandleResponse { my ( $Self, %Param ) = @_; # ha hiba volt a válaszban, akkor továbbítja if ( !$Param{ResponseSuccess} ) { if ( !IsStringWithData( $Param{ResponseErrorMessage} ) ) { return $Self->{DebuggerObject}->Error( Summary => 'Hiba volt a válaszban, de nincs válasz hibaüzenet!', ); } return { Success => 0, ErrorMessage => $Param{ResponseErrorMessage}, }; } # szükségünk van egy jegyszámra if ( !IsStringWithData( $Param{Data}->{TicketNumber} ) ) { return $Self->{DebuggerObject}->Error( Summary => 'Nem kaptunk jegyszámot!' ); } # a jegyszám előkészítése my %ReturnData = ( TicketNumber => $Param{Data}->{TicketNumber}, ); # a művelet ellenőrzése if ( IsStringWithData( $Param{Data}->{Action} ) ) { if ( $Param{Data}->{Action} !~ m{ \A ( .*? ) Test \z }xms ) { return $Self->{DebuggerObject}->Error( Summary => 'Kaptunk műveletet, nem az nem megfelelő formátumú!', ); } $ReturnData{Action} = $1; } return { Success => 1, Data => \%ReturnData, }; }
A HandleResponse
függvényt használják az előző kérésből
származó adatok fogadásához és feldolgozásához, amelyet a távoli rendszernek
készítettek. Ezeket az adatokat már átadta a leképező réteg, hogy átalakítsa
azokat a távoli rendszer formátumáról az OTRS formátumára (ha szükséges).
Ennél a bizonyos példánál ismét ellenőrzi a jegyszámot, és azt is ellenőrzi,
hogy a művelet a „Test” szóval végződik-e (amint az a
PrepareRequest
függvényben történt).
Ez a meghívó csak tesztelésekhez van, egy valódi meghívó ellenőrizni fogja, hogy a válasz a távoli rendszer által leírt formátumban volt-e, és végrehajthat néhány műveletet, mint például: egy másik meghívó meghívása, egy hívás végrehajtása egy alapmodulhoz, az adatbázis frissítése, hiba küldése, stb.
Szükség van ezen meghívómodul regisztrálására, hogy elérhető legyen az OTRS grafikus felhasználói felületén. Ezt a lenti XML beállítás használatával lehet megtenni.
<ConfigItem Name="GenericInterface::Invoker::Module###Test::Test" Required="0" Valid="1"> <Description Translatable="1">GenericInterface module registration for the invoker layer.</Description> <Group>GenericInterface</Group> <SubGroup>GenericInterface::Invoker::ModuleRegistration</SubGroup> <Setting> <Hash> <Item Key="Name">Test</Item> <Item Key="Controller">Test</Item> <Item Key="ConfigDialog">AdminGenericInterfaceInvokerDefault</Item> </Hash> </Setting> </ConfigItem>
A műveletet egy tevékenység végrehajtásához használják az OTRS-en belül. Ezt a tevékenységet a távoli rendszer kéri, és tartalmazhat különleges paramétereket azért, hogy helyesen végrehajtsa a tevékenységet. A tevékenység végrehajtása után az OTRS elküld egy meghatározott megerősítést a távoli rendszernek.
Ezután be fogjuk mutatni, hogy hogyan kell egy új műveletet kifejleszteni. Minden egyes műveletnek meg kell valósítania ezeket a szubrutinokat:
new
Run
Meg kell valósítanunk ezen metódusok mindegyikét azért, hogy képesek legyünk
végrehajtani a szolgáltató által kezelt műveletet
(Kernel/GenericInterface/Provider.pm
).
Ebben a szakaszban egy minta műveletmodul lesz megjelenítve, és minden szubrutin elmagyarázásra kerül.
# -- # Kernel/GenericInterface/Operation/Test/Test.pm - GenericInterface test operation backend # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::GenericInterface::Operation::Test::Test; use strict; use warnings; use Kernel::System::VariableCheck qw(IsHashRefWithData); our $ObjectManagerDisabled = 1;
Ez egy gyakori fejléc, amely megtalálható a szokásos OTRS modulokban. Az
osztály/csomag neve a package
kulcsszón keresztül van
deklarálva.
Felveszünk egy VariableCheck
modult is bizonyos
ellenőrzések végrehajtásához néhány változón. A műveletek nem
példányosíthatók az objektumkezelővel.
sub new { my ( $Type, %Param ) = @_; my $Self = {}; bless( $Self, $Type ); # a szükséges objektumok ellenőrzése for my $Needed (qw(DebuggerObject)) { if ( !$Param{$Needed} ) { return { Success => 0, ErrorMessage => "Nincs $Needed!" }; } $Self->{$Needed} = $Param{$Needed}; } return $Self; }
A new
konstruktor hozza létre az osztály új példányát. A
kódolási irányelvek szerint az objektumkezelő által nem kezelt más
osztályoknak csak azon objektumait kell a new
konstruktorban létrehozni, amelyek ebben a modulban szükségesek.
sub Run { my ( $Self, %Param ) = @_; # adatok ellenőrzése - csak meghatározatlant vagy kivonathivatkozást fogad el if ( defined $Param{Data} && ref $Param{Data} ne 'HASH' ) { return $Self->{DebuggerObject}->Error( Summary => 'Van adat, de az nem kivonathivatkozás a műveletteszt háttérprogramban!' ); } if ( defined $Param{Data} && $Param{Data}->{TestError} ) { return { Success => 0, ErrorMessage => "Hibaüzenet a következő hibakódhoz: $Param{Data}->{TestError}", Data => { ErrorData => $Param{Data}->{ErrorData}, }, }; } # adatok másolása my $ReturnData; if ( ref $Param{Data} eq 'HASH' ) { $ReturnData = \%{ $Param{Data} }; } else { $ReturnData = undef; } # az eredmény visszaadása return { Success => 1, Data => $ReturnData, }; }
A Run
függvény az egyes műveletek fő része. Fogadja az
összes belsőleg leképezett adatot a távoli rendszertől, amelyre a
szolgáltatónak szüksége van a művelet végrehajtásához, végrehajtja a
műveletet, és visszaadja az eredményt a szolgáltatónak a külső leképezéshez,
valamint visszaszállítja a távoli rendszerhez.
Ez a bizonyos példa ugyanúgy adja vissza az adatokat, ahogy azok a távoli
rendszertől jönnek, hacsak a TestError
paraméter át nincs
adva. Ebben az esetben egy hibát ad vissza.
Szükség van ezen műveletmodul regisztrálására, hogy elérhető legyen az OTRS grafikus felhasználói felületén. Ezt a lenti XML beállítás használatával lehet megtenni.
<ConfigItem Name="GenericInterface::Operation::Module###Test::Test" Required="0" Valid="1"> <Description Translatable="1">GenericInterface module registration for the operation layer.</Description> <Group>GenericInterface</Group> <SubGroup>GenericInterface::Operation::ModuleRegistration</SubGroup> <Setting> <Hash> <Item Key="Name">Test</Item> <Item Key="Controller">Test</Item> <Item Key="ConfigDialog">AdminGenericInterfaceOperationDefault</Item> </Hash> </Setting> </ConfigItem>
Unit Test for Generic Interface operations does not differs from other unit tests but it is needed to consider testing locally, but also simulating a remote connection. It is a good practice to test both separately since results could be slightly different.
To learn more about unit tests, please take a look to the Unit Test Chapter.
The following is just the starting point for a unit test:
# -- # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- ## no critic (Modules::RequireExplicitPackage) use strict; use warnings; use utf8; use vars (qw($Self)); use Kernel::GenericInterface::Debugger; use Kernel::GenericInterface::Operation::Test::Test; use Kernel::System::VariableCheck qw(:all); # Skip SSL certificate verification (RestoreDatabase must not be used in this test). $Kernel::OM->ObjectParamAdd( 'Kernel::System::UnitTest::Helper' => { SkipSSLVerify => 1, }, ); my $Helper = $Kernel::OM->Get('Kernel::System::UnitTest::Helper'); # get a random number my $RandomID = $Helper->GetRandomNumber(); # create a new user for current test my $UserLogin = $Helper->TestUserCreate( Groups => ['users'], ); my $Password = $UserLogin; my $UserID = $Kernel::OM->Get('Kernel::System::User')->UserLookup( UserLogin => $UserLogin, ); # set web-service name my $WebserviceName = '-Test-' . $RandomID; # create web-service object my $WebserviceObject = $Kernel::OM->Get('Kernel::System::GenericInterface::Webservice'); $Self->Is( 'Kernel::System::GenericInterface::Webservice', ref $WebserviceObject, "Create web service object", ); my $WebserviceID = $WebserviceObject->WebserviceAdd( Name => $WebserviceName, Config => { Debugger => { DebugThreshold => 'debug', }, Provider => { Transport => { Type => '', }, }, }, ValidID => 1, UserID => 1, ); $Self->True( $WebserviceID, "Added Web Service", ); # get remote host with some precautions for certain unit test systems my $Host = $Helper->GetTestHTTPHostname(); my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); # prepare web-service config my $RemoteSystem = $ConfigObject->Get('HttpType') . '://' . $Host . '/' . $ConfigObject->Get('ScriptAlias') . '/nph-genericinterface.pl/WebserviceID/' . $WebserviceID; my $WebserviceConfig = { Description => 'Test for Ticket Connector using SOAP transport backend.', Debugger => { DebugThreshold => 'debug', TestMode => 1, }, Provider => { Transport => { Type => 'HTTP::SOAP', Config => { MaxLength => 10000000, NameSpace => 'http://otrs.org/SoapTestInterface/', Endpoint => $RemoteSystem, }, }, Operation => { Test => { Type => 'Test::Test', }, }, }, Requester => { Transport => { Type => 'HTTP::SOAP', Config => { NameSpace => 'http://otrs.org/SoapTestInterface/', Encoding => 'UTF-8', Endpoint => $RemoteSystem, }, }, Invoker => { Test => { Type => 'Test::TestSimple' , # requester needs to be Test::TestSimple in order to simulate a request to a remote system }, }, }, }; # update web-service with real config # the update is needed because we are using # the WebserviceID for the Endpoint in config my $WebserviceUpdate = $WebserviceObject->WebserviceUpdate( ID => $WebserviceID, Name => $WebserviceName, Config => $WebserviceConfig, ValidID => 1, UserID => $UserID, ); $Self->True( $WebserviceUpdate, "Updated Web Service $WebserviceID - $WebserviceName", ); # debugger object my $DebuggerObject = Kernel::GenericInterface::Debugger->new( DebuggerConfig => { DebugThreshold => 'debug', TestMode => 1, }, WebserviceID => $WebserviceID, CommunicationType => 'Provider', ); $Self->Is( ref $DebuggerObject, 'Kernel::GenericInterface::Debugger', 'DebuggerObject instantiate correctly', ); # define test cases my @Tests = ( { Name => 'Test case name', SuccessRequest => 1, # 1 or 0 RequestData => { # ... add test data }, ExpectedReturnLocalData => { Data => { # ... add expected local results }, Success => 1, # 1 or 0 }, ExpectedReturnRemoteData => { Data => { # ... add expected remote results }, Success => 1, # 1 or 0 }, Operation => 'Test', }, # ... add more test cases ); TEST: for my $Test (@Tests) { # create local object my $LocalObject = "Kernel::GenericInterface::Operation::Test::$Test->{Operation}"->new( DebuggerObject => $DebuggerObject, WebserviceID => $WebserviceID, ); $Self->Is( "Kernel::GenericInterface::Operation::Test::$Test->{Operation}", ref $LocalObject, "$Test->{Name} - Create local object", ); my %Auth = ( UserLogin => $UserLogin, Password => $Password, ); if ( IsHashRefWithData( $Test->{Auth} ) ) { %Auth = %{ $Test->{Auth} }; } # start requester with our web-service my $LocalResult = $LocalObject->Run( WebserviceID => $WebserviceID, Invoker => $Test->{Operation}, Data => { %Auth, %{ $Test->{RequestData} }, }, ); # check result $Self->Is( 'HASH', ref $LocalResult, "$Test->{Name} - Local result structure is valid", ); # create requester object my $RequesterObject = $Kernel::OM->Get('Kernel::GenericInterface::Requester'); $Self->Is( 'Kernel::GenericInterface::Requester', ref $RequesterObject, "$Test->{Name} - Create requester object", ); # start requester with our web-service my $RequesterResult = $RequesterObject->Run( WebserviceID => $WebserviceID, Invoker => $Test->{Operation}, Data => { %Auth, %{ $Test->{RequestData} }, }, ); # check result $Self->Is( 'HASH', ref $RequesterResult, "$Test->{Name} - Requester result structure is valid", ); $Self->Is( $RequesterResult->{Success}, $Test->{SuccessRequest}, "$Test->{Name} - Requester successful result", ); # ... add tests for the results } # delete web service my $WebserviceDelete = $WebserviceObject->WebserviceDelete( ID => $WebserviceID, UserID => $UserID, ); $Self->True( $WebserviceDelete, "Deleted Web Service $WebserviceID", ); # also delete any other added data during the this test, since RestoreDatabase must not be used. 1;
WSDL files contain the definitions of the web services and its operations
for SOAP messages, in case we will extend
development/webservices/GenericTickeConnectorSOAP.wsdl
in some places:
Port Type:
<wsdl:portType name="GenericTicketConnector_PortType"> <!-- ... --> <wsdl:operation name="Test"> <wsdl:input message="tns:TestRequest"/> <wsdl:output message="tns:TestResponse"/> </wsdl:operation> <!-- ... -->
Binding:
<wsdl:binding name="GenericTicketConnector_Binding" type="tns:GenericTicketConnector_PortType"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/> <!-- ... --> <wsdl:operation name="Test"> <soap:operation soapAction="http://www.otrs.org/TicketConnector/Test"/> <wsdl:input> <soap:body use="literal"/> </wsdl:input> <wsdl:output> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> <!-- ... --> </wsdl:binding>
Type:
<wsdl:types> <xsd:schema targetNamespace="http://www.otrs.org/TicketConnector/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!-- ... --> <xsd:element name="Test"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="0" name="Param1" type="xsd:string"/> <xsd:element minOccurs="0" name="Param2" type="xsd:positiveInteger"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="TestResponse"> <xsd:complexType> <xsd:sequence> <xsd:element maxOccurs="unbounded" minOccurs="1" name="Attribute1" type="xsd:string"/> </xsd:sequence> </xsd:complexType> </xsd:element> <!-- ... --> </xsd:schema> </wsdl:types>
Message:
<!-- ... --> <wsdl:message name="TestRequest"> <wsdl:part element="tns:Test" name="parameters"/> </wsdl:message> <wsdl:message name="TestResponse"> <wsdl:part element="tns:TestResponse" name="parameters"/> </wsdl:message> <!-- ... -->
WADL files contain the definitions of the web services and its operations
for REST interface, add a new resource to
development/webservices/GenericTickeConnectorREST.wadl
.
<resources base="http://localhost/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST"> <!-- ... --> <resource path="Test" id="Test"> <doc xml:lang="en" title="Test"/> <param name="Param1" type="xs:string" required="false" default="" style="query" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> <param name="Param2" type="xs:string" required="false" default="" style="query" xmlns:xs="http://www.w3.org/2001/XMLSchema"/> <method name="GET" id="GET_Test"> <doc xml:lang="en" title="GET_Test"/> <request/> <response status="200"> <representation mediaType="application/json; charset=UTF-8"/> </response> </method> </resource> </resource> <!-- ... --> </resources>
Web services can be imported into OTRS by a YAML with a predefined structure
in this case we will extend
development/webservices/GenericTickeConnectorSOAP.yml
for a SOAP web service.
Provider: Operation: # ... Test: Description: This is only a test MappingInbound: {} MappingOutbound: {} Type: Test::Test
Web services can be imported into OTRS by a YAML with a predefined structure
in this case we will extend
development/webservices/GenericTickeConnectorREST.yml
for a REST web service.
Provider: Operation: # ... Test: Description: This is only a test MappingInbound: {} MappingOutbound: {} Type: Test::Test # ... Transport: Config: # ... RouteOperationMapping: # .. Test: RequestMethod: - GET Route: /Test
Az OTRS démon egy elkülönített folyamat, amely segít az OTRS-nek bizonyos műveleteket aszinkron módon és a webszolgáltatás folyamattól leválasztva végrehajtani, de ugyanazt az adatbázist megosztva.
A bin/otrs.Daemon.pl
OTRS démon fő célja, hogy meghívja
(démonizálja) a rendszerbeállításokban lévő összes regisztrált démonmodult.
Minden egyes démonmodulnak meg kell valósítania egy közös API-t annak érdekében, hogy az OTRS démon helyesen tudja meghívni, és félig állandó folyamat legyen a rendszeren. Az állandó folyamat megnövelheti a méretét és memóriahasználatát az idő múlásával, és normális esetben nem válaszolnak a beállításokban lévő változásokra. Ezért kell a démonmoduloknak megvalósítaniuk egy eldobási mechanizmust, hogy leállíthatók és újra meghívhatók legyenek időről időre, felszabadítva a rendszer erőforrásait és újraolvasva a beállításokat.
Egy démonmodul lehet mindenre jó megoldás bizonyos feladat végrehajtásánál, de lehet olyan eset is, amikor egy megoldás különböző démonmodulokat igényel az összetettsége miatt. Pontosan ez az eset az OTRS ütemező démonjával, amely fel van osztva számos démonmodulra, beleértve a feladatkezeléshez és a feladatvégrehajtáshoz szükséges néhány démonmodult.
Nem szükséges mindig új démonmodult létrehozni bizonyos feladatok végrehajtásához. Általában az OTRS ütemező démon elboldogul ezek jelentős részével – akár ha egy olyan OTRS függvényről van szó, amelyet rendszeresen végre kell hajtani (CRON-szerűen), vagy ha egy OTRS esemény aktiválta azt – az OTRS ütemezőnek képesnek kell lenni kezelnie mindenféle beállítás nélkül, vagy egy új ütemező feladatelvégző modul hozzáadásával.
Az összes démonmodulnak regisztrálva kell lennie a rendszerbeállításokban azért, hogy a fő OTRS démon meg tudja hívni azokat.
<ConfigItem Name="DaemonModules###TestDaemon" Required="1" Valid="1"> <Description Translatable="1">The daemon registration for the scheduler generic agent task manager.</Description> <Group>Daemon</Group> <SubGroup>Core::Daemon::ModuleRegistration</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::System::Daemon::DaemonModules::TestDaemon</Item> </Hash> </Setting> </ConfigItem>
A következő kód egy olyan démonmodult valósít meg, amely megjeleníti a rendszeridőt 2 másodpercenként.
# -- # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::Daemon::DaemonModules::TestDaemon; use strict; use warnings; use utf8; use Kernel::System::VariableCheck qw(:all); use parent qw(Kernel::System::Daemon::BaseDaemon); our @ObjectDependencies = ( 'Kernel::Config', 'Kernel::System::Cache', 'Kernel::System::DB', );
This is common header that can be found in most OTRS modules. The
class/package name is declared via the package
keyword.
Ebben az esetben a BaseDaemon
osztályból származtatunk
le, és az objektumkezelő függőségei be vannak állítva.
sub new { my ( $Type, %Param ) = @_; # Új kivonat lefoglalása az objektumhoz. my $Self = {}; bless $Self, $Type; # Objektumok lekérése a konstruktorban a teljesítmény megtartásáért. $Self->{ConfigObject} = $Kernel::OM->Get('Kernel::Config'); $Self->{CacheObject} = $Kernel::OM->Get('Kernel::System::Cache'); $Self->{DBObject} = $Kernel::OM->Get('Kernel::System::DB'); # Letiltás a memóriagyorsítótárban, hogy fürtözhető legyen. $Self->{CacheObject}->Configure( CacheInMemory => 0, CacheInBackend => 1, ); $Self->{SleepPost} = 2; # 2 másodperc alvás minden hurok után $Self->{Discard} = 60 * 60; # eldobás minden órában $Self->{DiscardCount} = $Self->{Discard} / $Self->{SleepPost}; $Self->{Debug} = $Param{Debug}; $Self->{DaemonName} = 'Daemon: TestDaemon'; return $Self; }
A new
konstruktor hozza létre az osztály új
példányát. Néhány felhasznált objektum is itt lesz létrehozva. Erősen
ajánlott a memóriába történő gyorsítótárazás letiltása a démonmodulokban,
különösen akkor, ha az OTRS fürtözött környezetben fut.
Azért, hogy ez a démonmodul minden második másodpercben végrehajtható legyen, egy alvási idő meghatározása szükséges annak megfelelően, egyébként azonnal végrehajtásra kerül, amint lehetséges.
A démonmodul frissítése időről időre azért szükséges, hogy meghatározható legyen, mikor kell eldobni.
A következő függvényeknél (PreRun
, Run
és PostRun
) ha azok hamis értékkel térnek vissza, akkor a
fő OTRS démon el fogja dobni az objektumot, és egy újat hoz létre, amint
lehetséges.
sub PreRun { my ( $Self, %Param ) = @_; # Annak ellenőrzése, hogy az adatbázis elérhető-e. return 1 if $Self->{DBObject}->Ping(); sleep 10; return; }
A PreRun
metódus a fő démonmodul metódusa előtt kerül
végrehajtásra, és a célja néhány teszt elvégzése a valódi műfelet
előtt. Ebben az esetben az adatbázis ellenőrzése készen van (mindig
javasolt), egyébként 10 másodpercet alszik. Ez azért szükséges, hogy
megvárja az adatbázis-kapcsolat ismételt felépítését.
sub Run { my ( $Self, %Param ) = @_; print "Jelenlegi idő: " . localtime . "\n"; return 1; }
A Run
metódus az, ahol a fő démonmodul kódja
található. Ebben az esetben csak az aktuális időt írja ki.
sub PostRun { my ( $Self, %Param ) = @_; sleep $Self->{SleepPost}; $Self->{DiscardCount}--; if ( $Self->{Debug} ) { print " $Self->{DaemonName} eldobásainak száma: $Self->{DiscardCount}\n"; } return if $Self->{DiscardCount} <= 0; return 1; }
A PostRun
metódus használható az alvások végrehajtásához
(annak megakadályozásához, hogy a démonmodul túl gyakran legyen
végrehajtva), valamint az objektum biztonságos eldobásának kezeléséhez
is. Egyéb műveletek is elvégezhetők itt, mint például ellenőrzés vagy
tisztítás.
sub Summary { my ( $Self, %Param ) = @_; my %Summary = ( Header => 'Tesztdémon összegzés:', Column => [ { Name => 'SomeColumn', DisplayName => 'Valamilyen oszlop', Size => 15, }, { Name => 'AnotherColumn', DisplayName => 'Egy másik oszlop', Size => 15, }, # ... ], Data => [ { SomeColumn => '1. valamilyen adat', AnotherColumn => '1. másik adat', }, { SomeColumn => '2. valamilyen adat', AnotherColumn => '2. másik adat', }, # ... ], NoDataMesssage => '', ); return \%Summary; }
A Summary
metódust a
Maint::Daemon::Summary
konzolparancs hívja meg, és
Header
, Column
,
Data
és NoDataMessages
kulcsokat kell
visszaadnia. A Column
és a Data
kulcsoknak tömböknek vagy kivonatoknak kell lenniük. Arra használható, hogy
hasznos információkat jelenítsen meg arról, amit a démonmodul éppen csinál,
vagy ami eddig történt. Ez a metódus elhagyható.
1;
Fájl vége.
Az OTRS ütemező a démonmodulok és a feladatelvégzők együttese, amelyek együtt futnak azért, hogy az összes szükséges OTRS feladatot aszinkron módon végrehajtsák a webkiszolgáló folyamatából.
A SchedulerCronTaskManager
kiolvassa a regisztrált
cron-feladatokat az OTRS rendszerbeállításaiból, és meghatározza a helyes
időt a végrehajtandó feladat létrehozásához.
A SchedulerFutureTaskManager
ellenőrzi azokat a
feladatokat, amelyek úgy vannak beállítva, hogy csak egy alkalommal fussanak
a jövőben, és beállítja, hogy a feladat időben kerüljön
végrehajtásra. Például amikor egy általános felület meghívónak nem sikerül
elérnie a távoli kiszolgálót, akkor ütemezni tudja magát, hogy 5 perccel
később újra fusson.
A SchedulerGenericAgentTaskManager
folyamatosan olvassa a
GenericAgent
feladatot, amely rendszeres időközönkénti
futáshoz van beállítva, és annak megfelelően állítja be azok végrehajtását.
Amikor ezek a feladatkezelők nem elegendőek, akkor egy új démonmodul hozható
létre. Egy feladat regisztrálásához a Run()
metódusuk egy
bizonyos pontján meg kell hívni a TaskAdd()
függvényt a
chedulerDB
objektumból, és amint regisztrálva lett, akkor
a SchedulerTaskWorker
végrehajtja a következő szabad
időszeletben.
A SchedulerTaskWorker
az aszinkron végrehajtó
használatával végrehajtja az előző feladatkezelő által tervezett összes
feladatot, és még azokat is, amelyek közvetlenül a kódból jönnek.
Annak érdekében, hogy az összes feladatot végrehajtsa, a
SchedulerTaskWorker
meghív egy háttérprogram-modult
(feladatelvégzőt) az adott feladat végrehajtásához. Az elvégző modult a
feladat típusa határozza meg. Ha új feladattípus kerül hozzáadásra, akkor az
új feladatelvégzőt is igényel.
A
Kernel/System/Daemon/DaemonModules/SchedulerTaskWorker
mappa alatt elhelyezett összes fájl lehet potenciális feladatelvégző, és
azok nem igényelnek semmilyen regisztrációt a rendszerbeállításokban.
# -- # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::Daemon::DaemonModules::SchedulerTaskWorker::TestWorker; use strict; use warnings; use parent qw(Kernel::System::Daemon::DaemonModules::BaseTaskWorker); our @ObjectDependencies = ( 'Kernel::System::Log', );
This is common header that can be found in most OTRS modules. The
class/package name is declared via the package
keyword.
Ebben az esetben a BaseTaskWorker
osztályból
származtatunk le, és az objektumkezelő függőségei be vannak állítva.
sub new { my ( $Type, %Param ) = @_; my $Self = {}; bless( $Self, $Type ); $Self->{Debug} = $Param{Debug}; $Self->{WorkerName} = 'Worker: Test'; return $Self; }
A new
konstruktor hozza létre az osztály új példányát.
sub Run { my ( $Self, %Param ) = @_; # Feladatparaméterek ellenőrzése. my $CheckResult = $Self->_CheckTaskParams( %Param, NeededDataAttributes => [ 'NeededAtrribute1', 'NeededAtrribute2' ], DataParamsRef => 'HASH', # vagy 'ARRAT' ); # Végrehajtás leállítása, ha hiba található a paraméterekben. return if !$CheckResult; my $Success; my $ErrorMessage; if ( $Self->{Debug} ) { print " $Self->{WorkerName} végrehajtja a feladatot: $Param{TaskName}\n"; } do { # A szabványos hiba lokalizálása. local *STDERR; # A szabványos hiba átirányítása egy változóba. open STDERR, ">>", \$ErrorMessage; $Success = $Kernel::OM->Get('Kernel::System::MyPackage')->Run( Param1 => 'someparam', ); }; if ( !$Success ) { $ErrorMessage ||= "$Param{TaskName} végrehajtása sikertelen egy hibaüzenettel!"; $Self->_HandleError( TaskName => $Param{TaskName}, TaskType => 'Test', LogMessage => "Hiba történt a(z) $Param{TaskName} végrehajtásakor: $ErrorMessage", ErrorMessage => "$ErrorMessage", ); } return $Success; }
A Run
a fő metódus. Egy
_CheckTaskParams()
hívás az alaposztályból megspórol
néhány kódsort. A feladat végrehajtása a szabványos hibakimenet megszerzése
közben nagyon jó gyakorlat, mivel az OTRS ütemező normális esetben
felügyelet nélkül fut, és az összes hiba egy változóba történő mentése
lehetővé fogja tenni a későbbi feldolgozást. A
_HandleError()
közös felületet biztosít a hibaüzenetek
e-mailben történő küldéséhez a rendszerbeállításokban megadott címzetteknek.
1;
Fájl vége.
A dinamikus mezők olyan egyéni mezők, amelyek hozzáadhatók egy képernyőhöz, hogy javítsák és információkat adjanak hozzá egy objektumhoz (például egy jegyhez vagy egy bejegyzéshez).
A dinamikus mezők a jegy és a bejegyzés szabad mezőinek
(TikcetFreeText
, TicketFreeKey
,
TicketFreeTime
, ArticleFreeText
,
ArticleFreeKey
és ArticleFreeTime
)
evolúciója az OTRS régebbi verzióiból.
Az OTRS 3.1-es verziójától a régi szabad mezőket lecserélték az új dinamikus mezőkre. A korábbi verziókról történő frissítéskor a jobb visszafelé kompatibilitáshoz és az adatmegőrzéshez egy költöztető parancsfájlt fejlesztettek ki a meglévő szabad mezők dinamikus mezőkre való átalakításához, és azok értékeinek áthelyezéséhez az adatbázisban lévő ticket és article táblákból az új dinamikus mezők tábláiba.
Minden szabad mezőket használó egyéni fejlesztést át kell írni az új dinamikus mezők kódszerkezetére, különben többé nem fognak működni. Emiatt nagyon fontos tudni azt, hogy az OTRS 3.0-nak csak a frissített telepítései rendelkeznek a dinamikus mezőkre átalakított régi szabad mezőkkel, az OTRS új vagy tiszta telepítéseinek nincsenek „eredetileg” meghatározott dinamikus mezői, és az egyéni fejlesztés által szükséges összes dinamikus mezőt hozzá kell adni.
A jegyenkénti vagy bejegyzésenkénti mezők számának korlátozása eltávolításra került. Ez azt jelenti, hogy egy jegy vagy egy bejegyzés annyi mezővel rendelkezhet, amennyi szükséges. És mostantól lehetséges a dinamikus mezők keretrendszerének használata egyéb objektumoknál is ahelyett, hogy csak a jegynél vagy a bejegyzésnél lenne használható.
Az új dinamikus mezők ugyanazokat az adattípusokat tudják eltárolni mint a szabad mezők (szöveg és dátum/idő), és ugyanúgy határozhatók meg mint azok (egysoros beviteli mező, legördülő és dátum/idő), de a dinamikus mezők túlmennek ezen, ugyanis egy új egész szám adattípus került hozzáadásra, valamint új lehetőségek is az olyan mezők meghatározásához, mint például többsoros beviteli mezők, jelölőnégyzetek, többválasztós mezők és (idő nélküli) dátum mezők. Minden egyes mezőtípus saját adattípust határoz meg.
A moduláris tervezésének köszönhetően az egyes dinamikus mezőtípusok egy keretrendszerhez tartozó bővítményként láthatók, és ez a bővítmény lehet egy szabványos OTRS csomag is a dinamikus mezők elérhető típusainak kiterjesztéséhez, vagy akár a jelenlegi dinamikus mező további függvényekkel való kiterjesztéséhez.
Az új dinamikus mezők létrehozása előtt szükséges megérteni azok keretrendszerét, és hogy az OTRS képernyők hogyan lépnek kölcsönhatásba azokkal, valamint a mögöttes API-t.
A következő kép a dinamikus mezők keretrendszer szerkezetét mutatja be.
Az előtétprogram modulokban normális esetben a
BackendObject
nevű objektum a közvetítő az előtétprogram
modulok és az egyes konkrét dinamikus mező megvalósítás vagy illesztőprogram
között. Ez határoz meg egy általános közbenső API-t az összes dinamikus mező
illesztőprogramhoz, és az egyes illesztőprogramok felelőssége a közbenső API
megvalósítása a mező sajátos szükségleteihez.
A dinamikus mező háttérprogram az összes illesztőprogram fő vezérlője. Ebben a modulban minden egyes függvény felelős a szükséges paraméterek ellenőrzéséért, és ugyanazon függvény meghívásáért az adott illesztőprogramban a kapott dinamikus mező beállítási paraméter szerint.
Ez a modul felelős bizonyos függvények meghívásáért is minden egyes objektumtípus delegáltnál (úgymint jegy vagy bejegyzés). Például egy előzmény bejegyzés hozzáadásához vagy egy esemény elsütéséhez.
Ez a modul az
$OTRS_HOME/Kernel/System/DynamicField/Backend.pm
fájlban található.
Egy dinamikus mező illesztőprogram a dinamikus mező megvalósítása. Minden egyes illesztőprogramnak meg kell valósítania a háttérprogramban meghatározott összes kötelező függvényt (van néhány olyan függvény, amely egy viselkedéstől függ, és nem szükséges megvalósítani azokat, ha a dinamikus mező nem rendelkezik azzal a bizonyos viselkedéssel).
Egy illesztőprogram felelős annak ismeretéért, hogy hogyan kérje le a saját értékét vagy értékeit egy webkérésből vagy egy profilból (mint például egy keresési profilból). Szükséges tudnia a HTML kódot is a szerkesztő vagy megjelenítő képernyőkön lévő mező megjelenítéséhez, vagy hogy hogyan lépjen kölcsönhatásba a statisztikák modullal, többek között a függvényekkel.
Ezek a modulok az
$OTRS_HOME/Kernel/System/DynamicField/Driver/*.pm
fájlokban találhatók.
Létezik néhány alap illesztőprogram, úgymint Base.pm
,
BaseText.pm
, BaseSelect.pm
és
BaseDateTime.pm
, amely gyakori függvényeket valósít meg
bizonyos illesztőprogramokhoz (például a TextArea.pm
illesztőprogram a BaseText.pm
fájlt használja, amely a
Base.pm
fájlt használja, ekkor a
TextArea
csak azon függvények megvalósítását igényli,
amelyek hiányoznak a Base.pm
és
BateText.pm
fájlokból, vagy azokat, amelyek különleges
esetek).
A következő az illesztőprogramok öröklődési fája:
Base.pm
BaseText.pm
Text.pm
TextArea.pm
BaseSelect.pm
Dropdown.pm
Multiselect.pm
BaseDateTime.pm
DateTime.pm
Date.pm
Checkbox.pm
Egy objektumtípus delegált felelős bizonyos függvények végrehajtásáért a dinamikus mezőhöz kapcsolt objektumon. Ezeket a függvényeket a háttérprogram objektum aktiválja, amint szükség van rájuk.
Ezek a modulok az
$OTRS_HOME/Kernel/System/DynamicField/ObjectType/*.pm
fájlokban találhatók.
A dinamikus mezők kezeléséhez (hozzáadás, szerkesztés és felsorolás) már egy
csomó modul van kifejlesztve. Van egy bizonyos fő modul
(AdminDynamicField.pm
), amely megjeleníti a
meghatározott dinamikus mezők listáját, és más modulokon belülről hívják meg
új dinamikus mezők létrehozásához vagy a meglévők módosításához.
Normális esetben egy dinamikus mező illesztőprogramnak saját adminisztrátori
modulra van szüksége (adminisztrátori párbeszédablak) a tulajdonságai
meghatározásához. Ez a párbeszédablak esetleg eltérhet a többi
illesztőprogramtól. De ez nem kötelező, az illesztőprogramok megoszthatják
az adminisztrátori párbeszédablakokat, ha szükséges információkat
biztosíthatnak az összes olyan illesztőprogramhoz, amelyek hozzájuk vannak
kapcsolva, nem számít, hogy eltérő típusból származnak. Ami kötelező, hogy
minden egyes illesztőprogramnak hozzákapcsolva kell lennie egy
adminisztrátori párbeszédablakhoz (például a szöveg és a szövegterület
illesztőprogramok megosztják az
AdminDynamicFieldText.pm
adminisztrátori
párbeszédablakot, és a dátum és a dátum/idő illesztőprogramok megosztják az
AdminDynamicFieldDateTime.pm
adminisztrátori
párbeszédablakot).
Az adminisztrátori párbeszédablakok a normál OTRS adminisztrátori modulszabályokat és szerkezetet követik. De a szabványosításhoz az összes beállítás közös részének az összes dinamikus mezőnél ugyanolyan megjelenésűnek kell lennie az összes adminisztrátori párbeszédablaknál.
Ezek a modulok az $OTRS_HOME/Kernel/Modules/*.pm
fájlokban találhatók.
Minden adminisztrátori párbeszédablaknak szüksége van a neki megfelelő HTML
sablonfájlra (.tt
).
Ezek a modulok olvassák és írják a dinamikus mezők információit az adatbázistáblákban.
Ez a modul felelős a dinamikus mező meghatározások kezeléséért. Ez
biztosítja az alap API-t a hozzáadáshoz, megváltoztatáshoz, törléshez,
felsoroláshoz és a dinamikus mezők lekéréséhez. Ez a modul az
$OTRS_HOME/Kernel/System/DynamicField.pm
fájlban
található.
Két tábla van az adatbázisban a dinamikus mező információinak tárolásához:
dynamic_field: a DynamicField.pm
alapmodul használja, és a dinamikus mező meghatározásokat tárolja.
dynamic_field_value: a
DynamicFieldValue.pm
alapmodul használja a dinamikus
mező értékeinek mentéséhez minden egyes dinamikus mező és minden egyes
objektumtípus példánynál.
A háttérprogram modulnak szüksége van egy módra megtudni azt, hogy mely illesztőprogramok léteznek, mivel az illesztőprogramok mennyisége egyszerűen kiterjeszthető. Ezek kezelésének legegyszerűbb módja a rendszerbeállítás használata, ahol a dinamikus mező illesztőprogramok és az objektumtípus illesztőprogramok információi eltárolhatók és kiterjeszthetők.
A fő adminisztrátori modulnak is szükséges tudnia ezeket az információkat az elérhető dinamikus mező illesztőprogramokról a hozzájuk kapcsolt adminisztrátori párbeszédablakok használatához, a dinamikus mezők létrehozásához vagy módosításához.
Az előtétprogram moduloknak szükségük van a rendszerbeállítások olvasására
megtudni azt, hogy mely dinamikus mezők vannak bekapcsolva az egyes
képernyőknél, és melyek kötelezőek. Például a
Ticket::Frontend::AgentTicketPhone###DynamicField
tárolja
az aktív, kötelező és inaktív dinamikus mezőket az új telefonos jegy
képernyőnél.
Ismerve azt, hogy az előtétprogram modulok hogyan lépnek kölcsönhatásba a dinamikus mezőkkel, nem feltétlenül szükséges a dinamikus mezők kiterjesztése a jegy vagy bejegyzés objektumokhoz, mivel már elő van készítve az összes olyan képernyő, amely dinamikus mezőket tud használni. De egyéni fejlesztések esetén vagy a dinamikus mezők más objektumokhoz történő kiterjesztéséhez nagyon hasznos tudni, hogy a dinamikus mezők keretrendszere hogyan érhető el egy előtétprogram modulból.
A következő kép egy egyszerű példáját mutatja be annak, hogy a dinamikus mezők hogyan lépnek kölcsönhatásba az OTRS keretrendszer többi részével.
Az első lépés, hogy az előtétprogram modul beolvassa a beállított dinamikus
mezőket. Például az AgentTicketNote
modulnak be kell
olvasnia a
Ticket::Frontend::AgentTicketNote###DynamicField
beállítást. Ez a beállítás használható szűrőparaméterként a
DynamicFieldListGet()
dinamikus mező alapmodul függvénynél. A
képernyő tárolhatja ennek a függvénynek az eredményeit, hogy meglegyen az
aktivált dinamikus mezők listája ennél a bizonyos képernyőnél.
Ezután a képernyőnek meg kell próbálnia lekérni az értékeket a
webkérésből. Erre a célra használhatja az EditFieldValueGet()
háttérprogram-objektum függvényt, és használhatja ezeket az értékeket az
ACL-ek aktiválásához. A háttérprogram-objektum minden egyes
illesztőprogramot használni fog a különleges műveletek végrehajtásához az
összes függvénynél.
A folytatáshoz a képernyőnek le kell kérnie a HTML-t minden egyes mezőhöz
annak megjelenítéséhez. Az EditFieldRender()
háttérprogram-objektum függvény használható ezen művelet és az ACL-ek
korlátozásának végrehajtásához, valamint a webkérésből származó értékek
átadhatók ennek a függvénynek azért, hogy jobb eredményeket kapjon. Egy
elküldés esetén a képernyő használhatja az
EditFieldValueValidate()
háttérprogram-objektum függvényt is a
kötelező mezők ellenőrzéséhez.
A többi képernyő használhatja a DisplayFieldRender()
függvényt
az EditFieldRender()
helyett, ha a képernyő csak a mezőértéket
jeleníti meg, és ilyen esetben nincs szükség értékellenőrzésre.
A dinamikus mező értékének tárolásához szükséges az objektumazonosító
lekérése. Ennél a példánál ha a dinamikus mező hozzá van kapcsolva egy jegy
objektumhoz, akkor a képernyőnek már rendelkeznie kell a jegyazonosítóval,
egyébként ha a mező hozzá van kapcsolva egy bejegyzés objektumhoz azért,
hogy beállítsa a mező értékét, akkor először a bejegyzés létrehozása
szükséges. A háttérprogram-objektumból a ValueSet()
függvény
használható a dinamikus mező értékének beállításához.
Összefoglalva, az előtétprogram moduloknak nem szükséges tudniuk, hogy az egyes dinamikus mezők hogyan működnek belsőleg azért, hogy lekérjék vagy beállítsák az értékeiket vagy megjelenítsék azokat. Egyszerűen csak meg kell hívnia a háttérprogram-objektum modult, és általános módon kell használnia a mezőket.
Számos módszer létezik a dinamikus mezők kiterjesztésére. A következő szakaszok meg fogják próbálni a leggyakoribb forgatókönyveket bemutatni.
Egy új dinamikus mező típus létrehozásához a következők szükségesek:
Hozzon létre egy dinamikus mező illesztőprogramot
Ez az új mező fő modulja.
Hozzon létre vagy használjon egy meglévő adminisztrátori párbeszédablakot
Egy kezelőfelület megszerzéséhez, és a konfigurációs beállításainak megadásához.
Hozzon létre egy beállítófájlt
Az új mező regisztrálásához a háttérprogramban (vagy a keretrendszerben lévő új adminisztrátori párbeszédablakokban, ha szükséges), valamint hogy képes legyen példányokat vagy azt létrehozni.
Egy új dinamikus mező típus létrehozásához más objektumoknál a következők szükségesek:
Hozzon létre egy dinamikus mező illesztőprogramot
Ez az új mező fő modulja.
Hozzon létre egy objektumtípus delegáltat
Ez akkor is szükséges, ha a „másik objektum” nem igényel semmilyen különleges adatkezelést a függvényeiben (például egy érték beállítása után). Az összes objektumtípus delegáltnak meg kell valósítania azokat a függvényeket, amelyeket a háttérprogram igényel.
Vessen egy pillantást a jelenlegi objektumtípus delegáltakra ugyanazon függvények megvalósításához még akkor is, ha azok csak egy sikeres értéket adnak vissza a „másik objektumnál”.
Hozzon létre vagy használjon egy meglévő adminisztrátori párbeszédablakot
Egy kezelőfelület megszerzéséhez, és a konfigurációs beállításainak megadásához.
Valósítsa meg a dinamikus mezőket az előtétprogram modulokban
Hogy képes legyen használni a dinamikus mezőket.
Hozzon létre egy beállítófájlt
Az új mező regisztrálásához a háttérprogramban (vagy a keretrendszerben lévő új adminisztrátori párbeszédablakokban, ha szükséges), valamint hogy képes legyen példányokat vagy azt létrehozni. És végezze el a szükséges beállításokat az új képernyőkön történő megjelenítéshez, elrejtéshez vagy a dinamikus mezők kötelezőként való megjelenítéséhez.
Egy csomag létrehozásához a meglévő dinamikus mezők használata érdekében a következők szükségesek:
Valósítsa meg a dinamikus mezőket az előtétprogram modulokban
Hogy képes legyen használni a dinamikus mezőket.
Hozzon létre egy beállítófájlt
Hogy lehetőséget adjon a végfelhasználónak az új képernyőkön történő megjelenítéshez, elrejtéshez vagy a dinamikus mezők kötelezőként való megjelenítéséhez.
Lehetséges lehet, hogy a háttérprogram objektum nem rendelkezik egy szükséges függvénnyel az egyéni fejlesztésekhez, vagy az is előfordulhat, hogy megvan ugyan a szükséges függvénye, de a visszatérési formátum nem felel meg az egyéni fejlesztés szükségleteinek, vagy hogy egy új viselkedés az új vagy a régi függvények végrehajtását igényli.
A legegyszerűbb mód ennek elvégzéséhez a jelenlegi mezőfájlok kiterjesztése. Ehhez egy olyan új háttérprogram kiterjesztésfájlt szükséges létrehozni, amely meghatározza az új függvényeket, és olyan illesztőprogram kiterjesztéseket is létre kell hozni, amelyek megvalósítják ezeket az új függvényeket minden egyes mezőnél. Ezeknek az új illesztőprogramoknak csak az új függvényeket kell majd megvalósítaniuk, mivel az eredeti illesztőprogramok törődnek a szabványos függvényekkel. Ezen új fájlok egyikének sincs szüksége konstruktorra, mivel ezek egy alapként lesznek betöltve a háttérprogram objektumhoz és az illesztőprogramokhoz.
Az egyetlen korlátozás, hogy a függvényeket eltérően kell elnevezni a háttérprogramnál és az illesztőprogramnál lévőknél, különben felül fognak íródni a jelenlegi objektumokkal.
Tegye az új háttérprogram kiterjesztést a DynamicField
könyvtárba (például
/$OTRS_HOME/Kernel/System/DynamicField/NewPackageBackend.pm
és az illesztőprogramjait a
/$OTRS_HOME/Kernel/System/DynamicField/Driver/NewPackage*.pm
fájlokba).
Az új viselkedéseknek csak egy kis beállítás szükséges a kiterjesztések beállítófájljában.
Az új háttérprogram függvények létrehozásához a következők szükségesek:
Hozzon létre egy új háttérprogram kiterjesztés modult
Csak az új függvények meghatározásához.
Hozza létre a dinamikus mezők illesztőprogram kiterjesztéseit
Csak az új függvények megvalósításához.
Valósítsa meg az új dinamikus mezők függvényeit az előtétprogram modulokban
Hogy képes legyen használni az új dinamikus mezők függvényeit.
Hozzon létre egy beállítófájlt
Az új háttérprogram és az illesztőprogramok kiterjesztéseinek és viselkedéseinek regisztrálásához.
A folyamat bemutatásához egy új „jelszó” dinamikus mező lesz létrehozva. Ez
az új dinamikus mező típus egy új jelszómezőt fog megjeleníteni a jegy és a
bejegyzés objektumokhoz. Mivel nagyon hasonló egy szöveg dinamikus mezőhöz,
ezért a Base
és a BaseText
illesztőprogramokat fogjuk használni alapként ezen új mező felépítéséhez.
Az új jelszómező megvalósítása csak oktatási célokra van, nem biztosít semmilyen biztonsági szintet, és nem ajánlott termelési rendszereknél.
A dinamikus mező létrehozásához négy fájlt fogunk létrehozni: egy beállítófájlt (XML) a modulok regisztrálásához, egy adminisztrátori párbeszédablak modult (Perl) a mezőlehetőségek beállításához, egy sablonmodult az adminisztrátori párbeszédablakhoz és egy dinamikus mező illesztőprogramot (Perl).
Fájlszerkezet:
$HOME (például /opt/otrs/) | ... |--/Kernel/ | |--/Config/ | | |--/Files/ | | | |DynamicFieldPassword.xml ... | |--/Modules/ | | |AdminDynamicFieldPassword.pm ... | |--/Output/ | | |--/HTML/ | | | |--/Standard/ | | | | |AdminDynamicFieldPassword.tt ... | |--/System/ | | |--/DynamicField/ | | | |--/Driver/ | | | | |Password.pm ...
A beállítófájlokat használják a dinamikus mező típusok (illesztőprogram) és
az objektumtípus illesztőprogramok regisztrálásához a
BackendObject
számára. Ezek szabványos regisztrációkat is
tárolnak az adminisztrátori modulokhoz a keretrendszerben.
Ebben a szakaszban a jelszó dinamikus mezőhöz egy beállítófájl van megjelenítve és elmagyarázva.
<?xml version="1.0" encoding="utf-8"?> <otrs_config version="1.0" init="Application">
Ez a normál fejléc egy beállítófájlhoz.
<ConfigItem Name="DynamicFields::Driver###Password" Required="0" Valid="1"> <Description Translatable="1">Dinamikus mező háttérprogram regisztráció.</Description> <Group>DynamicFieldPassword</Group> <SubGroup>DynamicFields::Backend::Registration</SubGroup> <Setting> <Hash> <Item Key="DisplayName" Translatable="1">Jelszó</Item> <Item Key="Module">Kernel::System::DynamicField::Driver::Password</Item> <Item Key="ConfigDialog">AdminDynamicFieldPassword</Item> </Hash> </Setting> </ConfigItem>
Ez a beállítás regisztrálja a jelszó dinamikus mező illesztőprogramot a
háttérprogram modulhoz, így az felvehető az elérhető dinamikus mezők
típusainak listájába. A saját adminisztrátori párbeszédablakát is
meghatározza a ConfigDialog
kulcsban. Ezt a kulcsot a fő
dinamikus mező adminisztrátori modul használja ennek az új dinamikus mező
típusának a kezeléséhez.
<ConfigItem Name="Frontend::Module###AdminDynamicFieldPassword" Required="0" Valid="1"> <Description Translatable="1">Előtétprogram-modul regisztráció az ügyintézői felülethez.</Description> <Group>DynamicFieldPassword</Group> <SubGroup>Frontend::Admin::ModuleRegistration</SubGroup> <Setting> <FrontendModuleReg> <Group>admin</Group> <Description>Admin</Description> <Title Translatable="1">Dinamikus mezők szöveg háttérprogram grafikus felület</Title> <Loader> <JavaScript>Core.Agent.Admin.DynamicField.js</JavaScript> </Loader> </FrontendModuleReg> </Setting> </ConfigItem>
Ez egy szabványos modulregisztráció a jelszó adminisztrátori párbeszédablakhoz az adminisztrátori felületen.
</otrs_config>
Egy beállítófájl szabványos lezárása.
Az adminisztrátori párbeszédablakok szabványos adminisztrátori modulok a dinamikus mezők kezeléséhez (hozzáadás vagy szerkesztés).
Ebben a szakaszban a jelszó dinamikus mezőhöz egy adminisztrátori párbeszédablak van megjelenítve és elmagyarázva.
# -- # Kernel/Modules/AdminDynamicFieldPassword.pm - provides a dynamic fields password config view for admins # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::Modules::AdminDynamicFieldPassword; use strict; use warnings; use Kernel::System::VariableCheck qw(:all); use Kernel::System::Valid; use Kernel::System::CheckItem; use Kernel::System::DynamicField;
Ez egy gyakori fejléc, amely megtalálható a szokásos OTRS modulokban. Az
osztály/csomag neve a package
kulcsszón keresztül van
deklarálva.
sub new { my ( $Type, %Param ) = @_; my $Self = {%Param}; bless( $Self, $Type ); for (qw(ParamObject LayoutObject LogObject ConfigObject)) { if ( !$Self->{$_} ) { $Self->{LayoutObject}->FatalError( Message => "Nincs $_!" ); } } # további objektumok létrehozása $Self->{ValidObject} = Kernel::System::Valid->new( %{$Self} ); $Self->{DynamicFieldObject} = Kernel::System::DynamicField->new( %{$Self} ); # beállított objektumtípusok lekérése $Self->{ObjectTypeConfig} = $Self->{ConfigObject}->Get('DynamicFields::ObjectType'); # a mezők beállításának lekérése $Self->{FieldTypeConfig} = $Self->{ConfigObject}->Get('DynamicFields::Backend') || {}; $Self->{DefaultValueMask} = '****'; return $Self; }
A new
konstruktor hozza létre az osztály új példányát. A
kódolási irányelvek szerint más osztályoknak azon objektumait kell a
new
konstruktorban létrehozni, amelyek ebben a modulban
szükségesek.
sub Run { my ( $Self, %Param ) = @_; if ( $Self->{Subaction} eq 'Add' ) { return $Self->_Add( %Param, ); } elsif ( $Self->{Subaction} eq 'AddAction' ) { # kihívási token ellenőrzése az írási művelethez $Self->{LayoutObject}->ChallengeTokenCheck(); return $Self->_AddAction( %Param, ); } if ( $Self->{Subaction} eq 'Change' ) { return $Self->_Change( %Param, ); } elsif ( $Self->{Subaction} eq 'ChangeAction' ) { # kihívási token ellenőrzése az írási művelethez $Self->{LayoutObject}->ChallengeTokenCheck(); return $Self->_ChangeAction( %Param, ); } return $Self->{LayoutObject}->ErrorScreen( Message => "Meghatározatlan alművelet.", ); }
A Run
a webkérés által meghívott alapértelmezett
függvény. Megpróbáljuk ezt a függvényt annyira egyszerűvé tenni, amennyire
csak lehetséges, és lehetővé tenni a segítő függvényeknek a „kemény” munka
elvégzését.
sub _Add { my ( $Self, %Param ) = @_; my %GetParam; for my $Needed (qw(ObjectType FieldType FieldOrder)) { $GetParam{$Needed} = $Self->{ParamObject}->GetParam( Param => $Needed ); if ( !$Needed ) { return $Self->{LayoutObject}->ErrorScreen( Message => "Szükséges: $Needed", ); } } # az objektumtípus és a mezőtípus megjelenített nevének lekérése my $ObjectTypeName = $Self->{ObjectTypeConfig}->{ $GetParam{ObjectType} }->{DisplayName} || ''; my $FieldTypeName = $Self->{FieldTypeConfig}->{ $GetParam{FieldType} }->{DisplayName} || ''; return $Self->_ShowScreen( %Param, %GetParam, Mode => 'Add', ObjectTypeName => $ObjectTypeName, FieldTypeName => $FieldTypeName, ); }
Az _Add
függvény is nagyon egyszerű, csak lekér néhány
paramétert a webkérésből, és meghívja a _ShowScreen()
függvényt. Normális esetben ezt a függvényt nem szükséges módosítani.
sub _AddAction { my ( $Self, %Param ) = @_; my %Errors; my %GetParam; for my $Needed (qw(Name Label FieldOrder)) { $GetParam{$Needed} = $Self->{ParamObject}->GetParam( Param => $Needed ); if ( !$GetParam{$Needed} ) { $Errors{ $Needed . 'ServerError' } = 'ServerError'; $Errors{ $Needed . 'ServerErrorMessage' } = 'Ez a mező kötelező.'; } } if ( $GetParam{Name} ) { # annak ellenőrzése, hogy a név csak betűket és számokat tartalmaz-e if ( $GetParam{Name} !~ m{\A ( ?: [a-zA-Z] | \d )+ \z}xms ) { # kiszolgálóhiba hibaosztály hozzáadása $Errors{NameServerError} = 'ServerError'; $Errors{NameServerErrorMessage} = 'A mező nem csak ASCII betűket és számokat tartalmaz.'; } # annak ellenőrzése, hogy a név kettőzött-e my %DynamicFieldsList = %{ $Self->{DynamicFieldObject}->DynamicFieldList( Valid => 0, ResultType => 'HASH', ) }; %DynamicFieldsList = reverse %DynamicFieldsList; if ( $DynamicFieldsList{ $GetParam{Name} } ) { # kiszolgálóhiba hibaosztály hozzáadása $Errors{NameServerError} = 'ServerError'; $Errors{NameServerErrorMessage} = 'Már létezik egy másik ugyanilyen nevű mező.'; } } if ( $GetParam{FieldOrder} ) { # annak ellenőrzése, hogy a mezősorrend számszerű és pozitív-e if ( $GetParam{FieldOrder} !~ m{\A ( ?: \d )+ \z}xms ) { # kiszolgálóhiba hibaosztály hozzáadása $Errors{FieldOrderServerError} = 'ServerError'; $Errors{FieldOrderServerErrorMessage} = 'A mezőnek számnak kell lennie.'; } } for my $ConfigParam ( qw( ObjectType ObjectTypeName FieldType FieldTypeName DefaultValue ValidID ShowValue ValueMask ) ) { $GetParam{$ConfigParam} = $Self->{ParamObject}->GetParam( Param => $ConfigParam ); } # kijavíthatatlan hibák if ( !$GetParam{ValidID} ) { return $Self->{LayoutObject}->ErrorScreen( Message => "Szükséges: ValidID", ); } # visszatérés a hozzáadás képernyőre, ha hibák vannak if (%Errors) { return $Self->_ShowScreen( %Param, %Errors, %GetParam, Mode => 'Add', ); } # bizonyos beállítások elvégzése my $FieldConfig = { DefaultValue => $GetParam{DefaultValue}, ShowValue => $GetParam{ShowValue}, ValueMask => $GetParam{ValueMask} || $Self->{DefaultValueMask}, }; # egy új mező létrehozása my $FieldID = $Self->{DynamicFieldObject}->DynamicFieldAdd( Name => $GetParam{Name}, Label => $GetParam{Label}, FieldOrder => $GetParam{FieldOrder}, FieldType => $GetParam{FieldType}, ObjectType => $GetParam{ObjectType}, Config => $FieldConfig, ValidID => $GetParam{ValidID}, UserID => $Self->{UserID}, ); if ( !$FieldID ) { return $Self->{LayoutObject}->ErrorScreen( Message => "Nem sikerült létrehozni az új mezőt", ); } return $Self->{LayoutObject}->Redirect( OP => "Action=AdminDynamicField", ); }
Az _AddAction
függvény kéri le a beállítási paramétereket egy
új dinamikus mezőből, és ellenőrzi, hogy a dinamikus mező neve csak betűket
és számokat tartalmaz-e. Ez a függvény képes ellenőrizni bármilyen egyéb
paramétert is.
A Name
, Label
,
FieldOrder
, Validity
közös paraméterek
az összes dinamikus mezőnél, és ezek kötelezők. Minden egyes dinamikus
mezőnek megvan a saját különleges beállítása, amelynek tartalmaznia kell
legalább a DefaultValue
paramétert. Ebben az esetben a
ShowValue
és a ValueMask
paraméterekkel is rendelkezik a jelszómezőnél.
Ha a mező rendelkezik egy rögzített listájú értékek tárolásának
képességével, akkor azokat a PossibleValues
paraméterben
kell tárolni a különleges beállítási kivonaton belül.
Mint más adminisztrátori modulokban, ha egy paraméter nem érvényes, akkor ez a függvény visszatér a hozzáadás képernyőre, kiemelve a hibás űrlapmezőket.
Ha az összes paraméter helyes, akkor létrehoz egy új dinamikus mezőt.
sub _Change { my ( $Self, %Param ) = @_; my %GetParam; for my $Needed (qw(ObjectType FieldType)) { $GetParam{$Needed} = $Self->{ParamObject}->GetParam( Param => $Needed ); if ( !$Needed ) { return $Self->{LayoutObject}->ErrorScreen( Message => "Szükséges: $Needed", ); } } # az objektumtípus és a mezőtípus megjelenített nevének lekérése my $ObjectTypeName = $Self->{ObjectTypeConfig}->{ $GetParam{ObjectType} }->{DisplayName} || ''; my $FieldTypeName = $Self->{FieldTypeConfig}->{ $GetParam{FieldType} }->{DisplayName} || ''; my $FieldID = $Self->{ParamObject}->GetParam( Param => 'ID' ); if ( !$FieldID ) { return $Self->{LayoutObject}->ErrorScreen( Message => "Azonosító szükséges", ); } # dinamikus mező adatainak lekérése my $DynamicFieldData = $Self->{DynamicFieldObject}->DynamicFieldGet( ID => $FieldID, ); # érvényes dinamikus mező beállítások ellenőrzése if ( !IsHashRefWithData($DynamicFieldData) ) { return $Self->{LayoutObject}->ErrorScreen( Message => "Nem sikerült lekérni az adatokat a dinamikus mezőhöz: $FieldID", ); } my %Config = (); # beállítások kibontása if ( IsHashRefWithData( $DynamicFieldData->{Config} ) ) { %Config = %{ $DynamicFieldData->{Config} }; } return $Self->_ShowScreen( %Param, %GetParam, %${DynamicFieldData}, %Config, ID => $FieldID, Mode => 'Change', ObjectTypeName => $ObjectTypeName, FieldTypeName => $FieldTypeName, ); }
A _Change
függvény nagyon hasonló az _Add
függvényhez, de mivel ezt a függvényt egy meglévő mező szerkesztéséhez
használják, ellenőriznie kell a FieldID
paramétert, és be
kell gyűjtenie a jelenlegi dinamikus mező adatait.
sub _ChangeAction { my ( $Self, %Param ) = @_; my %Errors; my %GetParam; for my $Needed (qw(Name Label FieldOrder)) { $GetParam{$Needed} = $Self->{ParamObject}->GetParam( Param => $Needed ); if ( !$GetParam{$Needed} ) { $Errors{ $Needed . 'ServerError' } = 'ServerError'; $Errors{ $Needed . 'ServerErrorMessage' } = 'Ez a mező kötelező.'; } } my $FieldID = $Self->{ParamObject}->GetParam( Param => 'ID' ); if ( !$FieldID ) { return $Self->{LayoutObject}->ErrorScreen( Message => "Azonosító szükséges", ); } if ( $GetParam{Name} ) { # annak ellenőrzése, hogy a név kisbetűs-e if ( $GetParam{Name} !~ m{\A ( ?: [a-zA-Z] | \d )+ \z}xms ) { # kiszolgálóhiba hibaosztály hozzáadása $Errors{NameServerError} = 'ServerError'; $Errors{NameServerErrorMessage} = 'A mező nem csak ASCII betűket és számokat tartalmaz.'; } # annak ellenőrzése, hogy a név kettőzött-e my %DynamicFieldsList = %{ $Self->{DynamicFieldObject}->DynamicFieldList( Valid => 0, ResultType => 'HASH', ) }; %DynamicFieldsList = reverse %DynamicFieldsList; if ( $DynamicFieldsList{ $GetParam{Name} } && $DynamicFieldsList{ $GetParam{Name} } ne $FieldID ) { # kiszolgálóhiba hibaosztály hozzáadása $Errors{NameServerError} = 'ServerError'; $Errors{NameServerErrorMessage} = 'Már létezik egy másik ugyanilyen nevű mező.'; } } if ( $GetParam{FieldOrder} ) { # annak ellenőrzése, hogy a mezősorrend számszerű és pozitív-e if ( $GetParam{FieldOrder} !~ m{\A ( ?: \d )+ \z}xms ) { # add server error error class $Errors{FieldOrderServerError} = 'ServerError'; $Errors{FieldOrderServerErrorMessage} = 'A mezőnek számnak kell lennie.'; } } for my $ConfigParam ( qw( ObjectType ObjectTypeName FieldType FieldTypeName DefaultValue ValidID ShowValue ValueMask ) ) { $GetParam{$ConfigParam} = $Self->{ParamObject}->GetParam( Param => $ConfigParam ); } # kijavíthatatlan hibák if ( !$GetParam{ValidID} ) { return $Self->{LayoutObject}->ErrorScreen( Message => "Szükséges: ValidID", ); } # a dinamikus mező adatainak lekérése my $DynamicFieldData = $Self->{DynamicFieldObject}->DynamicFieldGet( ID => $FieldID, ); # érvényes dinamikus mező beállítások ellenőrzése if ( !IsHashRefWithData($DynamicFieldData) ) { return $Self->{LayoutObject}->ErrorScreen( Message => "Nem sikerült lekérni az adatokat a dinamikus mezőhöz: $FieldID", ); } # visszatérés a változtatás képernyőhöz, ha hibák vannak if (%Errors) { return $Self->_ShowScreen( %Param, %Errors, %GetParam, ID => $FieldID, Mode => 'Change', ); } # különleges beállítások elvégzése my $FieldConfig = { DefaultValue => $GetParam{DefaultValue}, ShowValue => $GetParam{ShowValue}, ValueMask => $GetParam{ValueMask}, }; # dinamikus mező frissítése (a FieldType és az ObjectType nem változtatható meg; régi értékek használata) my $UpdateSuccess = $Self->{DynamicFieldObject}->DynamicFieldUpdate( ID => $FieldID, Name => $GetParam{Name}, Label => $GetParam{Label}, FieldOrder => $GetParam{FieldOrder}, FieldType => $DynamicFieldData->{FieldType}, ObjectType => $DynamicFieldData->{ObjectType}, Config => $FieldConfig, ValidID => $GetParam{ValidID}, UserID => $Self->{UserID}, ); if ( !$UpdateSuccess ) { return $Self->{LayoutObject}->ErrorScreen( Message => "Nem sikerült frissíteni a mezőt: $GetParam{Name}", ); } return $Self->{LayoutObject}->Redirect( OP => "Action=AdminDynamicField", ); }
A _ChangeAction()
nagyon hasonló az _AddAction()
függvényhez, de át van írva egy meglévő mező frissítéséhez egy új
létrehozása helyett.
sub _ShowScreen { my ( $Self, %Param ) = @_; $Param{DisplayFieldName} = 'New'; if ( $Param{Mode} eq 'Change' ) { $Param{ShowWarning} = 'ShowWarning'; $Param{DisplayFieldName} = $Param{Name}; } # fejléc my $Output = $Self->{LayoutObject}->Header(); $Output .= $Self->{LayoutObject}->NavigationBar(); # az összes mező lekérése my $DynamicFieldList = $Self->{DynamicFieldObject}->DynamicFieldListGet( Valid => 0, ); # a sorrendszámok listájának lekérése (már rendezve van). my @DynamicfieldOrderList; for my $Dynamicfield ( @{$DynamicFieldList} ) { push @DynamicfieldOrderList, $Dynamicfield->{FieldOrder}; } # hozzáadáskor létre kell hoznunk egy további sorrendszámot az új mezőhöz if ( $Param{Mode} eq 'Add' ) { # az utolsó elem lekérése a sorrendlistából, és 1 hozzáadása my $LastOrderNumber = $DynamicfieldOrderList[-1]; $LastOrderNumber++; # ezen új sorrendszám hozzáadása a lista végéhez push @DynamicfieldOrderList, $LastOrderNumber; } my $DynamicFieldOrderSrtg = $Self->{LayoutObject}->BuildSelection( Data => \@DynamicfieldOrderList, Name => 'FieldOrder', SelectedValue => $Param{FieldOrder} || 1, PossibleNone => 0, Class => 'W50pc Validate_Number', ); my %ValidList = $Self->{ValidObject}->ValidList(); # az ellenőrzés kiválasztás létrehozása my $ValidityStrg = $Self->{LayoutObject}->BuildSelection( Data => \%ValidList, Name => 'ValidID', SelectedID => $Param{ValidID} || 1, PossibleNone => 0, Translation => 1, Class => 'W50pc', ); # a beállítási mezőre jellemző beállítások meghatározása my $DefaultValue = ( defined $Param{DefaultValue} ? $Param{DefaultValue} : '' ); # az érték megjelenítése választás létrehozása my $ShowValueStrg = $Self->{LayoutObject}->BuildSelection( Data => [ 'No', 'Yes' ], Name => 'ShowValue', SelectedValue => $Param{ShowValue} || 'No', PossibleNone => 0, Translation => 1, Class => 'W50pc', ); # kimenet előállítása $Output .= $Self->{LayoutObject}->Output( TemplateFile => 'AdminDynamicFieldPassword', Data => { %Param, ValidityStrg => $ValidityStrg, DynamicFieldOrderSrtg => $DynamicFieldOrderSrtg, DefaultValue => $DefaultValue, ShowValueStrg => $ShowValueStrg, ValueMask => $Param{ValueMask} || $Self->{DefaultValueMask}, }, ); $Output .= $Self->{LayoutObject}->Footer(); return $Output; } 1;
A _ShowScreen
függvényt használják egy sablonból történő HTML
elemek és blokkok beállítására és meghatározására az adminisztrátori
párbeszédablak HTML kódjának előállításához.
A sablon az a hely, ahol a párbeszédablak HTML kódja el van tárolva.
Ebben a szakaszban a jelszó dinamikus mezőhöz egy adminisztrátori párbeszédablak sablon van megjelenítve és elmagyarázva.
# -- # AdminDynamicFieldPassword.tt - provides HTML form for AdminDynamicFieldPassword # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # --
Ez egy gyakori fejléc, amely megtalálható a szokásos OTRS modulokban.
<div class="MainBox ARIARoleMain LayoutFixedSidebar SidebarFirst"> <h1>[% Translate("Dynamic Fields") | html %] - [% Translate(Data.ObjectTypeName) | html %]: [% Translate(Data.Mode) | html %] [% Translate(Data.FieldTypeName) | html %] [% Translate("Mező") | html %]</h1> <div class="Clear"></div> <div class="SidebarColumn"> <div class="WidgetSimple"> <div class="Header"> <h2>[% Translate("Műveletek") | html %]</h2> </div> <div class="Content"> <ul class="ActionList"> <li> <a href="[% Env("Baselink") %]Action=AdminDynamicField" class="CallForAction"><span>[% Translate("Ugrás vissza az áttekintőhöz") | html %]</span></a> </li> </ul> </div> </div> </div>
A kód ezen része rendelkezik a fő dobozzal és a műveletek oldalsávval is. Nincs szükség módosításokra ebben a szakaszban.
<div class="ContentColumn"> <form action="[% Env("CGIHandle") %]" method="post" class="Validate PreventMultipleSubmits"> <input type="hidden" name="Action" value="AdminDynamicFieldPassword" /> <input type="hidden" name="Subaction" value="[% Data.Mode | html %]Action" /> <input type="hidden" name="ObjectType" value="[% Data.ObjectType | html %]" /> <input type="hidden" name="FieldType" value="[% Data.FieldType | html %]" /> <input type="hidden" name="ID" value="[% Data.ID | html %]" />
A kód ezen szakaszában van meghatározva a párbeszédablak jobboldali
része. Figyelje meg, hogy a rejtett Action
beviteli mező
értékének egyeznie kell az adminisztrátori párbeszédablak nevével.
<div class="WidgetSimple"> <div class="Header"> <h2>[% Translate("Általános") | html %]</h2> </div> <div class="Content"> <div class="LayoutGrid ColumnsWithSpacing"> <div class="Size1of2"> <fieldset class="TableLike"> <label class="Mandatory" for="Name"><span class="Marker">*</span> [% Translate("Név") | html %]:</label> <div class="Field"> <input id="Name" class="W50pc [% Data.NameServerError | html %] [% Data.ShowWarning | html %] Validate_Alphanumeric" type="text" maxlength="200" value="[% Data.Name | html %]" name="Name"/> <div id="NameError" class="TooltipErrorMessage"><p>[% Translate("Ez a mező kötelező, és az értéke csak betű és szám karakter lehet.") | html %]</p></div> <div id="NameServerError" class="TooltipErrorMessage"><p>[% Translate(Data.NameServerErrorMessage) | html %]</p></div> <p class="FieldExplanation">[% Translate("Egyedinek kell lennie, és csak betű és szám karaktereket fogad el.") | html %]</p> <p class="Warning Hidden">[% Translate("Az érték megváltoztatása kézi módosításokat fog igényelni a rendszeren.") | html %]</p> </div> <div class="Clear"></div> <label class="Mandatory" for="Label"><span class="Marker">*</span> [% Translate("Címke") | html %]:</label> <div class="Field"> <input id="Label" class="W50pc [% Data.LabelServerError | html %] Validate_Required" type="text" maxlength="200" value="[% Data.Label | html %]" name="Label"/> <div id="LabelError" class="TooltipErrorMessage"><p>[% Translate("Ez a mező kötelező.") | html %]</p></div> <div id="LabelServerError" class="TooltipErrorMessage"><p>[% Translate(Data.LabelServerErrorMessage) | html %]</p></div> <p class="FieldExplanation">[% Translate("Ez azokon a képernyőkön megjelenítendő név, ahol a mező aktív.") | html %]</p> </div> <div class="Clear"></div> <label class="Mandatory" for="FieldOrder"><span class="Marker">*</span> [% Translate("Mezősorrend") | html %]:</label> <div class="Field"> [% Data.DynamicFieldOrderSrtg %] <div id="FieldOrderError" class="TooltipErrorMessage"><p>[% Translate("Ez a mező kötelező, és csak számot tartalmazhat.") | html %]</p></div> <div id="FieldOrderServerError" class="TooltipErrorMessage"><p>[% Translate(Data.FieldOrderServerErrorMessage) | html %]</p></div> <p class="FieldExplanation">[% Translate("Ez az a sorrend, amelyben ez a mező meg fog jelenni a képernyőkön, ahol aktív.") | html %]</p> </div> <div class="Clear"></div> </fieldset> </div> <div class="Size1of2"> <fieldset class="TableLike"> <label for="ValidID">[% Translate("Érvényesség") | html %]:</label> <div class="Field"> [% Data.ValidityStrg %] </div> <div class="Clear"></div> <div class="SpacingTop"></div> <label for="FieldTypeName">[% Translate("Mezőtípus") | html %]:</label> <div class="Field"> <input id="FieldTypeName" readonly="readonly" class="W50pc" type="text" maxlength="200" value="[% Data.FieldTypeName | html %]" name="FieldTypeName"/> <div class="Clear"></div> </div> <div class="SpacingTop"></div> <label for="ObjectTypeName">[% Translate("Objektumtípus") | html %]:</label> <div class="Field"> <input id="ObjectTypeName" readonly="readonly" class="W50pc" type="text" maxlength="200" value="[% Data.ObjectTypeName | html %]" name="ObjectTypeName"/> <div class="Clear"></div> </div> </fieldset> </div> </div> </div> </div>
Ez az első felületi elem tartalmazza a szokásos űrlapattribútumokat a dinamikus mezőkhöz. A többi dinamikus mezővel való következetességért javasolt a kód ezen részének változatlanul hagyása.
<div class="WidgetSimple"> <div class="Header"> <h2>[% Translate(Data.FieldTypeName) | html %] [% Translate("Mezőbeállítások") | html %]</h2> </div> <div class="Content"> <fieldset class="TableLike"> <label for="DefaultValue">[% Translate("Alapértelmezett érték") | html %]:</label> <div class="Field"> <input id="DefaultValue" class="W50pc" type="text" maxlength="200" value="[% Data.DefaultValue | html %]" name="DefaultValue"/> <p class="FieldExplanation">[% Translate("Ez az alapértelmezett érték ehhez a mezőhöz.") | html %]</p> </div> <div class="Clear"></div> <label for="ShowValue">[% Translate("Érték megjelenítése") | html %]:</label> <div class="Field"> [% Data.ShowValueStrg %] <p class="FieldExplanation"> [% Translate("A mezőérték felfedéséhez a nem szerkesztői képernyőkön (például jegynagyítás képernyő)") | html %] </p> </div> <div class="Clear"></div> <label for="ValueMask">[% Translate("Rejtett értékmaszk") | html %]:</label> <div class="Field"> <input id="ValueMask" class="W50pc" type="text" maxlength="200" value="[% Data.ValueMask | html %]" name="ValueMask"/> <p class="FieldExplanation"> [% Translate("Ez az alternatív érték annak megjelenítéséhez, ha az Érték megjelenítése „Nem” értékre van állítva (Alapértelmezett: **** ).") | html %] </p> </div> <div class="Clear"></div> </fieldset> </div> </div>
A második felületi elem a dinamikus mezőre jellemző űrlapattribútumokkal rendelkezik. Ez az a hely, ahol az új attribútumok beállíthatók, és használhatnak JavaScript és AJAX technológiákat, hogy egyszerűbbé és barátságosabbá tegyék a végfelhasználó számára.
<fieldset class="TableLike"> <div class="Field SpacingTop"> <button type="submit" class="Primary" value="[% Translate("Save") | html %]">[% Translate("Mentés") | html %]</button> [% Translate("vagy") | html %] <a href="[% Env("Baselink") %]Action=AdminDynamicField">[% Translate("Mégse") | html %]</a> </div> <div class="Clear"></div> </fieldset> </form> </div> </div> [% WRAPPER JSOnDocumentComplete %] <script type="text/javascript">//<![CDATA[ $('.ShowWarning').bind('change keyup', function (Event) { $('p.Warning').removeClass('Hidden'); }); Core.Agent.Admin.DynamicField.ValidationInit(); //]]></script> [% END %]
A fájl utolsó része tartalmazza a „Mentés” gombot és a „Mégse” hivatkozást, valamint az egyéb szükséges JavaScript kódot.
Az illesztőprogram maga a dinamikus mező. Számos olyan
függvényt tartalmaz, amelyet széles körben használnak az OTRS
keretrendszerben. Egy illesztőprogram örökölhet néhány függvényt az
alaposztályokból, például a TextArea
illesztőprogram a
Base.pm
és a BaseText.pm
fájlokból
örökli a függvények legnagyobb részét, és csak azokat a függvényeket
valósítja meg, amelyek eltérő logikát vagy eredményeket igényelnek. A
jelölőnégyzet mező illesztőprogram csak a Base.pm
fájlból örököl, mivel az összes többi függvény nagyon eltérő bármely más
alap illesztőprogramtól.
Nézze meg a /Kernel/System/DynmicField/Backend.pm
modul
Perl On-line Dokumentációját (POD) az összes attribútum listája és a
lehetséges visszatérési adatok megismeréséhez az egyes függvényeknél.
Ebben a szakaszban a jelszó dinamikus mező illesztőprogram van bemutatva és
elmagyarázva. Ez az illesztőprogram örököl néhány függvényt a
Base.pm
és a BaseText.pm
fájlokból, és csak azokat a függvényeket valósítja meg, amelyek eltérő
eredményeket igényelnek.
# -- # Kernel/System/DynamicField/Driver/Password.pm - Driver for DynamicField Password backend # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::DynamicField::Driver::Password; use strict; use warnings; use Kernel::System::VariableCheck qw(:all); use Kernel::System::DynamicFieldValue; use base qw(Kernel::System::DynamicField::Driver::BaseText); our @ObjectDependencies = ( 'Kernel::Config', 'Kernel::System::DynamicFieldValue', 'Kernel::System::Main', );
Ez egy gyakori fejléc, amely megtalálható a szokásos OTRS modulokban. Az
osztály/csomag neve a package
kulcsszón keresztül van
deklarálva. Figyelje meg, hogy a BaseText
osztályt
használják alaposztályként.
sub new { my ( $Type, %Param ) = @_; # új kivonat lefoglalása az objektumhoz my $Self = {}; bless( $Self, $Type ); # mezőviselkedések beállítása $Self->{Behaviors} = { 'IsACLReducible' => 0, 'IsNotificationEventCondition' => 1, 'IsSortable' => 0, 'IsFiltrable' => 0, 'IsStatsCondition' => 1, 'IsCustomerInterfaceCapable' => 1, }; # a dinamikus mező háttérprogram egyéni kiterjesztéseinek lekérése my $DynamicFieldDriverExtensions = $Kernel::OM->Get('Kernel::Config')->Get('DynamicFields::Extension::Driver::Password'); EXTENSION: for my $ExtensionKey ( sort keys %{$DynamicFieldDriverExtensions} ) { # érvénytelen kiterjesztések kihagyása next EXTENSION if !IsHashRefWithData( $DynamicFieldDriverExtensions->{$ExtensionKey} ); # egy kiterjesztés beállítás gyors elérésének létrehozása my $Extension = $DynamicFieldDriverExtensions->{$ExtensionKey}; # annak ellenőrzése, hogy a kiterjesztésnek van-e új modulja if ( $Extension->{Module} ) { # annak ellenőrzése, hogy a modul betölthető-e if ( !$Kernel::OM->Get('Kernel::System::Main')->RequireBaseClass( $Extension->{Module} ) ) { die "Nem lehet betölteni a dinamikus mezők háttérprogram modulját:" . " $Extension->{Module}! $@"; } } # annak ellenőrzése, hogy a kiterjesztés tartalmaz-e további viselkedéseket if ( IsHashRefWithData( $Extension->{Behaviors} ) ) { %{ $Self->{Behaviors} } = ( %{ $Self->{Behaviors} }, %{ $Extension->{Behaviors} } ); } } return $Self; }
A new
konstruktor hozza létre az osztály új példányát. A
kódolási irányelvek szerint más osztályoknak azon objektumait kell a
new
konstruktorban létrehozni, amelyek ebben a modulban
szükségesek.
Fontos a viselkedéseket helyesen meghatározni, mivel a mező lehet használható vagy lehet nem használható bizonyos képernyőkön. Azokat a függvényeket esetleg nem szükséges megvalósítani, amelyek olyan viselkedésektől függenek, amelyek nem aktívak ennél a bizonyos mezőnél.
Az illesztőprogramokat kizárólag a BackendObject
hozza
létre, és nem közvetlenül bármely egyéb modulból.
sub EditFieldRender { my ( $Self, %Param ) = @_; # beállítások átvétele a mezőbeállításokból my $FieldConfig = $Param{DynamicFieldConfig}->{Config}; my $FieldName = 'DynamicField_' . $Param{DynamicFieldConfig}->{Name}; my $FieldLabel = $Param{DynamicFieldConfig}->{Label}; my $Value = ''; # a mezőérték beállítása vagy alapértelmezett if ( $Param{UseDefaultValue} ) { $Value = ( defined $FieldConfig->{DefaultValue} ? $FieldConfig->{DefaultValue} : '' ); } $Value = $Param{Value} if defined $Param{Value}; # a dinamikus mező értékének kibontása a webkérésből my $FieldValue = $Self->EditFieldValueGet( %Param, ); # értékek beállítása a paraméterobjektumból, ha létezik if ( defined $FieldValue ) { $Value = $FieldValue; } # osztály ellenőrzése és beállítása, ha szükséges my $FieldClass = 'DynamicFieldText W50pc'; if ( defined $Param{Class} && $Param{Class} ne '' ) { $FieldClass .= ' ' . $Param{Class}; } # mező beállítása kötelezőként $FieldClass .= ' Validate_Required' if $Param{Mandatory}; # hiba CSS osztály beállítása $FieldClass .= ' ServerError' if $Param{ServerError}; my $HTMLString = <<"EOF"; <input type="password" class="$FieldClass" id="$FieldName" name="$FieldName" title="$FieldLabel" value="$Value" /> EOF if ( $Param{Mandatory} ) { my $DivID = $FieldName . 'Error'; # kliensoldali ellenőrzéshez $HTMLString .= <<"EOF"; <div id="$DivID" class="TooltipErrorMessage"> <p> \$Text{"Ez a mező kötelező."} </p> </div> EOF } if ( $Param{ServerError} ) { my $ErrorMessage = $Param{ErrorMessage} || 'Ez a mező kötelező.'; my $DivID = $FieldName . 'ServerError'; # kiszolgálóoldali ellenőrzéshez $HTMLString .= <<"EOF"; <div id="$DivID" class="TooltipErrorMessage"> <p> \$Text{"$ErrorMessage"} </p> </div> EOF } # az EditLabelRender meghívása a közös illesztőprogramon my $LabelString = $Self->EditLabelRender( %Param, DynamicFieldConfig => $Param{DynamicFieldConfig}, Mandatory => $Param{Mandatory} || '0', FieldName => $FieldName, ); my $Data = { Field => $HTMLString, Label => $LabelString, }; return $Data; }
Ez a függvény felelős a mező és annak címkéje HTML ábrázolásának
létrehozásáért, és olyan szerkesztő képernyőkön használják, mint például az
AgentTicketPhone
, AgentTicketNote
,
stb.
sub DisplayValueRender { my ( $Self, %Param ) = @_; # a HTMLOutput beállítása alapértelmezettként, ha nincs megadva if ( !defined $Param{HTMLOutput} ) { $Param{HTMLOutput} = 1; } my $Value; my $Title; # annak ellenőrzése, hogy a mező be van-e állítva a jelszó megjelenítéséhez vagy sem if ( defined $Param{DynamicFieldConfig}->{Config}->{ShowValue} && $Param{DynamicFieldConfig}->{Config}->{ShowValue} eq 'Yes' ) { # a nyers Title és Value szövegek lekérése a mezőértékből $Value = defined $Param{Value} ? $Param{Value} : ''; $Title = $Value; } else { # a maszk megjelenítése az érték helyett $Value = $Param{DynamicFieldConfig}->{Config}->{ValueMask} || ''; $Title = 'A mező értéke rejtve van.' } # HTMLOutput átalakítások if ( $Param{HTMLOutput} ) { $Value = $Param{LayoutObject}->Ascii2Html( Text => $Value, Max => $Param{ValueMaxChars} || '', ); $Title = $Param{LayoutObject}->Ascii2Html( Text => $Title, Max => $Param{TitleMaxChars} || '', ); } else { if ( $Param{ValueMaxChars} && length($Value) > $Param{ValueMaxChars} ) { $Value = substr( $Value, 0, $Param{ValueMaxChars} ) . '...'; } if ( $Param{TitleMaxChars} && length($Title) > $Param{TitleMaxChars} ) { $Title = substr( $Title, 0, $Param{TitleMaxChars} ) . '...'; } } # visszatérési szerkezet létrehozása my $Data = { Value => $Value, Title => $Title, }; return $Data; }
A DisplayValueRender()
függvény egyszerű szövegként adja vissza
a mező értékét és annak feliratát (mindkettő lefordítható). Ennél a bizonyos
példánál azt ellenőrizzük, hogy a jelszót meg kell-e mutatni, vagy egy
beállítási paraméter által előre meghatározott maszkot kell-e megjeleníteni
a dinamikus mezőben.
sub ReadableValueRender { my ( $Self, %Param ) = @_; my $Value; my $Title; # annak ellenőrzése, hogy a mező be van-e állítva a jelszó megjelenítéséhez vagy sem if ( defined $Param{DynamicFieldConfig}->{Config}->{ShowValue} && $Param{DynamicFieldConfig}->{Config}->{ShowValue} eq 'Yes' ) { # a nyers Title és Value szövegek lekérése a mezőértékből $Value = $Param{Value} // ''; $Title = $Value; } else { # a maszk megjelenítése az érték helyett $Value = $Param{DynamicFieldConfig}->{Config}->{ValueMask} || ''; $Title = 'A mező értéke rejtve van.' } # szövegek levágása, ha szükséges if ( $Param{ValueMaxChars} && length($Value) > $Param{ValueMaxChars} ) { $Value = substr( $Value, 0, $Param{ValueMaxChars} ) . '...'; } if ( $Param{TitleMaxChars} && length($Title) > $Param{TitleMaxChars} ) { $Title = substr( $Title, 0, $Param{TitleMaxChars} ) . '...'; } # visszatérési szerkezet létrehozása my $Data = { Value => $Value, Title => $Title, }; return $Data; }
Ez a függvény hasonló a DisplayValueRender()
függvényhez, de
olyan helyeken használják, ahol nincs LayoutObject
.
A következők olyan egyéb függvények, amelyek talán szükségesek lehetnek, ha
egy új dinamikus mező nem örököl más osztályokból. Ezen függvények teljes
kódjának megtekintéséhez nézzen bele közvetlenül a
Kernel/System/DynamicField/Driver/Base.pm
és a
Kernel/System/DynamicField/Driver/BaseText.pm
fájlokba.
sub ValueGet { ... }
Ez a függvény lekéri az értéket a mezőből egy adott objektumnál. Ebben az esetben az első szövegértéket adjuk vissza, mivel a mező egyszerre csak egy szövegértéket tárol.
sub ValueSet { ... }
A ValueSet()
függvényt egy dinamikus mező érték tárolásához
használják. Ebben az esetben a mező csak egy szöveg típusú értéket
tárol. Más mezők tárolhatnak egynél több értéket is a
ValueText
, a ValueDateTime
vagy a
ValueInt
formátumnál.
sub ValueDelete { ... }
Ezt a függvényt egy mező értékének törléséhez használják, amely egy bizonyos objektumazonosítóhoz van csatolva. Például ha egy objektum példánynak törlésére készülnek, akkor nincs oka a mezőérték tárolásának az adatbázisban annál a bizonyos objektumpéldánynál.
sub AllValuesDelete { ... }
Az AllValuesDelete()
függvényt az összes érték törléséhez
használják egy bizonyos dinamikus mezőből. Ez a függvény nagyon hasznos,
amikor egy dinamikus mező törlésre fog kerülni.
sub ValueValidate { ... }
A ValueValidate()
függvényt annak ellenőrzéséhez használják,
hogy az érték megegyezik-e a típusának.
sub SearchSQLGet { ... }
Ezt a függvényt a TicketSearch
alapmodul használja egy
jegy kereséséhez szükséges belső lekérdezés felépítéséhez, ezt a mezőt
alapul véve keresési paraméterként.
sub SearchSQLOrderFieldGet { ... }
A SearchSQLOrderFieldGet
szintén egy segítő a
TicketSearch
modulhoz. A
$Param{TableAlias}
paramétert meg kell tartani, és a
value_text
lecserélhető a value_date
vagy a value_int
paraméterrel a mezőtől függően.
sub EditFieldValueGet { ... }
Az EditFieldValueGet()
egy olyan függvény, amelyet az OTRS
szerkesztő képernyőin használnak, és a célja a mező értékének lekérése vagy
egy sablonból (mint például az általános ügyintéző profilból), vagy egy
webkérésből. Ez a függvény megkapja a webkérést a
$Param{ParamObject}
paraméterben, amely az
előtétprogram-modul vagy a képernyő ParamObject
objektumának egy másolata.
Két visszatérési formátum létezik ennél a függvénynél. A normál, amely egyszerűen a nyers érték, vagy egy szerkezet, amely a mezőnév => mezőérték páros. Például egy dátum dinamikus mező normális esetben a dátumot szövegként adja vissza, és ha egy szerkezetet kell visszaadnia, akkor a kivonatban egy párost ad vissza a dátum minden egyes részéhez.
Ha az eredménynek egy szerkezetnek kell lennie, akkor normális esetben ezt arra használják, hogy az értékét egy sablonban tárolja, mint például egy általános ügyintéző profilban. Például egy dátummező számos HTML összetevőt használ a mező felépítéséhez, mint például a „használt” jelölőnégyzetet és kiválasztókat az évhez, hónaphoz, naphoz, stb.
sub EditFieldValueValidate { ... }
Ennek a függvénynek biztosítania kell legalább egy metódust az ellenőrzéshez, ha a mező üres, és hibát kell visszaadnia, ha a mező üres és kötelező, de végrehajthat további ellenőrzéseket is a másfajta mezőknél, mint például ha a kiválasztott lehetőség érvényes, vagy ha egy dátumnak csak a múltban kell lennie, stb. Egy egyéni hibaüzenetet is biztosíthat.
sub SearchFieldRender { ... }
Ezt a függvényt a jegykeresés párbeszédablak használja, és hasonló a
EditFieldRander()
függvényhez, de normális esetben egy keresési
képernyőn kisebb változtatásokat kell elvégezni az összes mezőnél. Például
ebben az esetben egy HTML szöveges beviteli mező használunk egy
jelszóbeviteli mező helyett. Más mezőkben (például legördülő mező)
többválasztósként jelenik meg azért, hogy egyszerre több érték keresését
tegye lehetővé a felhasználónak.
sub SearchFieldValueGet { ... }
Nagyon hasonló az EditFieldValueGet()
függvényhez, de eltérő
név előtagot használ a keresési párbeszédablak képernyőhöz átírva.
sub SearchFieldParameterBuild { ... }
A SearchFieldParameterBuild()
függvényt is a jegykeresés
párbeszédablak használja a helyes operátor és érték beállításához, hogy
elvégezze a keresést ezen a mezőn. Azt is visszaadja, hogy az értéket hogyan
kell megjeleníteni a használt keresési attribútumokban a találatok oldalon.
sub StatsFieldParameterBuild { ... }
Ezt a függvényt a statisztikák moduljai használják. Tartalmazza a mező
meghatározást a statisztikák formátumában. A rögzített értékekkel rendelkező
mezőknél tartalmazza az összes lehetséges értéket is, és ha azok
lefordíthatók, akkor nézze meg a BaseSelect
illesztőprogram kódját példaként arra, hogy azokat hogyan kell
megvalósítani.
sub StatsSearchFieldParameterBuild { ... }
A StatsSearchFieldParameterBuild()
nagyon hasonló a
SearchFieldParameterBuild()
függvényhez. A különbség az, hogy a
SearchFieldParameterBuild()
a keresési profilból kapja meg az
értéket, és ez pedig közvetlenül a paramétereiből kapja meg az értéket.
Ezt a függvényt a statisztikák modul használja.
sub TemplateValueTypeGet { ... }
A TemplateValueTypeGet()
függvényt annak megismeréséhez
használják, hogy a dinamikus mező értékei hogyan vannak eltárolva egy olyan
profilnál, amelyet le kell kérni (SCALAR vagy ARRAY formában), és
meghatározza a mező helyes nevét is a profilban.
sub RandomValueSet { ... }
Ezt a függvényt az otrs.FillDB.pl
parancsfájl
használja, hogy feltöltse az adatbázist néhány teszt és véletlenszerű
adattal. A függvény által beszúrt érték nem igazán fontos. Az egyetlen
megkötés az, hogy az értéknek kompatibilisnek kell lennie a mezőérték
típusával.
sub ObjectMatch { ... }
Az értesítési modulok használják. Ez a függvény 1-et ad vissza, ha a mező
jelen van a $Param{ObjectAttributes}
paraméterben, és ha
megegyezik a megadott értékkel.
Ezen folyamat bemutatásához a Foo függvénynél egy új dinamikus mező funkcionalitás kiterjesztés lesz hozzáadva a háttérprogram objektumhoz, valamint a szövegmező illesztőprogramba.
A kiterjesztés létrehozásához három fájlt fogunk létrehozni: egy beállítófájlt (XML) a modulok regisztrálásához, egy háttérprogram kiterjesztést (Perl) az új függvény meghatározásához, és egy szövegmező illesztőprogram kiterjesztést (Perl), amely megvalósítja az új függvényt a szövegmezőknél.
Fájlszerkezet:
$HOME (például /opt/otrs/) | ... |--/Kernel/ | |--/Config/ | | |--/Files/ | | | |DynamicFieldFooExtension.xml ... | |--/System/ | | |--/DynamicField/ | | | FooExtensionBackend.pm | | | |--/Driver/ | | | | |FooExtensionText.pm ...
A beállítófájlokat használják a kiterjesztések regisztrálásához a háttérprogramnál és az illesztőprogramoknál, valamint az egyes illesztőprogramok új viselkedéseihez.
Ha egy illesztőprogramot kiterjesztenek egy új függvénnyel, akkor a háttérprogramnak is szüksége lesz egy kiterjesztésre ahhoz a függvényhez.
Ebben a szakaszban a Foo
kiterjesztéshez egy beállítófájl
van megjelenítve és elmagyarázva.
<?xml version="1.0" encoding="utf-8"?> <otrs_config version="1.0" init="Application">
Ez a normál fejléc egy beállítófájlhoz.
<ConfigItem Name="DynamicFields::Extension::Backend###100-Foo" Required="0" Valid="1"> <Description Translatable="1">Dynamic Fields Extension.</Description> <Group>DynamicFieldFooExtension</Group> <SubGroup>DynamicFields::Extension::Registration</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::System::DynamicField::FooExtensionBackend</Item> </Hash> </Setting> </ConfigItem>
Ez a beállítás regisztrálja a kiterjeszt a Backend
objektumban. A modul alaposztályként lesz betöltve a
Backend
objektumból.
<ConfigItem Name="DynamicFields::Extension::Driver::Text###100-Foo" Required="0" Valid="1"> <Description Translatable="1">Dynamic Fields Extension.</Description> <Group>DynamicFieldFooExtension</Group> <SubGroup>DynamicFields::Extension::Registration</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::System::DynamicField::Driver::FooExtensionText</Item> <Item Key="Behaviors"> <Hash> <Item Key="Foo">1</Item> </Hash> </Item> </Hash> </Setting> </ConfigItem>
Ez egy kiterjesztés regisztrációja a Text
dinamikus mező
illesztőprogramban. A modul alaposztályként lesz betöltve az
illesztőprogramban. Figyeljen arra is, hogy új viselkedések is
megadhatók. Ezek a kiterjesztett viselkedések lesznek hozzáadva azokhoz a
viselkedésekhez, amelyekkel az illesztőprogram eredetileg rendelkezik, ebből
adódóan a HasBehavior()
hívásával azt ellenőrizve, hogy ezeknél
az új viselkedéseknél teljesen átlátszó legyen.
</otrs_config>
Egy beállítófájl szabványos lezárása.
A háttérprogram kiterjesztések átláthatóan lesznek betöltve magába a háttérprogramba egy alaposztályként. A háttérprogramból az összes meghatározott objektum és tulajdonság elérhető lesz a kiterjesztésben.
A háttérprogram kiterjesztésben meghatározott összes új függvényt meg kell valósítani egy illesztőprogram kiterjesztésben.
Ebben a szakaszban a háttérprogramhoz készített Foo
kiterjesztés van megjelenítve és elmagyarázva. A kiterjesztés csak a
Foo()
függvényt határozza meg.
# -- # Kernel/System/DynamicField/FooExtensionBackend.pm - Extension for DynamicField backend # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::DynamicField::FooExtensionBackend; use strict; use warnings; use Kernel::System::VariableCheck qw(:all); =head1 NAME Kernel::System::DynamicField::FooExtensionBackend =head1 SYNOPSIS DynamicFields Extension for Backend =head1 PUBLIC INTERFACE =over 4 =cut
Ez egy gyakori fejléc, amely megtalálható a szokásos OTRS modulokban. Az
osztály/csomag neve a package
kulcsszón keresztül van
deklarálva.
=item Foo() Tesztelő függvény: 1-et ad vissza, ha a függvény elérhető egy dinamikus mező illesztőprogramnál. my $Success = $BackendObject->Foo( DynamicFieldConfig => $DynamicFieldConfig, # a dinamikus mező teljes beállítása ); Returns: $Success = 1; # vagy undef =cut sub Foo { my ( $Self, %Param ) = @_; # a szükséges dolgok ellenőrzése for my $Needed (qw(DynamicFieldConfig)) { if ( !$Param{$Needed} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Szükséges: $Needed!", ); return; } } # a DynamicFieldConfig ellenőrzése (általánosan) if ( !IsHashRefWithData( $Param{DynamicFieldConfig} ) ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "A mező beállítása érvénytelen", ); return; } # a DynamicFieldConfig ellenőrzése (belsőleg) for my $Needed (qw(ID FieldType ObjectType)) { if ( !$Param{DynamicFieldConfig}->{$Needed} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "$Needed szükséges ebben: DynamicFieldConfig!", ); return; } } # a dinamikus mezőre jellemző háttérprogram beállítása my $DynamicFieldBackend = 'DynamicField' . $Param{DynamicFieldConfig}->{FieldType} . 'Object'; if ( !$Self->{$DynamicFieldBackend} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "A háttérprogram érvénytelen: $Param{DynamicFieldConfig}->{FieldType}!", ); return; } # annak ellenőrzése, hogy a függvény elérhető-e return if !$Self->{$DynamicFieldBackend}->can('Foo'); # a HasBehavior meghívása az adott háttérprogramnál return $Self->{$DynamicFieldBackend}->Foo(%Param); }
A Foo()
függvényt kizárólag tesztelési célokra
használják. Először leellenőrzi a dinamikus mező beállításait, majd azt
ellenőrzi, hogy a dinamikus mező illesztőprogram (típus) létezik-e, és
betöltésre került-e. Annak megakadályozásához, hogy egy olyan
illesztőprogramnál történjen függvényhívás, ahol nincs meghatározva, először
azt ellenőrzi, hogy az illesztőprogram képes-e végrehajtani a függvényt,
majd végrehajtja a függvényt az illesztőprogramban az összes paramétert
átadva.
Lehetséges annak a lépésnek a kihagyása is, amely azt próbálja, hogy az illesztőprogram képes-e végrehajtani a függvényt. Ennek elvégzéséhez szükséges egy mechanizmus megvalósítása az előtétprogram modulban egy különleges viselkedés megköveteléséhez a dinamikus mezőnél, és csak azután hívja meg a függvényt a háttérprogram objektumban.
Az illesztőprogram kiterjesztések átláthatóan lesznek betöltve magába az illesztőprogramba egy alaposztályként. Az illesztőprogramból az összes meghatározott objektum és tulajdonság elérhető lesz a kiterjesztésben.
Az illesztőprogram kiterjesztésben megvalósított összes új függvényt meg kell határozni egy háttérprogram kiterjesztésben, mivel minden függvény a háttérprogram objektumból kerül meghívásra.
Ebben a szakaszban a szövegmező illesztőprogramhoz készített
Foo
kiterjesztés van megjelenítve és elmagyarázva. A
kiterjesztés csak a Foo()
függvényt valósítja meg.
# -- # Kernel/System/DynamicField/Driver/FooExtensionText.pm - Extension for DynamicField Text Driver # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::DynamicField::Driver::FooExtensionText; use strict; use warnings; =head1 NAME Kernel::System::DynamicField::Driver::FooExtensionText =head1 SYNOPSIS DynamicFields Text Driver Extension =head1 PUBLIC INTERFACE This module extends the public interface of L<Kernel::System::DynamicField::Backend>. Please look there for a detailed reference of the functions. =over 4 =cut
Ez egy gyakori fejléc, amely megtalálható a szokásos OTRS modulokban. Az
osztály/csomag neve a package
kulcsszón keresztül van
deklarálva.
sub Foo { my ( $Self, %Param ) = @_; return 1; }
A Foo()
függvénynek nincs különleges logikája. Csak tesztelésre
van, és mindig 1-et ad vissza.
A levelezési modulokat a levelezési folyamat során használják. Kétféle
levelezési modul létezik: PostMasterPre
(egy e-mail
feldolgozása után használják) és PostMasterPost
(azután
használják, amikor egy e-mail feldolgozásra került, és az adatbázisban van).
Ha saját levelezési szűrőket szeretne létrehozni, akkor egyszerűen hozza
létre a saját modulját. Ezek a modulok a
Kernel/System/PostMaster/Filter/*.pm
fájlokban
találhatók. Az alapértelmezett modulokért nézze meg az adminisztrátori
kézikönyvet. Mindössze két függvényre van szüksége: new()
és
Run()
.
A következőkben egy példaszerű modul található az e-mailek egyeztetéséhez és
az X-OTRS fejlécek beállításához (további információkért nézze meg a
doc/X-OTRS-Headers.txt
fájlt).
Kernel/Config/Files/MyModule.xml
:
<ConfigItem Name="PostMaster::PreFilterModule###1-Example" Required="0" Valid="1"> <Description Translatable="1">Példamodul a bejövő üzenetek szűréséhez és manipulálásához.</Description> <Group>Ticket</Group> <SubGroup>Core::PostMaster</SubGroup> <Setting> <Hash> <Item Key="Module">Kernel::System::PostMaster::Filter::Example</Item> <Item Key="Match"> <Hash> <Item Key="From">noreply@</Item> </Hash> </Item> <Item Key="Set"> <Hash> <Item Key="X-OTRS-Ignore">yes</Item> </Hash> </Item> </Hash> </Setting> </ConfigItem>
És a tényleges szűrőkód a
Kernel/System/PostMaster/Filter/Example.pm
fájlban:
# -- # Copyright (C) 2001-2018 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::PostMaster::Filter::Example; use strict; use warnings; our @ObjectDependencies = ( 'Kernel::System::Log', ); sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless ($Self, $Type); $Self->{Debug} = $Param{Debug} || 0; return $Self; } sub Run { my ( $Self, %Param ) = @_; # get config options my %Config = (); my %Match = (); my %Set = (); if ($Param{JobConfig} && ref($Param{JobConfig}) eq 'HASH') { %Config = %{$Param{JobConfig}}; if ($Config{Match}) { %Match = %{$Config{Match}}; } if ($Config{Set}) { %Set = %{$Config{Set}}; } } # match 'Match => ???' stuff my $Matched = ''; my $MatchedNot = 0; for (sort keys %Match) { if ($Param{GetParam}->{$_} && $Param{GetParam}->{$_} =~ /$Match{$_}/i) { $Matched = $1 || '1'; if ($Self->{Debug} > 1) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'debug', Message => "'$Param{GetParam}->{$_}' =~ /$Match{$_}/i matched!", ); } } else { $MatchedNot = 1; if ($Self->{Debug} > 1) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'debug', Message => "'$Param{GetParam}->{$_}' =~ /$Match{$_}/i matched NOT!", ); } } } # should I ignore the incoming mail? if ($Matched && !$MatchedNot) { for (keys %Set) { if ($Set{$_} =~ /\[\*\*\*\]/i) { $Set{$_} = $Matched; } $Param{GetParam}->{$_} = $Set{$_}; $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'notice', Message => "Set param '$_' to '$Set{$_}' (Message-ID: $Param{GetParam}->{'Message-ID'}) ", ); } } return 1; } 1;
A következő kép az e-mail feldolgozási folyamatát mutatja be.