1package RTx::Calendar;
2
3use strict;
4use DateTime;
5use DateTime::Set;
6
7our $VERSION = "1.03";
8
9RT->AddStyleSheets('calendar.css');
10
11sub FirstDay {
12    my ($year, $month, $matchday) = @_;
13    my $set = DateTime::Set->from_recurrence(
14	next => sub { $_[0]->truncate( to => 'day' )->subtract( days => 1 ) }
15    );
16
17    my $day = DateTime->new( year => $year, month => $month );
18
19    $day = $set->next($day) while $day->day_of_week != $matchday;
20    $day;
21
22}
23
24sub LastDay {
25    my ($year, $month, $matchday) = @_;
26    my $set = DateTime::Set->from_recurrence(
27	next => sub { $_[0]->truncate( to => 'day' )->add( days => 1 ) }
28    );
29
30    my $day = DateTime->last_day_of_month( year => $year, month => $month );
31
32    $day = $set->next($day) while $day->day_of_week != $matchday;
33    $day;
34}
35
36# we can't use RT::Date::Date because it uses gmtime
37# and we need localtime
38sub LocalDate {
39  my $ts = shift;
40  my ($d,$m,$y) = (localtime($ts))[3..5];
41  sprintf "%4d-%02d-%02d", ($y + 1900), ++$m, $d;
42}
43
44sub DatesClauses {
45    my ($Dates, $begin, $end) = @_;
46
47    my $clauses = "";
48
49    my @DateClauses = map {
50	"($_ >= '" . $begin . " 00:00:00' AND $_ <= '" . $end . " 23:59:59')"
51    } @$Dates;
52    $clauses  .= " AND " . " ( " . join(" OR ", @DateClauses) . " ) "
53	if @DateClauses;
54
55    return $clauses
56}
57
58sub FindTickets {
59    my ($CurrentUser, $Query, $Dates, $begin, $end) = @_;
60
61    $Query .= DatesClauses($Dates, $begin, $end)
62	if $begin and $end;
63
64    my $Tickets = RT::Tickets->new($CurrentUser);
65    $Tickets->FromSQL($Query);
66
67    my %Tickets;
68    my %AlreadySeen;
69
70    while ( my $Ticket = $Tickets->Next()) {
71
72	# How to find the LastContacted date ?
73	for my $Date (@$Dates) {
74	    my $DateObj = $Date . "Obj";
75	    push @{ $Tickets{ LocalDate($Ticket->$DateObj->Unix) } }, $Ticket
76		# if reminder, check it's refering to a ticket
77		unless ($Ticket->Type eq 'reminder' and not $Ticket->RefersTo->First)
78		    or $AlreadySeen{  LocalDate($Ticket->$DateObj->Unix) }{ $Ticket }++;
79	}
80    }
81    return %Tickets;
82}
83
84#
85# Take a user object and return the search with Description "calendar" if it exists
86#
87sub SearchDefaultCalendar {
88    my $CurrentUser = shift;
89    my $Description = "calendar";
90
91    # I'm quite sure the loop isn't usefull but...
92    my @Objects = $CurrentUser->UserObj;
93    for my $object (@Objects) {
94	next unless ref($object) eq 'RT::User' && $object->id == $CurrentUser->Id;
95	my @searches = $object->Attributes->Named('SavedSearch');
96	for my $search (@searches) {
97	    next if ($search->SubValue('SearchType')
98			 && $search->SubValue('SearchType') ne 'Ticket');
99
100	    return $search
101		if "calendar" eq $search->Description;
102	}
103    }
104}
105
1061;
107
108__END__
109
110=head1 NAME
111
112RTx::Calendar - Calendar for RT due dates
113
114=head1 DESCRIPTION
115
116This RT extension provides a calendar view for your tickets and your
117reminders so you see when is your next due ticket. You can find it in
118ticket search sub navigation menu.
119
120Date fields in the search results are displayed/used in the calendar,
121for example if you have a ticket with a due date, it won't be displayed on
122that date unless the Due field is included in the search result format.
123
124There's a portlet to put on your home page (see Prefs/MyRT.html), see the
125CONFIGURATION section below for details on adding it.
126
127=head1 RT VERSION
128
129Works with RT 4.2, 4.4, 5.0
130
131=head1 INSTALLATION
132
133=over
134
135=item C<perl Makefile.PL>
136
137=item C<make>
138
139=item C<make install>
140
141May need root permissions
142
143=item patch RT
144
145Apply for versions prior to 4.4.2:
146
147    patch -p1 -d /path/to/rt < etc/tabs_privileged_callback.patch
148
149=item Edit your F</opt/rt5/etc/RT_SiteConfig.pm>
150
151Add this line:
152
153    Plugin('RTx::Calendar');
154
155=item Clear your mason cache
156
157    rm -rf /opt/rt5/var/mason_data/obj
158
159=item Restart your webserver
160
161=back
162
163=head1 CONFIGURATION
164
165=head2 Base configuration
166
167To use the C<MyCalendar> portlet, you must add C<MyCalendar> to
168C<$HomepageComponents> in F<etc/RT_SiteConfig.pm>:
169
170  Set($HomepageComponents, [qw(QuickCreate Quicksearch MyCalendar
171     MyAdminQueues MySupportQueues MyReminders RefreshHomepage)]);
172
173=head2 Display configuration
174
175You can show the owner in each day box by adding this line to your
176F<etc/RT_SiteConfig.pm>:
177
178    Set($CalendarDisplayOwner, 1);
179
180You can change which fields show up in the popup display when you
181mouse over a date in F<etc/RT_SiteConfig.pm>:
182
183    Set(@CalendarPopupFields, ('Status', 'OwnerObj->Name', 'DueObj->ISO'));
184
185=head1 USAGE
186
187A small help section is available in /Search/Calendar.html
188
189=head1 AUTHOR
190
191Best Practical Solutions, LLC E<lt>modules@bestpractical.comE<gt>
192
193Originally written by Nicolas Chuche E<lt>nchuche@barna.beE<gt>
194
195=head1 BUGS
196
197All bugs should be reported via email to
198
199    L<bug-RTx-Calendar@rt.cpan.org|mailto:bug-RTx-Calendar@rt.cpan.org>
200
201or via the web at
202
203    L<rt.cpan.org|http://rt.cpan.org/Public/Dist/Display.html?Name=RTx-Calendar>.
204
205=head1 LICENSE AND COPYRIGHT
206
207This software is Copyright (c) 2010-2020 by Best Practical Solutions
208
209Copyright 2007-2009 by Nicolas Chuche
210
211This is free software, licensed under:
212
213  The GNU General Public License, Version 2, June 1991
214
215=cut
216