import torrus 1.0.9
[freeside.git] / rt / lib / RTx / Calendar.pm
1 package RTx::Calendar;
2
3 use strict;
4 use base qw( Exporter );
5 use DateTime;
6 use DateTime::Set;
7
8 our $VERSION = "0.07";
9
10 our @EXPORT_OK = qw( FirstDay LastDay );
11
12 sub FirstDay {
13     my ($year, $month, $matchday) = @_;
14     my $set = DateTime::Set->from_recurrence(
15         next => sub { $_[0]->truncate( to => 'day' )->subtract( days => 1 ) }
16     );
17
18     my $day = DateTime->new( year => $year, month => $month );
19
20     $day = $set->next($day) while $day->day_of_week != $matchday;
21     $day;
22
23 }
24
25 sub LastDay {
26     my ($year, $month, $matchday) = @_;
27     my $set = DateTime::Set->from_recurrence(
28         next => sub { $_[0]->truncate( to => 'day' )->add( days => 1 ) }
29     );
30
31     my $day = DateTime->last_day_of_month( year => $year, month => $month );
32
33     $day = $set->next($day) while $day->day_of_week != $matchday;
34     $day;
35 }
36
37 # we can't use RT::Date::Date because it uses gmtime
38 # and we need localtime
39 sub LocalDate {
40   my $ts = shift;
41   my ($d,$m,$y) = (localtime($ts))[3..5];
42   sprintf "%4d-%02d-%02d", ($y + 1900), ++$m, $d;
43 }
44
45 sub DatesClauses {
46     my ($Dates, $begin, $end) = @_;
47
48     my $clauses = "";
49
50     my @DateClauses = map {
51         "($_ >= '" . $begin . "' AND $_ <= '" . $end . "')"
52     } @$Dates;
53     $clauses  .= " AND " . " ( " . join(" OR ", @DateClauses) . " ) "
54         if @DateClauses;
55
56     return $clauses
57 }
58
59 sub FindTickets {
60     my ($CurrentUser, $Query, $Dates, $begin, $end) = @_;
61
62     $Query .= DatesClauses($Dates, $begin, $end)
63         if $begin and $end;
64
65     my $Tickets = RT::Tickets->new($CurrentUser);
66     $Tickets->FromSQL($Query);
67
68     my %Tickets;
69     my %AlreadySeen;
70
71     while ( my $Ticket = $Tickets->Next()) {
72
73         # How to find the LastContacted date ?
74         for my $Date (@$Dates) {
75             my $DateObj = $Date . "Obj";
76             push @{ $Tickets{ LocalDate($Ticket->$DateObj->Unix) } }, $Ticket
77                 # if reminder, check it's refering to a ticket
78                 unless ($Ticket->Type eq 'reminder' and not $Ticket->RefersTo->First)
79                     or $AlreadySeen{  LocalDate($Ticket->$DateObj->Unix) }{ $Ticket }++;
80         }
81     }
82     return %Tickets;
83 }
84
85
86 # Take a user object and return the search with Description "calendar" if it exists
87
88 sub SearchDefaultCalendar {
89     my $CurrentUser = shift;
90     my $Description = "calendar";
91
92     # I'm quite sure the loop isn't usefull but...
93     my @Objects = $CurrentUser->UserObj;
94     for my $object (@Objects) {
95         next unless ref($object) eq 'RT::User' && $object->id == $CurrentUser->Id;
96         my @searches = $object->Attributes->Named('SavedSearch');
97         for my $search (@searches) {
98             next if ($search->SubValue('SearchType')
99                          && $search->SubValue('SearchType') ne 'Ticket');
100
101             return $search
102                 if "calendar" eq $search->Description;
103         }
104     }
105 }
106
107
108 1;
109
110 __END__
111
112 =head1 NAME
113
114 RTx::Calendar - Calendar for RT due tasks
115
116 =head1 VERSION
117
118 This document describes version 0.07 of RTx::Calendar
119
120 =head1 DESCRIPTION
121
122 This RT extension provides a calendar view for your tickets and your
123 reminders so you see when is your next due ticket. You can find it in
124 the menu Search->Calendar.
125
126 There's a portlet to put on your home page (see Prefs/MyRT.html)
127
128 You can also enable ics (ICal) feeds for your default calendar and all
129 your private searches in Prefs/Calendar.html. Authentication is magic
130 number based so that you can give those feeds to other people.
131
132 You can find screenshots on
133 http://gaspard.mine.nu/dotclear/index.php?tag/rtx-calendar
134
135 =head1 INSTALLATION
136
137 If you upgrade from 0.02, see next part before.
138
139 You need to install those three modules :
140
141   * Date::ICal
142   * Data::ICal
143   * DateTime::Set
144
145 Install it like a standard perl module
146
147  perl Makefile.PL
148  make
149  make install
150
151 If your RT is not in the default path (/opt/rt3) you must set RTHOME
152 before doing the Makefile.PL
153
154 =head1 CONFIGURATION
155
156 =head2 Base configuration
157
158 In RT 3.8 and later, to enable calendar plugin, you must add something
159 like that in your etc/RT_SiteConfig.pm :
160
161   Set(@Plugins,(qw(RTx::Calendar)));
162
163 To use MyCalendar portlet you must add MyCalendar to
164 $HomepageComponents in etc/RT_SiteConfig.pm like that :
165
166   Set($HomepageComponents, [qw(QuickCreate Quicksearch MyCalendar
167      MyAdminQueues MySupportQueues MyReminders RefreshHomepage)]);
168
169 To enable private searches ICal feeds, you need to give
170 CreateSavedSearch and LoadSavedSearch rights to your users.
171
172 =head2 Display configuration
173
174 You can show the owner in each day box by adding this line to your
175 etc/RT_SiteConfig.pm :
176
177     Set($CalendarDisplayOwner, 1);
178
179 You can change which fields show up in the popup display when you
180 mouse over a date in etc/RT_SiteConfig.pm :
181
182     @CalendarPopupFields = ('Status', 'OwnerObj->Name', 'DueObj->ISO');
183
184 =head2 ICAL feed configuration
185
186 By default, tickets are todo and reminders event. You can change this
187 by setting $RT::ICalTicketType and $RT::ICalReminderType in etc/RT_SiteConfig.pm :
188
189   Set($ICalTicketType,   "Data::ICal::Entry::Event");
190   Set($ICalReminderType ,"Data::ICal::Entry::Todo");
191
192 =head1 USAGE
193
194 A small help section is available in /Prefs/Calendar.html
195
196 =head1 UPGRADE FROM 0.02
197
198 As I've change directory structure, if you upgrade from 0.02 you need
199 to delete old files manually. Go in RTHOME/share/html (by default
200 /opt/rt3/share/html) and delete those files :
201
202   rm -rf Callbacks/RTx-Calendar
203   rm Tools/Calendar.html
204
205 RTx-Calendar may work without this but it's not very clean.
206
207 =head1 BUGS
208
209 =over
210
211 =item *
212 compatible only with RT 3.6 for the moment. If someone need
213 compatibility with 3.4 I can work on this. And I will work on 3.7
214 compatibility later.
215
216 =back
217
218 =head1 AUTHORS
219
220 Nicolas Chuche E<lt>nchuche@barna.beE<gt>
221
222 Idea borrowed from redmine's calendar (Thanks Jean-Philippe).
223
224 =head1 COPYRIGHT
225
226 Copyright 2007 by Nicolas Chuche E<lt>nchuche@barna.beE<gt>
227
228 This program is free software; you can redistribute it and/or 
229 modify it under the same terms as Perl itself.
230
231 See L<http://www.perl.com/perl/misc/Artistic.html>
232
233 =cut