| 53 | | my $item = $fields[7] ? |
|---|
| 54 | | $this->_parse_recurrent_event(@fields) : |
|---|
| 55 | | $this->_parse_general_event(@fields); |
|---|
| 56 | | $item->{debug_info} = $line; # save the CSV line as for debug info. |
|---|
| 57 | | push @items, $item if $item; |
|---|
| | 53 | # Cybozu Calendar CSV Format |
|---|
| | 54 | # GENERIC | RECCURENT |
|---|
| | 55 | # [ 0] id? | id? |
|---|
| | 56 | # [ 1] created | created |
|---|
| | 57 | # [ 2] <BLANK> x start_date |
|---|
| | 58 | # [ 3] start_date x end_date |
|---|
| | 59 | # [ 4] end_date x until_date |
|---|
| | 60 | # [ 5] start_time | start_time |
|---|
| | 61 | # [ 6] end_time | end_time |
|---|
| | 62 | # [ 7] <BLANK> | freq |
|---|
| | 63 | # [ 8] <BLANK> | freq_value |
|---|
| | 64 | # [ 9] ??? | ??? |
|---|
| | 65 | # [10] ??? | ??? |
|---|
| | 66 | # [11] abbrev | abbrev |
|---|
| | 67 | # [12] summary | summary |
|---|
| | 68 | # [13] description | description |
|---|
| | 69 | |
|---|
| | 70 | my %param; |
|---|
| | 71 | @param{qw(created start_time end_time freq freq_value abbrev summary description)} = @fields[1,5..8,11..13]; |
|---|
| | 72 | $param{created} =~ s/^ts\.//; |
|---|
| | 73 | $param{time_zone} = $this->{time_zone} || 'Asia/Tokyo'; |
|---|
| | 74 | |
|---|
| | 75 | my $item; |
|---|
| | 76 | if (!$param{freq}) { |
|---|
| | 77 | @param{qw(start_date end_date)} = @fields[3,4]; |
|---|
| | 78 | $item = WWW::CybozuOffice6::Calendar::Event->new(%param); |
|---|
| | 79 | } else { |
|---|
| | 80 | @param{qw(start_date end_date until_date)} = @fields[2..4]; |
|---|
| | 81 | $item = WWW::CybozuOffice6::Calendar::RecurentEvent->new(%param); |
|---|
| | 82 | } |
|---|
| | 83 | |
|---|
| | 84 | next unless $item; |
|---|
| | 85 | $item->comment($line); # save the CSV line as for debug info. |
|---|
| | 86 | push @items, $item; |
|---|
| 75 | | # handle non-recurrent events |
|---|
| 76 | | sub _parse_general_event { |
|---|
| 77 | | my $this = shift; |
|---|
| 78 | | my @fields = @_; |
|---|
| 79 | | |
|---|
| 80 | | my $now = DateTime->now; |
|---|
| 81 | | my $is_full_day = 0; |
|---|
| 82 | | |
|---|
| 83 | | my $start = $this->to_datetime($fields[3], $fields[5]); |
|---|
| 84 | | my $end = $this->to_datetime($fields[4], $fields[6]); |
|---|
| | 104 | package WWW::CybozuOffice6::Calendar::Event; |
|---|
| | 105 | |
|---|
| | 106 | sub new { |
|---|
| | 107 | my $class = shift; |
|---|
| | 108 | my $self = { |
|---|
| | 109 | is_full_day => 0, |
|---|
| | 110 | modified => DateTime->now, |
|---|
| | 111 | }; |
|---|
| | 112 | bless $self, $class; |
|---|
| | 113 | return unless $self->parse(@_); |
|---|
| | 114 | $self; |
|---|
| | 115 | } |
|---|
| | 116 | |
|---|
| | 117 | sub start { shift->_accessor('start', @_) } |
|---|
| | 118 | sub end { shift->_accessor('end', @_) } |
|---|
| | 119 | sub summary { shift->_accessor('summary', @_) } |
|---|
| | 120 | sub description { shift->_accessor('description', @_) } |
|---|
| | 121 | sub created { shift->_accessor('created', @_) } |
|---|
| | 122 | sub modified { shift->_accessor('modified', @_) } |
|---|
| | 123 | sub is_full_day { shift->_accessor('is_full_day', @_) } |
|---|
| | 124 | sub comment { shift->_accessor('comment', @_) } |
|---|
| | 125 | sub _accessor { |
|---|
| | 126 | my $this = shift; |
|---|
| | 127 | my $key = shift; |
|---|
| | 128 | $this->{$key} = shift if @_; |
|---|
| | 129 | $this->{$key}; |
|---|
| | 130 | } |
|---|
| | 131 | |
|---|
| | 132 | sub parse { |
|---|
| | 133 | my($this, %param) = @_; |
|---|
| | 134 | |
|---|
| | 135 | $this->{time_zone} = $param{time_zone} || 'Asia/Tokyo'; |
|---|
| | 136 | |
|---|
| | 137 | my $start = $this->to_datetime($param{start_date}, $param{start_time}); |
|---|
| | 138 | my $end = $this->to_datetime($param{end_date}, $param{end_time}); |
|---|
| 93 | | |
|---|
| 94 | | my($created) = $fields[1] =~ m/^ts\.(\d+)$/; |
|---|
| 95 | | $created = DateTime->from_epoch(epoch => $created || 0); |
|---|
| 96 | | |
|---|
| 97 | | my $summary = $fields[11] || ''; |
|---|
| 98 | | $summary .= ': ' if $summary; |
|---|
| 99 | | $summary .= $fields[12] || ''; |
|---|
| 100 | | |
|---|
| 101 | | my $item = { |
|---|
| 102 | | start => $start, |
|---|
| 103 | | end => $end, |
|---|
| 104 | | is_full_day => $is_full_day, |
|---|
| 105 | | summary => $summary, |
|---|
| 106 | | description => $fields[13] || $summary, |
|---|
| 107 | | created => $created, |
|---|
| 108 | | modified => $now, |
|---|
| 109 | | }; |
|---|
| 110 | | } |
|---|
| 111 | | |
|---|
| 112 | | # handle recurrent events |
|---|
| 113 | | our %FREQUENCY = ( y => 'YEARLY', m => 'MONTHLY', w => 'WEEKLY', |
|---|
| 114 | | d => 'DAILY', n => 'WEEKDAYS' ); |
|---|
| 115 | | sub _parse_recurrent_event { |
|---|
| 116 | | my $this = shift; |
|---|
| 117 | | my @fields = @_; |
|---|
| 118 | | |
|---|
| 119 | | # arrange for _parse_general_event |
|---|
| 120 | | my @f = @fields; |
|---|
| 121 | | $f[4] = $f[3]; |
|---|
| 122 | | $f[3] = $f[2]; |
|---|
| 123 | | my $item = $this->_parse_general_event(@f); |
|---|
| 124 | | |
|---|
| 125 | | # frequency |
|---|
| 126 | | my $freq = $fields[7]; |
|---|
| 127 | | if ($freq && exists $FREQUENCY{$freq}) { |
|---|
| 128 | | $item->{frequency} = $FREQUENCY{$freq}; |
|---|
| 129 | | $item->{frequency_value} = $fields[8] || 0; |
|---|
| 130 | | if ($fields[4] =~ m!^(\d+)/(\d+)/(\d+)$!) { |
|---|
| 131 | | my %args = (year => $1, month => $2, day => $3); |
|---|
| 132 | | my $until; |
|---|
| 133 | | if ($item->{is_full_day}) { |
|---|
| 134 | | $until = $this->to_datetime($fields[4], ':'); |
|---|
| 135 | | } else { |
|---|
| 136 | | $until = $item->{end}->clone->set(%args); |
|---|
| 137 | | $until->set_time_zone('UTC'); # timezone must be UTC |
|---|
| 138 | | } |
|---|
| 139 | | $item->{until} = $until; |
|---|
| 140 | | } |
|---|
| 141 | | } |
|---|
| 142 | | |
|---|
| 143 | | $item; |
|---|
| 144 | | } |
|---|
| 145 | | |
|---|
| | 150 | $this->{start} = $start; |
|---|
| | 151 | $this->{end} = $end; |
|---|
| | 152 | |
|---|
| | 153 | $this->{created} = DateTime->from_epoch(epoch => $param{created} || 0); |
|---|
| | 154 | |
|---|
| | 155 | my $summary = ($param{abbrev} ? $param{abbrev} . ': ' : '') . $param{summary}; |
|---|
| | 156 | $this->{summary} = $summary; |
|---|
| | 157 | $this->{description} = $param{description} || $summary; |
|---|
| | 158 | 1; |
|---|
| | 159 | } |
|---|
| | 160 | |
|---|
| | 161 | # convert (ymd, hms) pair to a DateTime object (timezone: localtime) |
|---|
| | 181 | } |
|---|
| | 182 | |
|---|
| | 183 | package WWW::CybozuOffice6::Calendar::RecurrentEvent; |
|---|
| | 184 | |
|---|
| | 185 | @WWW::CybozuOffice6::Calendar::RecurrentEvent::ISA = qw( WWW::CybozuOffice6::Calendar::Event ); |
|---|
| | 186 | |
|---|
| | 187 | sub frequency { shift->_accessor('frequency', @_) } |
|---|
| | 188 | sub frequency_value { shift->_accessor('frequency_value', @_) } |
|---|
| | 189 | |
|---|
| | 190 | our %FREQUENCY = ( y => 'YEARLY', m => 'MONTHLY', w => 'WEEKLY', |
|---|
| | 191 | d => 'DAILY', n => 'WEEKDAYS' ); |
|---|
| | 192 | sub parse { |
|---|
| | 193 | my($this, %param) = @_; |
|---|
| | 194 | $this->SUPER::parse(%param); |
|---|
| | 195 | |
|---|
| | 196 | # frequency |
|---|
| | 197 | my $freq = $param{freq}; |
|---|
| | 198 | return unless $freq && exists $FREQUENCY{$freq}; |
|---|
| | 199 | |
|---|
| | 200 | $this->{frequency} = $FREQUENCY{$freq}; |
|---|
| | 201 | $this->{frequency_value} = $param{freq_value} || 0; |
|---|
| | 202 | |
|---|
| | 203 | if ($param{until_date} =~ m!^(\d+)/(\d+)/(\d+)$!) { |
|---|
| | 204 | my %args = (year => $1, month => $2, day => $3); |
|---|
| | 205 | my $until; |
|---|
| | 206 | if ($this->{is_full_day}) { |
|---|
| | 207 | $until = $this->to_datetime($param{until_date}, ':'); |
|---|
| | 208 | } else { |
|---|
| | 209 | $until = $this->{end}->clone->set(%args); |
|---|
| | 210 | $until->set_time_zone('UTC'); # timezone must be UTC |
|---|
| | 211 | } |
|---|
| | 212 | $this->{until} = $until; |
|---|
| | 213 | } |
|---|
| | 214 | 1; |
|---|