init III
This commit is contained in:
799
Perl OTRS/Kernel/System/Calendar/Import/ICal.pm
Normal file
799
Perl OTRS/Kernel/System/Calendar/Import/ICal.pm
Normal file
@@ -0,0 +1,799 @@
|
||||
# --
|
||||
# Copyright (C) 2001-2019 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::Calendar::Import::ICal;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Data::ICal;
|
||||
use Data::ICal::Entry::Event;
|
||||
use Date::ICal;
|
||||
|
||||
use Kernel::System::VariableCheck qw(:all);
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Config',
|
||||
'Kernel::System::Cache',
|
||||
'Kernel::System::Calendar',
|
||||
'Kernel::System::Calendar::Appointment',
|
||||
'Kernel::System::Calendar::Plugin',
|
||||
'Kernel::System::Calendar::Team',
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::DB',
|
||||
'Kernel::System::Encode',
|
||||
'Kernel::System::Log',
|
||||
'Kernel::System::Main',
|
||||
'Kernel::System::User',
|
||||
);
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Kernel::System::Calendar::Import::ICal - C<iCalendar> import lib
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Import functions for C<iCalendar> format.
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
=head2 new()
|
||||
|
||||
create an object. Do not use it directly, instead use:
|
||||
|
||||
use Kernel::System::ObjectManager;
|
||||
local $Kernel::OM = Kernel::System::ObjectManager->new();
|
||||
my $ImportObject = $Kernel::OM->Get('Kernel::System::Calendar::Export::ICal');
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {%Param};
|
||||
bless( $Self, $Type );
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
=head2 Import()
|
||||
|
||||
Import calendar in C<iCalendar> format.
|
||||
|
||||
my $Success = $ImportObject->Import(
|
||||
CalendarID => 123,
|
||||
ICal => # (required) iCal string
|
||||
'
|
||||
BEGIN:VCALENDAR
|
||||
PRODID:Zimbra-Calendar-Provider
|
||||
VERSION:2.0
|
||||
METHOD:REQUEST
|
||||
...
|
||||
',
|
||||
UserID => 1, # (required) UserID
|
||||
UpdateExisting => 0, # (optional) Delete existing Appointments within same Calendar if UniqueID matches
|
||||
UntilLimit => '2017-01-01 00:00:00', # (optional) If provided, system will use this value for limiting recurring Appointments without defined end date
|
||||
# instead of AppointmentCalendar::Import::RecurringMonthsLimit to do the calculation
|
||||
# NOTE: PLEASE USE THIS PARAMETER FOR UNIT TESTS ONLY
|
||||
);
|
||||
|
||||
Returns number of imported appointments if successful, otherwise 0.
|
||||
|
||||
=cut
|
||||
|
||||
sub Import {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for my $Needed (qw(CalendarID ICal UserID)) {
|
||||
if ( !$Param{$Needed} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Needed!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
my $UntilLimitedTimestamp = $Param{UntilLimit} || '';
|
||||
|
||||
if ( !$UntilLimitedTimestamp ) {
|
||||
|
||||
# Calculate until time which will be used if there is any recurring Appointment without end
|
||||
# time defined.
|
||||
my $UntilTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
|
||||
my $RecurringMonthsLimit
|
||||
= $Kernel::OM->Get('Kernel::Config')->Get("AppointmentCalendar::Import::RecurringMonthsLimit")
|
||||
|| '12'; # default 12 months
|
||||
|
||||
$UntilTimeObject->Add(
|
||||
Months => $RecurringMonthsLimit,
|
||||
);
|
||||
$UntilLimitedTimestamp = $UntilTimeObject->ToString();
|
||||
}
|
||||
|
||||
# Turn on UTF8 flag on supplied string for correct encoding in PostgreSQL backend.
|
||||
$Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( \$Param{ICal} );
|
||||
|
||||
my $Calendar = Data::ICal->new( data => $Param{ICal} );
|
||||
|
||||
# If external library encountered an error while parsing the ICS file, log the received message
|
||||
# at this time and return.
|
||||
if ( $Calendar->{errno} ) {
|
||||
my $ErrorMessage = $Calendar->{error_message} // '';
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "[Data::ICal] $ErrorMessage",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
my @Entries = @{ $Calendar->entries() };
|
||||
my $AppointmentsImported = 0;
|
||||
|
||||
my $PluginObject = $Kernel::OM->Get('Kernel::System::Calendar::Plugin');
|
||||
my $AppointmentObject = $Kernel::OM->Get('Kernel::System::Calendar::Appointment');
|
||||
|
||||
ENTRY:
|
||||
for my $Entry (@Entries) {
|
||||
my $Properties = $Entry->properties();
|
||||
|
||||
my %Parameters;
|
||||
my %LinkedObjects;
|
||||
|
||||
# get uid
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{'uid'} )
|
||||
&& ref $Properties->{'uid'}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{'uid'}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
$Parameters{UniqueID} = $Properties->{'uid'}->[0]->{'value'};
|
||||
}
|
||||
|
||||
# get title
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{'summary'} )
|
||||
&& ref $Properties->{'summary'}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{'summary'}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
$Parameters{Title} = $Properties->{'summary'}->[0]->{'value'};
|
||||
}
|
||||
|
||||
# get description
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{'description'} )
|
||||
&& ref $Properties->{'description'}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{'description'}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
$Parameters{Description} = $Properties->{'description'}->[0]->{'value'};
|
||||
}
|
||||
|
||||
# get start time
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{'dtstart'} )
|
||||
&& ref $Properties->{'dtstart'}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{'dtstart'}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
|
||||
my $TimezoneID;
|
||||
|
||||
if ( ref $Properties->{'dtstart'}->[0]->{'_parameters'} eq 'HASH' ) {
|
||||
|
||||
# check if it's an all day event
|
||||
# 1) there is no time component for the date value
|
||||
# 2) there is an explicit value parameter set to DATE
|
||||
if (
|
||||
length $Properties->{'dtstart'}->[0]->{'value'} == 8
|
||||
||
|
||||
(
|
||||
$Properties->{'dtstart'}->[0]->{'_parameters'}->{'VALUE'}
|
||||
&& $Properties->{'dtstart'}->[0]->{'_parameters'}->{'VALUE'} eq 'DATE'
|
||||
)
|
||||
)
|
||||
{
|
||||
$Parameters{AllDay} = 1;
|
||||
}
|
||||
|
||||
# check timezone
|
||||
if ( $Properties->{'dtstart'}->[0]->{'_parameters'}->{'TZID'} ) {
|
||||
$TimezoneID = $Properties->{'dtstart'}->[0]->{'_parameters'}->{'TZID'};
|
||||
}
|
||||
}
|
||||
|
||||
my $StartTimeICal = $Self->_FormatTime(
|
||||
Time => $Properties->{'dtstart'}->[0]->{'value'},
|
||||
);
|
||||
my $StartTimeObject = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
String => $StartTimeICal,
|
||||
TimeZone => $TimezoneID,
|
||||
},
|
||||
);
|
||||
|
||||
if ( !$Parameters{AllDay} ) {
|
||||
$StartTimeObject->ToOTRSTimeZone();
|
||||
}
|
||||
|
||||
$Parameters{StartTime} = $StartTimeObject->ToString();
|
||||
}
|
||||
|
||||
# get end time
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{'dtend'} )
|
||||
&& ref $Properties->{'dtend'}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{'dtend'}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
my $TimezoneID;
|
||||
|
||||
if ( ref $Properties->{'dtend'}->[0]->{'_parameters'} eq 'HASH' ) {
|
||||
|
||||
# check timezone
|
||||
if ( $Properties->{'dtend'}->[0]->{'_parameters'}->{'TZID'} ) {
|
||||
$TimezoneID = $Properties->{'dtend'}->[0]->{'_parameters'}->{'TZID'};
|
||||
}
|
||||
}
|
||||
|
||||
my $EndTimeICal = $Self->_FormatTime(
|
||||
Time => $Properties->{'dtend'}->[0]->{'value'},
|
||||
);
|
||||
my $EndTimeObject = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
String => $EndTimeICal,
|
||||
TimeZone => $TimezoneID,
|
||||
},
|
||||
);
|
||||
|
||||
if ( !$Parameters{AllDay} ) {
|
||||
$EndTimeObject->ToOTRSTimeZone();
|
||||
}
|
||||
|
||||
$Parameters{EndTime} = $EndTimeObject->ToString();
|
||||
}
|
||||
|
||||
# Some iCalendar implementations (looking at you icalendar-ruby) do not require nor include
|
||||
# end time for appointments. In this case, prevent failing and use start time instead.
|
||||
else {
|
||||
$Parameters{EndTime} = $Parameters{StartTime};
|
||||
}
|
||||
|
||||
# get location
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{'location'} )
|
||||
&& ref $Properties->{'location'}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{'location'}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
$Parameters{Location} = $Properties->{'location'}->[0]->{'value'};
|
||||
}
|
||||
|
||||
# get rrule
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{'rrule'} )
|
||||
&& ref $Properties->{'rrule'}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{'rrule'}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
my ( $Frequency, $Until, $Interval, $Count, $DayNames, $MonthDay, $Months );
|
||||
|
||||
my @Rules = split ';', $Properties->{'rrule'}->[0]->{'value'};
|
||||
|
||||
RULE:
|
||||
for my $Rule (@Rules) {
|
||||
|
||||
if ( $Rule =~ /FREQ=(.*?)$/i ) {
|
||||
$Frequency = $1;
|
||||
}
|
||||
elsif ( $Rule =~ /UNTIL=(.*?)$/i ) {
|
||||
$Until = $1;
|
||||
}
|
||||
elsif ( $Rule =~ /INTERVAL=(\d+?)$/i ) {
|
||||
$Interval = $1;
|
||||
}
|
||||
elsif ( $Rule =~ /COUNT=(\d+?)$/i ) {
|
||||
$Count = $1;
|
||||
}
|
||||
elsif ( $Rule =~ /BYDAY=(.*?)$/i ) {
|
||||
$DayNames = $1;
|
||||
}
|
||||
elsif ( $Rule =~ /BYMONTHDAY=(.*?)$/i ) {
|
||||
$MonthDay = $1;
|
||||
}
|
||||
elsif ( $Rule =~ /BYMONTH=(.*?)$/i ) {
|
||||
$Months = $1;
|
||||
}
|
||||
}
|
||||
|
||||
$Interval ||= 1; # default value
|
||||
|
||||
# this appointment is repeating
|
||||
if ( $Frequency eq "DAILY" ) {
|
||||
$Parameters{Recurring} = 1;
|
||||
$Parameters{RecurrenceType} = $Interval == 1 ? "Daily" : "CustomDaily";
|
||||
$Parameters{RecurrenceInterval} = $Interval;
|
||||
|
||||
}
|
||||
elsif ( $Frequency eq "WEEKLY" ) {
|
||||
if ($DayNames) {
|
||||
|
||||
# custom
|
||||
|
||||
my @Days;
|
||||
|
||||
# SU,MO,TU,WE,TH,FR,SA
|
||||
for my $DayName ( split( ',', $DayNames ) ) {
|
||||
|
||||
if ( uc $DayName eq 'MO' ) {
|
||||
push @Days, 1;
|
||||
}
|
||||
elsif ( uc $DayName eq 'TU' ) {
|
||||
push @Days, 2;
|
||||
}
|
||||
elsif ( uc $DayName eq 'WE' ) {
|
||||
push @Days, 3;
|
||||
}
|
||||
elsif ( uc $DayName eq 'TH' ) {
|
||||
push @Days, 4;
|
||||
}
|
||||
elsif ( uc $DayName eq 'FR' ) {
|
||||
push @Days, 5;
|
||||
}
|
||||
elsif ( uc $DayName eq 'SA' ) {
|
||||
push @Days, 6;
|
||||
}
|
||||
elsif ( uc $DayName eq 'SU' ) {
|
||||
push @Days, 7;
|
||||
}
|
||||
}
|
||||
|
||||
if ( scalar @Days > 0 ) {
|
||||
|
||||
$Parameters{Recurring} = 1;
|
||||
$Parameters{RecurrenceType} = "CustomWeekly";
|
||||
$Parameters{RecurrenceInterval} = $Interval;
|
||||
$Parameters{RecurrenceFrequency} = \@Days;
|
||||
}
|
||||
}
|
||||
else {
|
||||
# each n days
|
||||
$Parameters{Recurring} = 1;
|
||||
$Parameters{RecurrenceType} = "Weekly";
|
||||
$Parameters{RecurrenceInterval} = $Interval;
|
||||
}
|
||||
}
|
||||
elsif ( $Frequency eq "MONTHLY" ) {
|
||||
|
||||
# Skip unsupported custom monthly recurring rules:
|
||||
# - FREQ=MONTHLY;BYDAY=2SA
|
||||
if ($DayNames) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Skip import of unsupported recurring rule: "
|
||||
. $Properties->{'rrule'}->[0]->{'value'},
|
||||
);
|
||||
next ENTRY;
|
||||
}
|
||||
|
||||
if ($MonthDay) {
|
||||
|
||||
# Custom
|
||||
# FREQ=MONTHLY;UNTIL=20170101T080000Z;BYMONTHDAY=16,31'
|
||||
my @Days = split( ',', $MonthDay );
|
||||
|
||||
$Parameters{Recurring} = 1;
|
||||
$Parameters{RecurrenceType} = "CustomMonthly";
|
||||
$Parameters{RecurrenceFrequency} = \@Days;
|
||||
$Parameters{RecurrenceInterval} = $Interval;
|
||||
}
|
||||
else {
|
||||
$Parameters{Recurring} = 1;
|
||||
$Parameters{RecurrenceType} = "Monthly";
|
||||
$Parameters{RecurrenceInterval} = $Interval;
|
||||
}
|
||||
}
|
||||
elsif ( $Frequency eq "YEARLY" ) {
|
||||
|
||||
# Skip unsupported custom yearly recurring rules:
|
||||
# - FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
|
||||
# - FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
|
||||
if ($DayNames) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Skip import of unsupported recurring rule: "
|
||||
. $Properties->{'rrule'}->[0]->{'value'},
|
||||
);
|
||||
next ENTRY;
|
||||
}
|
||||
|
||||
my @Months = split( ',', $Months || '' );
|
||||
|
||||
my $StartTimeObject = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
String => $Parameters{StartTime},
|
||||
},
|
||||
);
|
||||
|
||||
if (
|
||||
scalar @Months > 1
|
||||
|| (
|
||||
scalar @Months == 1
|
||||
&& $StartTimeObject->Get()->{Day} != $Months[0]
|
||||
)
|
||||
)
|
||||
{
|
||||
$Parameters{Recurring} = 1;
|
||||
$Parameters{RecurrenceType} = "CustomYearly";
|
||||
$Parameters{RecurrenceFrequency} = \@Months;
|
||||
$Parameters{RecurrenceInterval} = $Interval;
|
||||
}
|
||||
else {
|
||||
$Parameters{Recurring} = 1;
|
||||
$Parameters{RecurrenceType} = "Yearly";
|
||||
$Parameters{RecurrenceInterval} = $Interval;
|
||||
}
|
||||
}
|
||||
|
||||
# FREQ=YEARLY;INTERVAL=2;BYMONTH=1,2,12
|
||||
# FREQ=MONTHLY;UNTIL=20170302T121500Z'
|
||||
# FREQ=MONTHLY;UNTIL=20170202T090000Z;INTERVAL=2;BYMONTHDAY=31',
|
||||
# FREQ=WEEKLY;INTERVAL=2;BYDAY=TU
|
||||
# FREQ=YEARLY;UNTIL=20200602T080000Z;INTERVAL=2;BYMONTHDAY=1;BYMONTH=4';
|
||||
|
||||
# FREQ=DAILY;COUNT=3
|
||||
|
||||
if ($Until) {
|
||||
$Parameters{RecurrenceUntil} = $Self->_FormatTime(
|
||||
Time => $Until,
|
||||
);
|
||||
}
|
||||
elsif ($Count) {
|
||||
$Parameters{RecurrenceCount} = $Count;
|
||||
}
|
||||
else {
|
||||
# default value
|
||||
$Parameters{RecurrenceUntil} = $UntilLimitedTimestamp;
|
||||
}
|
||||
|
||||
# excluded dates
|
||||
if ( IsArrayRefWithData( $Properties->{'exdate'} ) ) {
|
||||
my @RecurrenceExclude;
|
||||
for my $Exclude ( @{ $Properties->{'exdate'} } ) {
|
||||
if (
|
||||
ref $Exclude eq 'Data::ICal::Property'
|
||||
&& $Exclude->{'value'}
|
||||
)
|
||||
{
|
||||
my $TimezoneID;
|
||||
if ( ref $Exclude->{'_parameters'} eq 'HASH' ) {
|
||||
|
||||
# check timezone
|
||||
if ( $Exclude->{'_parameters'}->{'TZID'} ) {
|
||||
$TimezoneID = $Exclude->{'_parameters'}->{'TZID'};
|
||||
}
|
||||
}
|
||||
|
||||
my $ExcludeTimeICal = $Self->_FormatTime(
|
||||
Time => $Exclude->{'value'},
|
||||
);
|
||||
my $ExcludeTimeObject = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
String => $ExcludeTimeICal,
|
||||
TimeZone => $TimezoneID,
|
||||
},
|
||||
);
|
||||
|
||||
if ( !$Parameters{AllDay} ) {
|
||||
$ExcludeTimeObject->ToOTRSTimeZone();
|
||||
}
|
||||
|
||||
push @RecurrenceExclude, $ExcludeTimeObject->ToString();
|
||||
}
|
||||
}
|
||||
$Parameters{RecurrenceExclude} = \@RecurrenceExclude;
|
||||
}
|
||||
}
|
||||
|
||||
# check if team object is registered
|
||||
if ( $Kernel::OM->Get('Kernel::System::Main')->Require( 'Kernel::System::Calendar::Team', Silent => 1 ) ) {
|
||||
|
||||
# get team
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{'x-otrs-team'} )
|
||||
&& ref $Properties->{'x-otrs-team'}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{'x-otrs-team'}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
my @Teams = split( ",", $Properties->{'x-otrs-team'}->[0]->{'value'} );
|
||||
|
||||
if (@Teams) {
|
||||
my @TeamIDs;
|
||||
|
||||
# get team ids
|
||||
for my $TeamName (@Teams) {
|
||||
my %Team = $Kernel::OM->Get('Kernel::System::Calendar::Team')->TeamGet(
|
||||
Name => $TeamName,
|
||||
UserID => $Param{UserID},
|
||||
);
|
||||
push @TeamIDs, $Team{ID} if $Team{ID};
|
||||
}
|
||||
$Parameters{TeamID} = \@TeamIDs if @TeamIDs;
|
||||
}
|
||||
}
|
||||
|
||||
# get resource
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{'x-otrs-resource'} )
|
||||
&& ref $Properties->{'x-otrs-resource'}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{'x-otrs-resource'}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
my @Resources = split( ",", $Properties->{'x-otrs-resource'}->[0]->{'value'} );
|
||||
|
||||
if (@Resources) {
|
||||
my @Users;
|
||||
|
||||
# get user ids
|
||||
for my $UserLogin (@Resources) {
|
||||
my $UserID = $Kernel::OM->Get('Kernel::System::User')->UserLookup(
|
||||
UserLogin => $UserLogin,
|
||||
);
|
||||
push @Users, $UserID if $UserID;
|
||||
}
|
||||
$Parameters{ResourceID} = \@Users if @Users;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# get available plugin keys suitable for lowercase search
|
||||
my $PluginKeys = $PluginObject->PluginKeys();
|
||||
|
||||
# plugin fields (start with 'x-otrs-plugin-')
|
||||
my @PluginFields = grep { $_ =~ /x-otrs-plugin-/i } keys %{$Properties};
|
||||
|
||||
PLUGINFIELD:
|
||||
for my $PluginField (@PluginFields) {
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{$PluginField} )
|
||||
&& ref $Properties->{$PluginField}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{$PluginField}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
# extract lowercase plugin key
|
||||
$PluginField =~ /x-otrs-plugin-(.*)$/;
|
||||
my $PluginKeyLC = $1;
|
||||
|
||||
# get proper plugin key
|
||||
my $PluginKey = $PluginKeys->{$PluginKeyLC};
|
||||
next PLUGINFIELD if !$PluginKey;
|
||||
|
||||
my @PluginData = split( ",", $Properties->{$PluginField}->[0]->{'value'} );
|
||||
$LinkedObjects{$PluginKey} = \@PluginData;
|
||||
}
|
||||
}
|
||||
|
||||
next ENTRY if !$Parameters{Title};
|
||||
|
||||
my %Appointment;
|
||||
|
||||
# get recurrence id
|
||||
if (
|
||||
IsArrayRefWithData( $Properties->{'recurrence-id'} )
|
||||
&& ref $Properties->{'recurrence-id'}->[0] eq 'Data::ICal::Property'
|
||||
&& $Properties->{'recurrence-id'}->[0]->{'value'}
|
||||
)
|
||||
{
|
||||
# get parent id
|
||||
my %ParentAppointment = $AppointmentObject->AppointmentGet(
|
||||
UniqueID => $Parameters{UniqueID},
|
||||
CalendarID => $Param{CalendarID},
|
||||
);
|
||||
next ENTRY if !%ParentAppointment;
|
||||
|
||||
$Parameters{ParentID} = $ParentAppointment{AppointmentID};
|
||||
|
||||
my $TimezoneID;
|
||||
if ( ref $Properties->{'recurrence-id'}->[0]->{'_parameters'} eq 'HASH' ) {
|
||||
|
||||
# check timezone
|
||||
if ( $Properties->{'recurrence-id'}->[0]->{'_parameters'}->{'TZID'} ) {
|
||||
$TimezoneID = $Properties->{'recurrence-id'}->[0]->{'_parameters'}->{'TZID'};
|
||||
}
|
||||
}
|
||||
|
||||
my $RecurrenceIDICal = $Self->_FormatTime(
|
||||
Time => $Properties->{'recurrence-id'}->[0]->{'value'},
|
||||
);
|
||||
my $RecurrenceIDObject = $Kernel::OM->Create(
|
||||
'Kernel::System::DateTime',
|
||||
ObjectParams => {
|
||||
String => $RecurrenceIDICal,
|
||||
TimeZone => $TimezoneID,
|
||||
},
|
||||
);
|
||||
|
||||
if ( !$Parameters{AllDay} ) {
|
||||
$RecurrenceIDObject->ToOTRSTimeZone();
|
||||
}
|
||||
|
||||
$Param{RecurrenceID} = $RecurrenceIDObject->ToString();
|
||||
|
||||
# delete existing overridden occurrence
|
||||
$AppointmentObject->AppointmentDeleteOccurrence(
|
||||
UniqueID => $Parameters{UniqueID},
|
||||
CalendarID => $Param{CalendarID},
|
||||
RecurrenceID => $Param{RecurrenceID},
|
||||
UserID => $Param{UserID},
|
||||
);
|
||||
}
|
||||
|
||||
# Check if appointment with same UniqueID in the same calendar already exists.
|
||||
else {
|
||||
%Appointment = $AppointmentObject->AppointmentGet(
|
||||
UniqueID => $Parameters{UniqueID},
|
||||
CalendarID => $Param{CalendarID},
|
||||
);
|
||||
|
||||
if (
|
||||
$Appointment{CalendarID}
|
||||
&& ( !$Param{UpdateExisting} || $Appointment{CalendarID} != $Param{CalendarID} )
|
||||
)
|
||||
{
|
||||
# If overwrite option isn't activated, create new appointment by clearing the
|
||||
# UniqueID.
|
||||
if (%Appointment) {
|
||||
delete $Parameters{UniqueID};
|
||||
}
|
||||
%Appointment = ();
|
||||
}
|
||||
}
|
||||
|
||||
my $Success;
|
||||
|
||||
# appointment exists in same Calendar, update it
|
||||
if (
|
||||
%Appointment
|
||||
&& $Appointment{AppointmentID}
|
||||
&& $Param{CalendarID} == $Appointment{CalendarID}
|
||||
)
|
||||
{
|
||||
$Success = $AppointmentObject->AppointmentUpdate(
|
||||
CalendarID => $Param{CalendarID},
|
||||
AppointmentID => $Appointment{AppointmentID},
|
||||
UserID => $Param{UserID},
|
||||
%Parameters,
|
||||
);
|
||||
}
|
||||
|
||||
# there is no appointment, create new one
|
||||
else {
|
||||
$Success = $AppointmentObject->AppointmentCreate(
|
||||
CalendarID => $Param{CalendarID},
|
||||
UserID => $Param{UserID},
|
||||
%Parameters,
|
||||
);
|
||||
}
|
||||
|
||||
if ($Success) {
|
||||
|
||||
PLUGINKEY:
|
||||
for my $PluginKey ( sort keys %LinkedObjects ) {
|
||||
next PLUGINKEY if !IsArrayRefWithData( $LinkedObjects{$PluginKey} );
|
||||
|
||||
# add links
|
||||
for my $PluginData ( @{ $LinkedObjects{$PluginKey} } ) {
|
||||
my $LinkSuccess = $PluginObject->PluginLinkAdd(
|
||||
AppointmentID => $Success,
|
||||
PluginKey => $PluginKey,
|
||||
PluginData => $PluginData,
|
||||
UserID => $Param{UserID},
|
||||
);
|
||||
|
||||
if ( !$LinkSuccess ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message =>
|
||||
"Unable to create object link (AppointmentID=$Success - $PluginKey=$PluginData) during calendar import!"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$AppointmentsImported++;
|
||||
}
|
||||
}
|
||||
|
||||
return $AppointmentsImported;
|
||||
}
|
||||
|
||||
sub _FormatTime {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for my $Needed (qw(Time)) {
|
||||
if ( !$Param{$Needed} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $Needed!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
my $TimeStamp;
|
||||
|
||||
if ( $Param{Time} =~ /(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})/i ) {
|
||||
|
||||
# format string
|
||||
$TimeStamp = "$1-$2-$3 $4:$5:$6";
|
||||
}
|
||||
elsif ( $Param{Time} =~ /(\d{4})(\d{2})(\d{2})/ ) {
|
||||
|
||||
# only date is given (without time)
|
||||
$TimeStamp = "$1-$2-$3 00:00:00";
|
||||
}
|
||||
|
||||
return $TimeStamp;
|
||||
}
|
||||
|
||||
{
|
||||
no warnings 'redefine'; ## no critic
|
||||
|
||||
# Include additional optional repeatable properties used by some iCalendar implementations, in
|
||||
# order to prevent Perl warnings.
|
||||
sub Data::ICal::Entry::Alarm::optional_repeatable_properties { ## no critic
|
||||
qw(
|
||||
uid acknowledged related-to description
|
||||
);
|
||||
}
|
||||
|
||||
sub Data::ICal::Entry::Event::optional_repeatable_properties { ## no critic
|
||||
my $Self = shift;
|
||||
|
||||
my @Properties;
|
||||
|
||||
if ( not $Self->vcal10 ) { ## no critic
|
||||
@Properties = qw(
|
||||
attach attendee categories comment
|
||||
contact exdate exrule request-status related-to
|
||||
resources rdate rrule
|
||||
);
|
||||
}
|
||||
else {
|
||||
@Properties = qw(
|
||||
aalarm attach attendee categories
|
||||
dalarm exdate exrule malarm palarm related-to
|
||||
resources rdate rrule
|
||||
);
|
||||
}
|
||||
|
||||
push @Properties, '';
|
||||
|
||||
return @Properties;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=head1 TERMS AND CONDITIONS
|
||||
|
||||
This software is part of the OTRS project (L<https://otrs.org/>).
|
||||
|
||||
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 L<https://www.gnu.org/licenses/gpl-3.0.txt>.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user