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 two modules :
162 Install it like a standard perl module
168 If your RT is not in the default path (/opt/rt3) you must set RTHOME
169 before doing the Makefile.PL
173 =head2 Base configuration
175 In RT 3.8 and later, to enable calendar plugin, you must add something
176 like that in your etc/RT_SiteConfig.pm :
178 Set(@Plugins,(qw(RTx::Calendar)));
180 To use MyCalendar portlet you must add MyCalendar to
181 $HomepageComponents in etc/RT_SiteConfig.pm like that :
183 Set($HomepageComponents, [qw(QuickCreate Quicksearch MyCalendar
184 MyAdminQueues MySupportQueues MyReminders RefreshHomepage)]);
186 To enable private searches ICal feeds, you need to give
187 CreateSavedSearch and LoadSavedSearch rights to your users.
189 =head2 Display configuration
191 You can show the owner in each day box by adding this line to your
192 etc/RT_SiteConfig.pm :
194 Set($CalendarDisplayOwner, 1);
196 You can change which fields show up in the popup display when you
197 mouse over a date in etc/RT_SiteConfig.pm :
199 @CalendarPopupFields = ('Status', 'OwnerObj->Name', 'DueObj->ISO');
201 =head2 ICAL feed configuration
203 By default, tickets are todo and reminders event. You can change this
204 by setting $RT::ICalTicketType and $RT::ICalReminderType in etc/RT_SiteConfig.pm :
206 Set($ICalTicketType, "Data::ICal::Entry::Event");
207 Set($ICalReminderType ,"Data::ICal::Entry::Todo");
211 A small help section is available in /Prefs/Calendar.html
213 =head1 UPGRADE FROM 0.02
215 As I've change directory structure, if you upgrade from 0.02 you need
216 to delete old files manually. Go in RTHOME/share/html (by default
217 /opt/rt3/share/html) and delete those files :
219 rm -rf Callbacks/RTx-Calendar
220 rm Tools/Calendar.html
222 RTx-Calendar may work without this but it's not very clean.
226 All bugs should be reported via
227 L<http://rt.cpan.org/Public/Dist/Display.html?Name=RTx-Calendar>
228 or L<bug-RTx-Calendar@rt.cpan.org>.
232 Best Practical Solutions
234 Nicolas Chuche E<lt>nchuche@barna.beE<gt>
236 Idea borrowed from redmine's calendar (Thanks Jean-Philippe).
240 Copyright 2007-2009 by Nicolas Chuche E<lt>nchuche@barna.beE<gt>
242 Copyright 2010-2012 by Best Practical Solutions.
244 This program is free software; you can redistribute it and/or
245 modify it under the same terms as Perl itself.
247 See L<http://www.perl.com/perl/misc/Artistic.html>