4 use base qw( Exporter );
10 RT->AddStyleSheets('calendar.css')
11 if RT->can('AddStyleSheets');
13 our @EXPORT_OK = qw( FirstDay LastDay );
16 my ($year, $month, $matchday) = @_;
17 my $set = DateTime::Set->from_recurrence(
18 next => sub { $_[0]->truncate( to => 'day' )->subtract( days => 1 ) }
21 my $day = DateTime->new( year => $year, month => $month );
23 $day = $set->next($day) while $day->day_of_week != $matchday;
29 my ($year, $month, $matchday) = @_;
30 my $set = DateTime::Set->from_recurrence(
31 next => sub { $_[0]->truncate( to => 'day' )->add( days => 1 ) }
34 my $day = DateTime->last_day_of_month( year => $year, month => $month );
36 $day = $set->next($day) while $day->day_of_week != $matchday;
40 # we can't use RT::Date::Date because it uses gmtime
41 # and we need localtime
44 my ($d,$m,$y) = (localtime($ts))[3..5];
45 sprintf "%4d-%02d-%02d", ($y + 1900), ++$m, $d;
49 my ($Dates, $begin, $end) = @_;
53 my @DateClauses = map {
54 "($_ >= '" . $begin . " 00:00:00' AND $_ <= '" . $end . " 23:59:59')"
56 $clauses .= " AND " . " ( " . join(" OR ", @DateClauses) . " ) "
63 my ($CurrentUser, $Query, $Dates, $begin, $end) = @_;
65 $Query .= DatesClauses($Dates, $begin, $end)
68 my $Tickets = RT::Tickets->new($CurrentUser);
69 $Tickets->FromSQL($Query);
74 while ( my $Ticket = $Tickets->Next()) {
76 # How to find the LastContacted date ?
77 for my $Date (@$Dates) {
78 my $DateObj = $Date . "Obj";
79 push @{ $Tickets{ LocalDate($Ticket->$DateObj->Unix) } }, $Ticket
80 # if reminder, check it's refering to a ticket
81 unless ($Ticket->Type eq 'reminder' and not $Ticket->RefersTo->First)
82 or $AlreadySeen{ LocalDate($Ticket->$DateObj->Unix) }{ $Ticket }++;
89 # Take a user object and return the search with Description "calendar" if it exists
91 sub SearchDefaultCalendar {
92 my $CurrentUser = shift;
93 my $Description = "calendar";
95 # I'm quite sure the loop isn't usefull but...
96 my @Objects = $CurrentUser->UserObj;
97 for my $object (@Objects) {
98 next unless ref($object) eq 'RT::User' && $object->id == $CurrentUser->Id;
99 my @searches = $object->Attributes->Named('SavedSearch');
100 for my $search (@searches) {
101 next if ($search->SubValue('SearchType')
102 && $search->SubValue('SearchType') ne 'Ticket');
105 if "calendar" eq $search->Description;
110 package RT::Interface::Web::Menu;
112 # we should get an add_after method in 4.0.6 (hopefully), but until then
113 # shim this in so I don't copy the code.
114 unless (RT::Interface::Web::Menu->can('add_after')) {
115 *RT::Interface::Web::Menu::add_after = sub {
117 my $parent = $self->parent;
119 for my $contemporary ($parent->children) {
120 if ( $contemporary->key eq $self->key ) {
121 $sort_order = $contemporary->sort_order + 1;
125 $contemporary->sort_order( $contemporary->sort_order + 1 );
128 $parent->child( @_, sort_order => $sort_order );
139 RTx::Calendar - Calendar for RT due tasks
143 This RT extension provides a calendar view for your tickets and your
144 reminders so you see when is your next due ticket. You can find it in
145 the menu Search->Calendar.
147 There's a portlet to put on your home page (see Prefs/MyRT.html)
149 You can also enable ics (ICal) feeds for your default calendar and all
150 your private searches in Prefs/Calendar.html. Authentication is magic
151 number based so that you can give those feeds to other people.
155 If you upgrade from 0.02, see next part before.
157 You need to install those three modules :
163 Install it like a standard perl module
169 If your RT is not in the default path (/opt/rt3) you must set RTHOME
170 before doing the Makefile.PL
174 =head2 Base configuration
176 In RT 3.8 and later, to enable calendar plugin, you must add something
177 like that in your etc/RT_SiteConfig.pm :
179 Set(@Plugins,(qw(RTx::Calendar)));
181 To use MyCalendar portlet you must add MyCalendar to
182 $HomepageComponents in etc/RT_SiteConfig.pm like that :
184 Set($HomepageComponents, [qw(QuickCreate Quicksearch MyCalendar
185 MyAdminQueues MySupportQueues MyReminders RefreshHomepage)]);
187 To enable private searches ICal feeds, you need to give
188 CreateSavedSearch and LoadSavedSearch rights to your users.
190 =head2 Display configuration
192 You can show the owner in each day box by adding this line to your
193 etc/RT_SiteConfig.pm :
195 Set($CalendarDisplayOwner, 1);
197 You can change which fields show up in the popup display when you
198 mouse over a date in etc/RT_SiteConfig.pm :
200 @CalendarPopupFields = ('Status', 'OwnerObj->Name', 'DueObj->ISO');
202 =head2 ICAL feed configuration
204 By default, tickets are todo and reminders event. You can change this
205 by setting $RT::ICalTicketType and $RT::ICalReminderType in etc/RT_SiteConfig.pm :
207 Set($ICalTicketType, "Data::ICal::Entry::Event");
208 Set($ICalReminderType ,"Data::ICal::Entry::Todo");
212 A small help section is available in /Prefs/Calendar.html
214 =head1 UPGRADE FROM 0.02
216 As I've change directory structure, if you upgrade from 0.02 you need
217 to delete old files manually. Go in RTHOME/share/html (by default
218 /opt/rt3/share/html) and delete those files :
220 rm -rf Callbacks/RTx-Calendar
221 rm Tools/Calendar.html
223 RTx-Calendar may work without this but it's not very clean.
227 All bugs should be reported via
228 L<http://rt.cpan.org/Public/Dist/Display.html?Name=RTx-Calendar>
229 or L<bug-RTx-Calendar@rt.cpan.org>.
233 Best Practical Solutions
235 Nicolas Chuche E<lt>nchuche@barna.beE<gt>
237 Idea borrowed from redmine's calendar (Thanks Jean-Philippe).
241 Copyright 2007-2009 by Nicolas Chuche E<lt>nchuche@barna.beE<gt>
243 Copyright 2010-2012 by Best Practical Solutions.
245 This program is free software; you can redistribute it and/or
246 modify it under the same terms as Perl itself.
248 See L<http://www.perl.com/perl/misc/Artistic.html>