@@ -1,78 +1,82 @@
-Changes for 0.20
- * Packaging fixes only (0.19 failed to update CHANGES)
+1.00
+ - Packaging and documentation updates
+ - Drop ical support, as it is in core RT
+ - Add documentation to Calendar.html
-Changes for 0.19
- * Fix double-encoding of previous/next month chevrons
+0.20
+ - Packaging fixes only (0.19 failed to update CHANGES)
-Changes for 0.18
- * RT 4.2 compatibility
- * UI updates from Ivan Kohler
+0.19
+ - Fix double-encoding of previous/next month chevrons
-Changes for 0.17
- * Re-released after resolving PAUSE permissions; no changes since 0.16
+0.18
+ - RT 4.2 compatibility
+ - UI updates from Ivan Kohler
-Changes for 0.16 — Never indexed by PAUSE
- * Remove dependency on Date::ICal and use RT::Date's support instead
+0.17
+ - Re-released after resolving PAUSE permissions; no changes since 0.16
-Changes for 0.15
- * Switch to Digest::SHA from Digest::SHA1 to appease Debian
+0.16 Never indexed by PAUSE
+ - Remove dependency on Date::ICal and use RT::Date's support instead
-Changes for 0.14
- * Guard the modern stylesheets call on older RTs
+0.15
+ - Switch to Digest::SHA from Digest::SHA1 to appease Debian
-Changes for 0.13
- * Serve CSS the modern way on recent RT's
- * Namespace our CSS to avoid styling the RT core UI
+0.14
+ - Guard the modern stylesheets call on older RTs
-Changes for 0.12
- * Copyright updates
+0.13
+ - Serve CSS the modern way on recent RT's
+ - Namespace our CSS to avoid styling the RT core UI
-Changes for 0.11
- * fixes for characters that were breaking 3.8
+0.12
+ - Copyright updates
-Changes for 0.10
- * packaging tweak
+0.11
+ - fixes for characters that were breaking 3.8
-Changes for 0.09
- * RT 4 compatibility
+0.10
+ - packaging tweak
-Changes for 0.08
+0.09
+ - RT 4 compatibility
- * make sure the last date of a search is displayed (Shawn M Moore) [rt.cpan.org #63469]
+0.08
+ - make sure the last date of a search is displayed (Shawn M Moore)
+ [rt.cpan.org #63469]
-Changes for 0.07
+0.07
+ - add documentation on how to enable plugin in rt 3.8 and later
+ - add configuration to show owner in calendar (Shawn M Moore)
+ - make the popup display fields configurable (Shawn M Moore)
+ - tickets and reminders types (todo/event) are configurable in ical feed
- * add documentation on how to enable plugin in rt 3.8 and later
- * add configuration to show owner in calendar (Shawn M Moore)
- * make the popup display fields configurable (Shawn M Moore)
- * tickets and reminders types (todo/event) are configurable in ical feed
+0.06
+ - rt 3.8 compatibility
-Changes for 0.06
+0.05
+ - fix a bug in ics feeds when showing reminders
+ - use Module::Install::RTx 0.21
- * rt 3.8 compatibility
+0.04
+ - should work with rt 3.6.0 and seems to work with 3.7.2
+ - display Starts date by default
+ - you can use Format to display dates you want (Created, Started, Due,
+ Starts, ...)
+ - if a saved search is named "calendar", use it for the default
+ Calendar.html and for the portlet
+ - fix a bug in Prefs
-Changes for 0.05
- * fix a bug in ics feeds when showing reminders
- * use Module::Install::RTx 0.21
+0.03
+ - now uses Query Builder to find tickets
+ - ics (ICal) feeds available for each personal search with magic number
+ authentication method
+ - default calendars and feeds show reminders
+ - Calendar.html move in Search
+ - MyCalendar links to your own tickets and Nobody's tickets for the
+ current month
+ - fix a problem with localtime and gmtime
-Changes for 0.04
+0.02
+ - First release
- * should work with rt 3.6.0 and seems to work with 3.7.2
- * display Starts date by default
- * you can use Format to display dates you want (Created, Started, Due, Starts, ...)
- * if a saved search is named "calendar", use it for the default Calendar.html and for the portlet
- * fix a bug in Prefs
-
-Changes for 0.03
-
- * now uses Query Builder to find tickets
- * ics (ICal) feeds available for each personal search with magic number authentication method
- * default calendars and feeds show reminders
- * Calendar.html move in Search
- * MyCalendar links to your own tickets and Nobody's tickets for the
- current month
- * fix a problem with localtime and gmtime
-
-Changes for 0.02
-
- * First release
@@ -1,23 +1,22 @@
CHANGES
html/Callbacks/RTx-Calendar/Elements/Tabs/Privileged
-html/Callbacks/RTx-Calendar/Ticket/Elements/Tabs/Default
-html/Callbacks/RTx-Calendar/User/Elements/Tabs/Default
html/Elements/CalendarEvent
html/Elements/MyCalendar
-html/NoAuth/Calendar/dhandler
-html/Prefs/Calendar.html
-html/Prefs/Elements/CalendarFeed
html/Search/Calendar.html
inc/Module/Install.pm
inc/Module/Install/Base.pm
inc/Module/Install/Can.pm
inc/Module/Install/Fetch.pm
+inc/Module/Install/Include.pm
inc/Module/Install/Makefile.pm
inc/Module/Install/Metadata.pm
inc/Module/Install/ReadmeFromPod.pm
inc/Module/Install/RTx.pm
+inc/Module/Install/RTx/Runtime.pm
inc/Module/Install/Win32.pm
inc/Module/Install/WriteAll.pm
+inc/unicore/Name.pm
+inc/YAML/Tiny.pm
lib/RTx/Calendar.pm
Makefile.PL
MANIFEST This list of files
@@ -34,3 +33,4 @@ static/images/starts.png
static/images/starts_due.png
static/images/updated.png
TODO
+SIGNATURE Public-key signature (added by MakeMaker)
@@ -1,16 +1,15 @@
---
-abstract: 'Calendar view'
+abstract: 'Calendar for RT due dates'
author:
- - 'Best Practical Solutions'
- - 'Nicolas Chuche <nchuche@barna.be>'
+ - 'Best Practical Solutions, LLC <modules@bestpractical.com>'
build_requires:
- ExtUtils::MakeMaker: 6.36
+ ExtUtils::MakeMaker: 6.59
configure_requires:
- ExtUtils::MakeMaker: 6.36
+ ExtUtils::MakeMaker: 6.59
distribution_type: module
dynamic_config: 1
-generated_by: 'Module::Install version 1.08'
-license: perl
+generated_by: 'Module::Install version 1.12'
+license: gpl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: 1.4
@@ -20,13 +19,12 @@ no_index:
- html
- inc
- static
- package:
- - RT::Interface::Web::Menu
requires:
- Data::ICal: 0
DateTime: 0
DateTime::Set: 0
- Digest::SHA: 0
+ perl: 5.8.3
resources:
- license: http://dev.perl.org/licenses/
-version: '0.20'
+ license: http://opensource.org/licenses/gpl-license.php
+version: '1.00'
+x_module_install_rtx_version: '0.36'
+x_requires_rt: 4.0.9
@@ -1,16 +1,11 @@
use inc::Module::Install;
RTx('RTx-Calendar');
-author('Nicolas Chuche <nchuche@barna.be>');
-abstract('Calendar view');
-license('perl');
-readme_from('lib/RTx/Calendar.pm');
-requires 'DateTime' => 0;
-requires 'DateTime::Set' => 0;
-requires 'Data::ICal' => 0;
-requires 'Digest::SHA';
+requires 'DateTime';
+requires 'DateTime::Set';
-no_index(package => 'RT::Interface::Web::Menu');
+requires_rt '4.0.9';
+sign();
WriteAll();
@@ -1,5 +1,5 @@
NAME
- RTx::Calendar - Calendar for RT due tasks
+ RTx::Calendar - Calendar for RT due dates
DESCRIPTION
This RT extension provides a calendar view for your tickets and your
@@ -8,94 +8,70 @@ DESCRIPTION
There's a portlet to put on your home page (see Prefs/MyRT.html)
- You can also enable ics (ICal) feeds for your default calendar and all
- your private searches in Prefs/Calendar.html. Authentication is magic
- number based so that you can give those feeds to other people.
-
INSTALLATION
- If you upgrade from 0.02, see next part before.
+ perl Makefile.PL
+ make
+ make install
+ May need root permissions
- You need to install those two modules :
+ Edit your /opt/rt4/etc/RT_SiteConfig.pm
+ If you are using RT 4.2 or greater, add this line:
- * Data::ICal
- * DateTime::Set
+ Plugin('RTx::Calendar');
- Install it like a standard perl module
+ For RT 4.0, add this line:
- perl Makefile.PL
- make
- make install
+ Set(@Plugins, qw(RTx::Calendar));
- If your RT is not in the default path (/opt/rt3) you must set RTHOME
- before doing the Makefile.PL
+ or add RTx::Calendar to your existing @Plugins line.
-CONFIGURATION
- Base configuration
- In RT 3.8 and later, to enable calendar plugin, you must add something
- like that in your etc/RT_SiteConfig.pm :
+ Clear your mason cache
+ rm -rf /opt/rt4/var/mason_data/obj
- Set(@Plugins,(qw(RTx::Calendar)));
+ Restart your webserver
- To use MyCalendar portlet you must add MyCalendar to $HomepageComponents
- in etc/RT_SiteConfig.pm like that :
+CONFIGURATION
+ Base configuration
+ To use the MyCalendar portlet, you must add MyCalendar to
+ $HomepageComponents in etc/RT_SiteConfig.pm:
Set($HomepageComponents, [qw(QuickCreate Quicksearch MyCalendar
MyAdminQueues MySupportQueues MyReminders RefreshHomepage)]);
- To enable private searches ICal feeds, you need to give
- CreateSavedSearch and LoadSavedSearch rights to your users.
-
Display configuration
You can show the owner in each day box by adding this line to your
- etc/RT_SiteConfig.pm :
+ etc/RT_SiteConfig.pm:
Set($CalendarDisplayOwner, 1);
You can change which fields show up in the popup display when you mouse
- over a date in etc/RT_SiteConfig.pm :
-
- @CalendarPopupFields = ('Status', 'OwnerObj->Name', 'DueObj->ISO');
+ over a date in etc/RT_SiteConfig.pm:
- ICAL feed configuration
- By default, tickets are todo and reminders event. You can change this by
- setting $RT::ICalTicketType and $RT::ICalReminderType in
- etc/RT_SiteConfig.pm :
-
- Set($ICalTicketType, "Data::ICal::Entry::Event");
- Set($ICalReminderType ,"Data::ICal::Entry::Todo");
+ Set(@CalendarPopupFields, ('Status', 'OwnerObj->Name', 'DueObj->ISO'));
USAGE
A small help section is available in /Prefs/Calendar.html
-UPGRADE FROM 0.02
- As I've change directory structure, if you upgrade from 0.02 you need to
- delete old files manually. Go in RTHOME/share/html (by default
- /opt/rt3/share/html) and delete those files :
-
- rm -rf Callbacks/RTx-Calendar
- rm Tools/Calendar.html
+AUTHOR
+ Best Practical Solutions, LLC <modules@bestpractical.com>
- RTx-Calendar may work without this but it's not very clean.
+ Originally written by Nicolas Chuche <nchuche@barna.be>
BUGS
- All bugs should be reported via
- <http://rt.cpan.org/Public/Dist/Display.html?Name=RTx-Calendar> or
- bug-RTx-Calendar@rt.cpan.org.
+ All bugs should be reported via email to
-AUTHORS
- Best Practical Solutions
+ L<bug-RTx-Calendar@rt.cpan.org|mailto:bug-RTx-Calendar@rt.cpan.org>
- Nicolas Chuche <nchuche@barna.be>
+ or via the web at
- Idea borrowed from redmine's calendar (Thanks Jean-Philippe).
+ L<rt.cpan.org|http://rt.cpan.org/Public/Dist/Display.html?Name=RTx-Calendar>.
-COPYRIGHT
- Copyright 2007-2009 by Nicolas Chuche <nchuche@barna.be>
+LICENSE AND COPYRIGHT
+ This software is Copyright (c) 2010-2014 by Best Practical Solutions
- Copyright 2010-2014 by Best Practical Solutions.
+ Copyright 2007-2009 by Nicolas Chuche
- This program is free software; you can redistribute it and/or modify it
- under the same terms as Perl itself.
+ This is free software, licensed under:
- See <http://www.perl.com/perl/misc/Artistic.html>
+ The GNU General Public License, Version 2, June 1991
@@ -0,0 +1,58 @@
+This file contains message digests of all files listed in MANIFEST,
+signed via the Module::Signature module, version 0.73.
+
+To verify the content in this distribution, first make sure you have
+Module::Signature installed, then type:
+
+ % cpansign -v
+
+It will check each file's integrity, as well as the signature's
+validity. If "==> Signature verified OK! <==" is not displayed,
+the distribution may already have been compromised, and you should
+not run its Makefile.PL or Build.PL.
+
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+SHA1 93b5edfdbc96aaee55700e78655e4bdb28f4a08d CHANGES
+SHA1 069fb1d0efaa32ea73dde062044517d70f6b329f MANIFEST
+SHA1 a1193dbfbe36ed50f262c026646ab88e91b6b62e META.yml
+SHA1 ec583a4b786f31a5339836bd5cd89b948d5bfd8c Makefile.PL
+SHA1 e591584e85f8ca5539df93b048c6a3b74ec9dd68 README
+SHA1 4259a8cc84588a6c02d448172e281f74c29cfca9 TODO
+SHA1 c4c2273ca8a65f5f23689f5425d2cf00fcb7d718 html/Callbacks/RTx-Calendar/Elements/Tabs/Privileged
+SHA1 550731466ec0dfafb7da6aa92381acda57f353ae html/Elements/CalendarEvent
+SHA1 cba245b1e12d22745770f9c020f4cb0923915f2a html/Elements/MyCalendar
+SHA1 3f2989981d24accd86c199540ef27fc0df0eefcd html/Search/Calendar.html
+SHA1 9b5001bfa9cf8607b3b3935284d9253e0391c9f1 inc/Module/Install.pm
+SHA1 cab0e564f9bdf658535f683aa197157e06d0dcea inc/Module/Install/Base.pm
+SHA1 a1559b5b3b40f68efbbd256f4fef85970891b3ae inc/Module/Install/Can.pm
+SHA1 f15c1ba85f6d52e70c48c64bf0752c90a4ad66f9 inc/Module/Install/Fetch.pm
+SHA1 d44d96acd20793306dd201030c688e2a7d3083ee inc/Module/Install/Include.pm
+SHA1 eb48df8bafd07c6a862126d9b274df42b4395742 inc/Module/Install/Makefile.pm
+SHA1 95c73873c6c3cb7024614c225c53863e1e90c134 inc/Module/Install/Metadata.pm
+SHA1 6e010ba20a9d0ae23d8d0ff516868c1e571c2d44 inc/Module/Install/RTx.pm
+SHA1 3fdf4c0cffdb1a2e23e5cd26bf95be553f1f9590 inc/Module/Install/RTx/Runtime.pm
+SHA1 79f5b4199f622e8b05aac266b0c39f6a85bb303f inc/Module/Install/ReadmeFromPod.pm
+SHA1 f8b2ae3386f6ba26c33408968a953d450842eade inc/Module/Install/Win32.pm
+SHA1 f302bc703d76299cff243e5b44cecd61aac27b76 inc/Module/Install/WriteAll.pm
+SHA1 4e09b598c2626e08cec2bed5e981492fa9e90967 inc/YAML/Tiny.pm
+SHA1 034d0f3a7401dae4be3eee279258181f51a4ad81 inc/unicore/Name.pm
+SHA1 6e4ad3f34fd64e02ad62d51719b6860204c63476 lib/RTx/Calendar.pm
+SHA1 b2d9bba7a2668c1406eae6ab2c10d6aecf4f6e30 static/css/calendar.css
+SHA1 bd37038a23410e1b33f52bc47c26760ead317962 static/images/created.png
+SHA1 0e33b8c5c7b5f141301edbec9983fd0d727d650d static/images/created_due.png
+SHA1 7b320f37a1253b7e0fd90abf84f5740150f3c8e9 static/images/due.png
+SHA1 e34a63899ecdf6c49fc3fdb59a9769dc7ef04427 static/images/reminder.png
+SHA1 c11078b7f675e1af5dd9237840bcf5e3fa05df9d static/images/resolved.png
+SHA1 de6e66e9dfe0f780b8a28790264835727217cca5 static/images/started.png
+SHA1 0ad059771e0d96eaaa96e90883f4a375d67bcabd static/images/starts.png
+SHA1 b23cfcce3427f706f0dc6f5ff5909ee8a1c41658 static/images/starts_due.png
+SHA1 d123dfa126e3a8535175c273419aaa38398c9b7b static/images/updated.png
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iEYEARECAAYFAlSPjDQACgkQMflWJZZAbqAilACdG6njy+zYe/+L2VvYtOdiFUCV
+0cQAnRPtIeUbgIAZJN2Sf5zVSXZYsjY8
+=i6tC
+-----END PGP SIGNATURE-----
@@ -1,6 +1,5 @@
TODO
- * add Format choice in ICal feed if asked
* add test with Test::WWW::Mechanize
* add links from the calendar page
@@ -62,12 +62,4 @@ if ( $request_path =~ qr{^/Search/} && $m->request_args->{Query} ) {
path => '/Search/Calendar.html?' . $query_string->( %{$m->request_args} ) );
}
-my $about_me = Menu->child( 'preferences' );
-my $settings = $about_me ? $about_me->child('settings') : undef;
-
-if ( $settings ) {
- $settings->child( 'calendar' => title => loc('Calendar'),
- path => '/Prefs/Calendar.html' );
-}
-
</%INIT>
@@ -1,19 +0,0 @@
-<%init>
-my $args;
-$args= "?" . $m->comp(
- '/Elements/QueryString',
- Query => $ARGS{'Query'} || $session{'CurrentSearchHash'}->{'Query'},
- Format => $ARGS{'Format'} || $session{'CurrentSearchHash'}->{'Format'},
- OrderBy => $ARGS{'OrderBy'} || $session{'CurrentSearchHash'}->{'OrderBy'},
- Order => $ARGS{'Order'} || $session{'CurrentSearchHash'}->{'Order'},
- Page => $ARGS{'Page'} || $session{'CurrentSearchHash'}->{'Page'},
- Rows => $ARGS{'Rows'},
- ) if ($ARGS{'Query'} or $session{'CurrentSearchHash'}->{'Query'});
-$args ||= '';
-
-$tabs->{'zz'} = { title =>loc("Calendar"),
- path => "Search/Calendar.html$args" };
-</%init>
-<%args>
-$tabs
-</%args>
@@ -1,9 +0,0 @@
-<%init>
- $tabs->{'z'} = { title =>loc("Calendar"),
- path => "Prefs/Calendar.html" };
-</%init>
-<%args>
-$tabs
-$current_subtab => undef
-$Searches => undef
-</%args>
@@ -1,160 +0,0 @@
-<%init>
-
-use Data::ICal;
-use Data::ICal::Entry::Todo;
-use Data::ICal::Entry::Event;
-
-$RT::ICalTicketType ||= "Data::ICal::Entry::Todo";
-$RT::ICalReminderType ||= "Data::ICal::Entry::Event";
-
-my ($UserId, $SearchId, $MagicNumber);
-my $arg = $m->dhandler_arg;
-
-if ($arg =~ m{^(\d+)@(\d+)/(.*)$}) {
- $UserId = $1;
- $SearchId = $2;
- $MagicNumber = $3;
-} elsif ($arg =~ m{^(\d+)/(.*)}) {
- $UserId = $1;
- $MagicNumber = $2;
-} else {
- Abort("Corrupted URL.");
-}
-
-my $CurrentUser = new RT::CurrentUser();
-$CurrentUser->LoadById($UserId);
-my $user = $CurrentUser->Name;
-
-# if no user, abort
-unless ($CurrentUser->Id) {
- $RT::Logger->error("No such user id $UserId from $ENV{'REMOTE_ADDR'}");
- $m->out("RT/".$RT::VERSION ." ".404 ."\n\nno such file\n");
- $m->abort;
-}
-
-# verify user has LoadSavedSearch right
-if ($SearchId and not $CurrentUser->HasRight( Right => 'LoadSavedSearch',
- Object=> $RT::System )) {
- $RT::Logger->error("not enough rights for user $user from $ENV{'REMOTE_ADDR'}");
- $m->out("RT/".$RT::VERSION ." ".404 ."\n\nno such file\n");
- $m->abort;
-}
-
-
-# if MagicNumber doesn't match the one stored in database, abort
-my $Search;
-my $ICalAttribute;
-if ($SearchId) {
- $Search = $CurrentUser->Attributes->WithId($SearchId);
- $ICalAttribute = $Search->FirstAttribute('ICalURL');
-} else {
- $ICalAttribute = $CurrentUser->UserObj->FirstAttribute('ICalURL');
-}
-
-unless ($ICalAttribute) {
- $RT::Logger->error("No such ICal feed for $user from $ENV{'REMOTE_ADDR'}");
- $m->out("RT/".$RT::VERSION ." ".404 ."\n\nno such file\n");
- $m->abort;
-}
-
-
-if ($MagicNumber ne $ICalAttribute->Content) {
- $RT::Logger->error("FAILED LOGIN for $user from $ENV{'REMOTE_ADDR'}");
- $m->out("RT/".$RT::VERSION ." ".404 ."\n\nno such file\n");
- $m->abort;
-}
-
-my $Tickets = RT::Tickets->new($CurrentUser);
-
-my $Query = "( Status = 'new' OR Status = 'open' OR Status = 'stalled')
- AND ( Owner = '" . $CurrentUser->Id ."' OR Owner = 'Nobody' )
- AND ( Type = 'reminder' OR 'Type' = 'ticket' )";
-
-$Query = $Search->SubValue('Query')
- if $Search;
-
-$Query .= " AND ( Due > '1970-01-01' OR Starts > '1970-01-01' )";
-
-$Tickets->FromSQL($Query);
-
-$Tickets->OrderBy(FIELD => 'Due', ORDER => 'ASC');
-
-my $calendar = Data::ICal->new();
-
-my ($uid) = $RT::WebURL =~ m{https?://([^:]+)};
-
-while (my $Ticket = $Tickets->Next ) {
-
- my $event;
- if ($Ticket->Type eq 'ticket') {
- $event = add_todo($Ticket, $uid);
- } else {
- $event = add_event($Ticket, $uid);
- }
- next unless $event;
- $calendar->add_entry($event);
-}
-
-my $cal = $calendar->as_string;
-
-$r->content_type('text/calendar;charset=utf-8');
-$m->clear_buffer();
-$m->out($cal);
-$m->abort;
-
-sub add_event {
- my ($Reminder, $uid) = @_;
-
- return unless defined $Reminder->RefersTo->First;
- my $Ticket = $Reminder->RefersTo->First->TargetObj;
-
- my $now = RT::Date->new( $session{'CurrentUser'} ); $now->SetToNow;
- my %event = (
- summary => $Reminder->Subject ? $Reminder->Subject : '',
- url => "${RT::WebURL}/Ticket/Display.html?id=" . $Ticket->id,
- uid => $now->iCal . "-" . $Reminder->Id . "@" . $uid,
- categories => $Ticket->QueueObj->Name,
- dtstart => $Reminder->DueObj->iCal,
- );
-
- my $event = $RT::ICalReminderType->new();
- $event->add_properties(%event);
-
- return $event;
-}
-
-sub add_todo {
- my ($Ticket, $uid) = @_;
-
- my $now = RT::Date->new( $session{'CurrentUser'} ); $now->SetToNow;
- my %vtodo = (
- summary => $Ticket->Subject ? $Ticket->Subject : '',
- dtstart => $Ticket->CreatedObj->iCal,
- url => "${RT::WebURL}/Ticket/Display.html?id=" . $Ticket->id,
- uid => $now->iCal . "-" . $Ticket->Id . "@" . $uid,
- categories => $Ticket->QueueObj->Name,
- );
-
- $vtodo{due} = $Ticket->DueObj->iCal,
- if $Ticket->DueObj;
-
- if ($Ticket->OwnerObj->Id != $RT::Nobody->Id and $Ticket->OwnerObj->EmailAddress) {
- $vtodo{organizer} = "MAILTO:" . $Ticket->OwnerObj->EmailAddress;
- $vtodo{attendee} = "MAILTO:" . $Ticket->OwnerObj->EmailAddress;
- } elsif ($Ticket->QueueObj->CommentAddress) {
- $vtodo{organizer} = "MAILTO:" . $Ticket->QueueObj->CommentAddress;
- $vtodo{attendee} = "MAILTO:" . $Ticket->QueueObj->CommentAddress;
- }
-
- $vtodo{priority} = $Ticket->Priority
- if $Ticket->Priority;
-
- my $vtodo = $RT::ICalTicketType->new();
- $vtodo->add_properties(%vtodo);
-
- return $vtodo;
-}
-
-
-
-</%init>
@@ -1,125 +0,0 @@
-<%args>
-$ChangeURL => undef
-$ResetURL => undef
-$SearchType => 'Ticket'
-$HiddenField => undef
-</%args>
-
-<& /Elements/Header, Title => $title &>
-% if ( $m->comp_exists( '/User/Elements/Tabs' ) ) {
-<& /User/Elements/Tabs,
- current_tab => 'Prefs/Calendar.html',
- Title => $title
-&>
-% } else {
-<& /Elements/Tabs &>
-% }
-
-<&| /Widgets/TitleBox, title => loc('ICal Feeds (ics)') &>
-
-<&| /Widgets/TitleBox, title => 'Help' &>
-
-<h3>displaying reminders :</h3>
-<p>If you want to have reminders in a search you need to go in the <a
-href="<%$RT::WebPath%>/Search/Edit.html"><%loc("Edit Query")%></a> tab
-of the <%loc("query builder")%> and add something like that :
-
- <pre>
- AND ( Type = 'ticket' OR Type = 'reminder' )
-</pre>
-</p>
-
-<h3>displaying other kind of dates :</h3>
-<p>By default RTx::Calendar display Due and Starts dates. You can
-select other kind of events you want with the <%loc("Display
-Columns")%> section in the <a
-href="<%$RT::WebPath%>/Search/Build.html"><%loc("Query
-Builder")%></a>. The following one will display the two latter and
-LastUpdated dates :
-
-<pre>
- '<small>__Due__</small>',
- '<small>__Starts__</small>',
- '<small>__LastUpdated__</small>'
-</pre>
-</p>
-
-<h3>changing the default query :</h3>
-<p>You can change the default Query of Calendar.html and MyCalendar
-portlet by saving a query with the name <code>calendar</code> in the
-<a href="<%$RT::WebPath%>/Search/Build.html"><%loc("Query
-Builder")%></a>.</p>
-
-</&>
-
-<& /Prefs/Elements/CalendarFeed &>
-
-% # only allow this part if
-% if ($AllowSearch) {
-
-% my $search_count;
-
-% # I'm quite sure the loop isn't usefull but...
-% my @Objects = $session{CurrentUser}->UserObj;
-% for my $object (@Objects) {
-% next unless ref($object) eq 'RT::User' && $object->id == $session{'CurrentUser'}->Id;
-% my @searches = $object->Attributes->Named('SavedSearch');
-% for my $search (@searches) {
-% next if ($search->SubValue('SearchType')
-% && $search->SubValue('SearchType') ne $SearchType);
-% $search_count++;
-<& /Prefs/Elements/CalendarFeed, Object => $object, Search => $search &>
-
-% }
-% }
-% unless ($search_count) {
-
-<&| /Widgets/TitleBox, title => loc('Private Search ICal feeds') &>
-
-You can add private ICal feeds by saving new queries in <a
-href="<%$RT::WebPath . '/Search/Build.html'%>">the Query Builder</a>
-
-</&>
-
-% }
-% } else {
-%#<&| /Widgets/TitleBox, title => loc('Private Search ICal feeds')
-%# , title_class=> 'inverse'
-%# , color => "#993333" &>
-%#
-%#<%loc('Private search ICal feeds disabled. To enable them, ask your admin for "[_1]" and "[_2]" rights',
-%# loc('CreateSavedSearch'),
-%# loc('LoadSavedSearch') )%>
-%#
-%#</&>
-% }
-
-</&>
-
-<%INIT>
-use Digest::SHA;
-use RT::SavedSearches;
-
-my $title = loc("Calendar Prefs");
-my $AllowSearch;
-
-$AllowSearch = 1
- if $session{'CurrentUser'}->HasRight( Right => 'LoadSavedSearch',
- Object=> $RT::System );
-
-my $object;
-
-if ($HiddenField && $HiddenField eq 'Private') {
- $object = $session{CurrentUser}->UserObj;
-} elsif ($AllowSearch and $HiddenField and my ($SearchId) = $HiddenField =~ m/SavedSearch\-(\d+)/) {
- $object = $session{CurrentUser}->Attributes->WithId($SearchId);
-}
-
-if (defined $ChangeURL) {
- my @args = $object->SetAttribute(Name => 'ICalURL', Content => Digest::SHA::sha1_base64(time));
-} elsif (defined $ResetURL) {
- my @args = $object->DeleteAttribute('ICalURL');
-}
-
-
-</%INIT>
@@ -1,68 +0,0 @@
-<%args>
-$Search => undef
-$Object => undef
-$HiddenField => undef
-</%args>
-
-<&| /Widgets/TitleBox, title => $title &>
-
-% if ($FeedText) {
-<p><%$FeedText%></p>
-% } else {
-This feed will show tickets with due date find with query:<br />
-"<%$Search->SubValue('Query')%>".
-% }
-
-% if ($ICalURL) {
-<p>Your can paste this url in your calendar : <b><a href="<%$link%>"><%$link%></a></b><p>
-<table>
-<tr>
-<td>
-<form action="<%$RT::WebPath%>/Prefs/Calendar.html" method="post">
-<input type="hidden" name="HiddenField" value="<%$HiddenField%>" />
-<input type="submit" class="button" name="ResetURL" value="<%loc('Disable Feed')%>" />
-</form>
-</td>
-<td>
-<form action="<%$RT::WebPath%>/Prefs/Calendar.html" method="post">
-<input type="hidden" name="HiddenField" value="<%$HiddenField%>" />
-<input type="submit" class="button" name="ChangeURL" value="<%loc('Change Feed URL')%>" />
-</form>
-</td>
-</tr>
-</table>
-% } else {
-
-<form action="<%$RT::WebPath%>/Prefs/Calendar.html" method="post">
-<input type="hidden" name="HiddenField" value="<%$HiddenField%>" />
-<input type="submit" class="button" name="ChangeURL" value="<%loc('Enable Feed')%>" />
-</form>
-% }
-
-</&>
-
-<%init>
-my $title;
-my $ICalURL;
-my $Id;
-my $FeedText;
-my $link;
-
-if ($Object) {
- $title = loc('Feed for "') . ($Search->Description || loc('Unnamed search')) . '" search';
- $HiddenField = "SavedSearch-" . $Search->Id;
- $ICalURL = $Search->FirstAttribute('ICalURL');
- $Id = $session{CurrentUser}->Id . "@" . $Search->Id;
- $title .= " (disabled)" unless $ICalURL;
-} else {
- $title = loc('Feed for default calendar');
- $HiddenField = "Private";
- $ICalURL = $session{CurrentUser}->UserObj->FirstAttribute('ICalURL');
- $Id = $session{CurrentUser}->Id;
- $FeedText = "This feed will show yours and Nobody's tasks with due date.";
-}
-
-$link = $RT::WebURL . "NoAuth/Calendar/" . $Id . "/" . $ICalURL->Content
- if $ICalURL;
-
-</%init>
\ No newline at end of file
@@ -117,14 +117,7 @@ $NewQuery => 0
</table>
<table width="100%">
-<tr>
-
-<td valign="top" rowspan=9>
- <BR>
- <a href="<%$RT::WebPath%>/Prefs/Calendar.html">Calendar Preferences and Help</a>
-</td>
-
-% foreach my $legend (keys %legend) {
+% foreach my $legend (sort keys %legend) {
<tr>
<td align="right">
<img src="<%$RT::WebImagesURL%>/<%$legend%>.png" />
@@ -143,6 +136,43 @@ $NewQuery => 0
</&>
+<&| /Widgets/TitleBox, title => loc('Help') &>
+
+<h3><&|/l&>displaying reminders</&>:</h3>
+<p>
+<&|/l_unsafe, qq{<a href="$RT::WebPath/Search/Edit.html">} . loc("Advanced") . '</a>' &>
+If you want to have reminders in a search you need to go to [_1] tab
+and add something to the Query like that:
+</&>
+ <pre>
+ AND ( Type = 'ticket' OR Type = 'reminder' )
+</pre>
+</p>
+
+<h3><&|/l&>displaying other kind of dates</&>:</h3>
+<p>
+<&|/l_unsafe, qq{<a href="$RT::WebPath/Search/Build.html">} . loc("Query Builder") . '</a>'&>
+By default RTx::Calendar display Due and Starts dates. You can select other
+kind of events you want with the Display Columns section in the [_1].
+The following one will display the two latter and LastUpdated dates:
+</&>
+<pre>
+ '<small>__Due__</small>',
+ '<small>__Starts__</small>',
+ '<small>__LastUpdated__</small>'
+</pre>
+</p>
+
+<h3><&|/l&>changing the default query</&>:</h3>
+<p>
+<&|/l_unsafe, qq{<a href="$RT::WebPath/Search/Build.html">} . loc("Query Builder") . '</a>'&>
+You can change the default Query of Calendar.html and MyCalendar
+portlet by saving a query with the name <code>calendar</code> in the [_1].
+</&>
+</p>
+
+</&>
+
<%ONCE>
my %legend = (
@@ -4,7 +4,7 @@ package Module::Install::Base;
use strict 'vars';
use vars qw{$VERSION};
BEGIN {
- $VERSION = '1.08';
+ $VERSION = '1.12';
}
# Suspend handler for "redefined" warnings
@@ -8,7 +8,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.08';
+ $VERSION = '1.12';
@ISA = 'Module::Install::Base';
$ISCORE = 1;
}
@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.08';
+ $VERSION = '1.12';
@ISA = 'Module::Install::Base';
$ISCORE = 1;
}
@@ -0,0 +1,34 @@
+#line 1
+package Module::Install::Include;
+
+use strict;
+use Module::Install::Base ();
+
+use vars qw{$VERSION @ISA $ISCORE};
+BEGIN {
+ $VERSION = '1.12';
+ @ISA = 'Module::Install::Base';
+ $ISCORE = 1;
+}
+
+sub include {
+ shift()->admin->include(@_);
+}
+
+sub include_deps {
+ shift()->admin->include_deps(@_);
+}
+
+sub auto_include {
+ shift()->admin->auto_include(@_);
+}
+
+sub auto_include_deps {
+ shift()->admin->auto_include_deps(@_);
+}
+
+sub auto_include_dependent_dists {
+ shift()->admin->auto_include_dependent_dists(@_);
+}
+
+1;
@@ -8,7 +8,7 @@ use Fcntl qw/:flock :seek/;
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.08';
+ $VERSION = '1.12';
@ISA = 'Module::Install::Base';
$ISCORE = 1;
}
@@ -133,7 +133,7 @@ sub makemaker_args {
return $args;
}
-# For mm args that take multiple space-seperated args,
+# For mm args that take multiple space-separated args,
# append an argument to the current list.
sub makemaker_append {
my $self = shift;
@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.08';
+ $VERSION = '1.12';
@ISA = 'Module::Install::Base';
$ISCORE = 1;
}
@@ -347,7 +347,7 @@ sub name_from {
^ \s*
package \s*
([\w:]+)
- \s* ;
+ [\s|;]*
/ixms
) {
my ($name, $module_name) = ($1, $1);
@@ -705,7 +705,7 @@ sub _write_mymeta_data {
my @yaml = Parse::CPAN::Meta::LoadFile('META.yml');
my $meta = $yaml[0];
- # Overwrite the non-configure dependency hashs
+ # Overwrite the non-configure dependency hashes
delete $meta->{requires};
delete $meta->{build_requires};
delete $meta->{recommends};
@@ -0,0 +1,79 @@
+#line 1
+package Module::Install::RTx::Runtime;
+
+use base 'Exporter';
+our @EXPORT = qw/RTxDatabase RTxPlugin/;
+
+use strict;
+use File::Basename ();
+
+sub _rt_runtime_load {
+ require RT;
+
+ eval { RT::LoadConfig(); };
+ if (my $err = $@) {
+ die $err unless $err =~ /^RT couldn't load RT config file/m;
+ my $warn = <<EOT;
+This usually means that your current user cannot read the file. You
+will likely need to run this installation step as root, or some user
+with more permissions.
+EOT
+ $err =~ s/This usually means.*/$warn/s;
+ die $err;
+ }
+}
+
+sub RTxDatabase {
+ my ($action, $name, $version) = @_;
+
+ _rt_runtime_load();
+
+ require RT::System;
+ my $has_upgrade = RT::System->can('AddUpgradeHistory');
+
+ my $lib_path = File::Basename::dirname($INC{'RT.pm'});
+ my @args = (
+ "-Ilib",
+ "-I$RT::LocalLibPath",
+ "-I$lib_path",
+ "$RT::SbinPath/rt-setup-database",
+ "--action" => $action,
+ ($action eq 'upgrade' ? () : ("--datadir" => "etc")),
+ (($action eq 'insert') ? ("--datafile" => "etc/initialdata") : ()),
+ "--dba" => $RT::DatabaseAdmin || $RT::DatabaseUser,
+ "--prompt-for-dba-password" => '',
+ ($has_upgrade ? ("--package" => $name, "--ext-version" => $version) : ()),
+ );
+ # If we're upgrading against an RT which isn't at least 4.2 (has
+ # AddUpgradeHistory) then pass --package. Upgrades against later RT
+ # releases will pick up --package from AddUpgradeHistory.
+ if ($action eq 'upgrade' and not $has_upgrade) {
+ push @args, "--package" => $name;
+ }
+
+ print "$^X @args\n";
+ (system($^X, @args) == 0) or die "...returned with error: $?\n";
+}
+
+sub RTxPlugin {
+ my ($name) = @_;
+
+ _rt_runtime_load();
+ require YAML::Tiny;
+ my $data = YAML::Tiny::LoadFile('META.yml');
+ my $name = $data->{name};
+
+ my @enabled = RT->Config->Get('Plugins');
+ for my $required (@{$data->{x_requires_rt_plugins} || []}) {
+ next if grep {$required eq $_} @enabled;
+
+ warn <<"EOT";
+
+**** Warning: $name requires that the $required plugin be installed and
+ enabled; it is not currently in \@Plugins.
+
+EOT
+ }
+}
+
+1;
@@ -8,7 +8,7 @@ no warnings 'once';
use Module::Install::Base;
use base 'Module::Install::Base';
-our $VERSION = '0.34';
+our $VERSION = '0.36';
use FindBin;
use File::Glob ();
@@ -18,100 +18,79 @@ my @DIRS = qw(etc lib html static bin sbin po var);
my @INDEX_DIRS = qw(lib bin sbin);
sub RTx {
- my ( $self, $name ) = @_;
+ my ( $self, $name, $extra_args ) = @_;
+ $extra_args ||= {};
- my $original_name = $name;
- my $RTx = 'RTx';
- $RTx = $1 if $name =~ s/^(\w+)-//;
+ # Set up names
my $fname = $name;
$fname =~ s!-!/!g;
- $self->name("$RTx-$name")
+ $self->name( $name )
unless $self->name;
- $self->all_from( -e "$name.pm" ? "$name.pm" : "lib/$RTx/$fname.pm" )
+ $self->all_from( "lib/$fname.pm" )
unless $self->version;
- $self->abstract("RT $name Extension")
+ $self->abstract("$name Extension")
unless $self->abstract;
-
- my @prefixes = (qw(/opt /usr/local /home /usr /sw ));
- my $prefix = $ENV{PREFIX};
- @ARGV = grep { /PREFIX=(.*)/ ? ( ( $prefix = $1 ), 0 ) : 1 } @ARGV;
-
- if ($prefix) {
- $RT::LocalPath = $prefix;
- $INC{'RT.pm'} = "$RT::LocalPath/lib/RT.pm";
- } else {
- local @INC = (
- $ENV{RTHOME} ? ( $ENV{RTHOME}, "$ENV{RTHOME}/lib" ) : (),
- @INC,
- map { ( "$_/rt4/lib", "$_/lib/rt4", "$_/rt3/lib", "$_/lib/rt3", "$_/lib" )
- } grep $_, @prefixes
- );
- until ( eval { require RT; $RT::LocalPath } ) {
- warn
- "Cannot find the location of RT.pm that defines \$RT::LocalPath in: @INC\n";
- $_ = $self->prompt("Path to directory containing your RT.pm:") or exit;
- $_ =~ s/\/RT\.pm$//;
- push @INC, $_, "$_/rt3/lib", "$_/lib/rt3", "$_/lib";
- }
+ unless ( $extra_args->{no_readme_generation} ) {
+ $self->readme_from( "lib/$fname.pm",
+ { options => [ quotes => "none" ] } );
+ }
+ $self->add_metadata("x_module_install_rtx_version", $VERSION );
+
+ # Try to find RT.pm
+ my @prefixes = qw( /opt /usr/local /home /usr /sw /usr/share/request-tracker4);
+ $ENV{RTHOME} =~ s{/RT\.pm$}{} if defined $ENV{RTHOME};
+ $ENV{RTHOME} =~ s{/lib/?$}{} if defined $ENV{RTHOME};
+ my @try = $ENV{RTHOME} ? ($ENV{RTHOME}, "$ENV{RTHOME}/lib") : ();
+ while (1) {
+ my @look = @INC;
+ unshift @look, grep {defined and -d $_} @try;
+ push @look, grep {defined and -d $_}
+ map { ( "$_/rt4/lib", "$_/lib/rt4", "$_/lib" ) } @prefixes;
+ last if eval {local @INC = @look; require RT; $RT::LocalLibPath};
+
+ warn
+ "Cannot find the location of RT.pm that defines \$RT::LocalPath in: @look\n";
+ my $given = $self->prompt("Path to directory containing your RT.pm:") or exit;
+ $given =~ s{/RT\.pm$}{};
+ $given =~ s{/lib/?$}{};
+ @try = ($given, "$given/lib");
}
- my $lib_path = File::Basename::dirname( $INC{'RT.pm'} );
- my $local_lib_path = "$RT::LocalPath/lib";
print "Using RT configuration from $INC{'RT.pm'}:\n";
- unshift @INC, "$RT::LocalPath/lib" if $RT::LocalPath;
- unshift @INC, $lib_path;
-
- $RT::LocalVarPath ||= $RT::VarPath;
- $RT::LocalPoPath ||= $RT::LocalLexiconPath;
- $RT::LocalHtmlPath ||= $RT::MasonComponentRoot;
- $RT::LocalStaticPath ||= $RT::StaticPath;
- $RT::LocalLibPath ||= "$RT::LocalPath/lib";
- my $with_subdirs = $ENV{WITH_SUBDIRS};
- @ARGV = grep { /WITH_SUBDIRS=(.*)/ ? ( ( $with_subdirs = $1 ), 0 ) : 1 }
- @ARGV;
+ my $local_lib_path = $RT::LocalLibPath;
+ unshift @INC, $local_lib_path;
+ my $lib_path = File::Basename::dirname( $INC{'RT.pm'} );
+ unshift @INC, $lib_path;
- my %subdirs;
- %subdirs = map { $_ => 1 } split( /\s*,\s*/, $with_subdirs )
- if defined $with_subdirs;
- unless ( keys %subdirs ) {
- $subdirs{$_} = 1 foreach grep -d "$FindBin::Bin/$_", @DIRS;
+ # Set a baseline minimum version
+ unless ( $extra_args->{deprecated_rt} ) {
+ $self->requires_rt('4.0.0');
}
- # If we're running on RT 3.8 with plugin support, we really wany
- # to install libs, mason templates and po files into plugin specific
- # directories
+ # Installation locations
my %path;
- if ( $RT::LocalPluginPath ) {
- die "Because of bugs in RT 3.8.0 this extension can not be installed.\n"
- ."Upgrade to RT 3.8.1 or newer.\n" if $RT::VERSION =~ /^3\.8\.0/;
- $path{$_} = $RT::LocalPluginPath . "/$original_name/$_"
- foreach @DIRS;
-
- # Copy RT 4.2.0 static files into NoAuth; insufficient for
- # images, but good enough for css and js.
- $path{static} = "$path{html}/NoAuth/"
- unless $RT::StaticPath;
- } else {
- foreach ( @DIRS ) {
- no strict 'refs';
- my $varname = "RT::Local" . ucfirst($_) . "Path";
- $path{$_} = ${$varname} || "$RT::LocalPath/$_";
- }
+ $path{$_} = $RT::LocalPluginPath . "/$name/$_"
+ foreach @DIRS;
- $path{$_} .= "/$name" for grep $path{$_}, qw(etc po var);
- }
+ # Copy RT 4.2.0 static files into NoAuth; insufficient for
+ # images, but good enough for css and js.
+ $path{static} = "$path{html}/NoAuth/"
+ unless $RT::StaticPath;
+
+ # Delete the ones we don't need
+ delete $path{$_} for grep {not -d "$FindBin::Bin/$_"} keys %path;
my %index = map { $_ => 1 } @INDEX_DIRS;
$self->no_index( directory => $_ ) foreach grep !$index{$_}, @DIRS;
my $args = join ', ', map "q($_)", map { ($_, $path{$_}) }
- grep $subdirs{$_}, keys %path;
+ sort keys %path;
- print "./$_\t=> $path{$_}\n" for sort keys %subdirs;
+ printf "%-10s => %s\n", $_, $path{$_} for sort keys %path;
- if ( my @dirs = map { ( -D => $_ ) } grep $subdirs{$_}, qw(bin html sbin) ) {
+ if ( my @dirs = map { ( -D => $_ ) } grep $path{$_}, qw(bin html sbin etc) ) {
my @po = map { ( -o => $_ ) }
grep -f,
File::Glob::bsd_glob("po/*.po");
@@ -121,12 +100,15 @@ lexicons ::
.
}
+ $self->include('Module::Install::RTx::Runtime') if $self->admin;
+ $self->include_deps( 'YAML::Tiny', 0 ) if $self->admin;
my $postamble = << ".";
install ::
+\t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxPlugin()"
\t\$(NOECHO) \$(PERL) -MExtUtils::Install -e \"install({$args})\"
.
- if ( $subdirs{var} and -d $RT::MasonDataDir ) {
+ if ( $path{var} and -d $RT::MasonDataDir ) {
my ( $uid, $gid ) = ( stat($RT::MasonDataDir) )[ 4, 5 ];
$postamble .= << ".";
\t\$(NOECHO) chown -R $uid:$gid $path{var}
@@ -141,16 +123,16 @@ install ::
$has_etc{acl}++;
}
if ( -e 'etc/initialdata' ) { $has_etc{initialdata}++; }
- if ( grep { /\d+\.\d+\.\d+.*$/ } glob('etc/upgrade/*.*.*') ) {
+ if ( grep { /\d+\.\d+(\.\d+)?.*$/ } glob('etc/upgrade/*.*') ) {
$has_etc{upgrade}++;
}
$self->postamble("$postamble\n");
- unless ( $subdirs{'lib'} ) {
- $self->makemaker_args( PM => { "" => "" }, );
- } else {
+ if ( $path{lib} ) {
$self->makemaker_args( INSTALLSITELIB => $path{'lib'} );
$self->makemaker_args( INSTALLARCHLIB => $path{'lib'} );
+ } else {
+ $self->makemaker_args( PM => { "" => "" }, );
}
$self->makemaker_args( INSTALLSITEMAN1DIR => "$RT::LocalPath/man/man1" );
@@ -158,47 +140,96 @@ install ::
$self->makemaker_args( INSTALLSITEARCH => "$RT::LocalPath/man" );
if (%has_etc) {
- $self->load('RTxInitDB');
print "For first-time installation, type 'make initdb'.\n";
my $initdb = '';
$initdb .= <<"." if $has_etc{schema};
-\t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Minc::Module::Install -e"RTxInitDB(qw(schema \$(NAME) \$(VERSION)))"
+\t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxDatabase(qw(schema \$(NAME) \$(VERSION)))"
.
$initdb .= <<"." if $has_etc{acl};
-\t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Minc::Module::Install -e"RTxInitDB(qw(acl \$(NAME) \$(VERSION)))"
+\t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxDatabase(qw(acl \$(NAME) \$(VERSION)))"
.
$initdb .= <<"." if $has_etc{initialdata};
-\t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Minc::Module::Install -e"RTxInitDB(qw(insert \$(NAME) \$(VERSION)))"
+\t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxDatabase(qw(insert \$(NAME) \$(VERSION)))"
.
$self->postamble("initdb ::\n$initdb\n");
$self->postamble("initialize-database ::\n$initdb\n");
if ($has_etc{upgrade}) {
print "To upgrade from a previous version of this extension, use 'make upgrade-database'\n";
- my $upgradedb = qq|\t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Minc::Module::Install -e"RTxInitDB(qw(upgrade \$(NAME) \$(VERSION)))"\n|;
+ my $upgradedb = qq|\t\$(NOECHO) \$(PERL) -Ilib -I"$local_lib_path" -I"$lib_path" -Iinc -MModule::Install::RTx::Runtime -e"RTxDatabase(qw(upgrade \$(NAME) \$(VERSION)))"\n|;
$self->postamble("upgrade-database ::\n$upgradedb\n");
$self->postamble("upgradedb ::\n$upgradedb\n");
}
}
+
}
sub requires_rt {
my ($self,$version) = @_;
+ _load_rt_handle();
+
+ if ($self->is_admin) {
+ $self->add_metadata("x_requires_rt", $version);
+ my @sorted = sort RT::Handle::cmp_version $version,'4.0.0';
+ $self->perl_version('5.008003') if $sorted[0] eq '4.0.0'
+ and (not $self->perl_version or '5.008003' > $self->perl_version);
+ @sorted = sort RT::Handle::cmp_version $version,'4.2.0';
+ $self->perl_version('5.010001') if $sorted[0] eq '4.2.0'
+ and (not $self->perl_version or '5.010001' > $self->perl_version);
+ }
+
# if we're exactly the same version as what we want, silently return
return if ($version eq $RT::VERSION);
- _load_rt_handle();
my @sorted = sort RT::Handle::cmp_version $version,$RT::VERSION;
if ($sorted[-1] eq $version) {
- # should we die?
- die "\nWarning: prerequisite RT $version not found. Your installed version of RT ($RT::VERSION) is too old.\n\n";
+ die <<"EOT";
+
+**** Error: This extension requires RT $version. Your installed version
+ of RT ($RT::VERSION) is too old.
+
+EOT
+ }
+}
+
+sub requires_rt_plugin {
+ my $self = shift;
+ my ( $plugin ) = @_;
+
+ if ($self->is_admin) {
+ my $plugins = $self->Meta->{values}{"x_requires_rt_plugins"} || [];
+ push @{$plugins}, $plugin;
+ $self->add_metadata("x_requires_rt_plugins", $plugins);
}
+
+ my $path = $plugin;
+ $path =~ s{\:\:}{-}g;
+ $path = "$RT::LocalPluginPath/$path/lib";
+ if ( -e $path ) {
+ unshift @INC, $path;
+ } else {
+ my $name = $self->name;
+ warn <<"EOT";
+
+**** Warning: $name requires that the $plugin plugin be installed and
+ enabled; it does not appear to be installed.
+
+EOT
+ }
+ $self->requires(@_);
}
sub rt_too_new {
my ($self,$version,$msg) = @_;
- $msg ||= "Your version %s is too new, this extension requires a release of RT older than %s\n";
+ my $name = $self->name;
+ $msg ||= <<EOT;
+
+**** Error: Your installed version of RT (%s) is too new; this extension
+ only works with versions older than %s.
+
+EOT
+ $self->add_metadata("x_rt_too_new", $version) if $self->is_admin;
_load_rt_handle();
my @sorted = sort RT::Handle::cmp_version $version,$RT::VERSION;
@@ -227,4 +258,4 @@ sub _load_rt_handle {
__END__
-#line 367
+#line 390
@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.08';
+ $VERSION = '1.12';
@ISA = 'Module::Install::Base';
$ISCORE = 1;
}
@@ -6,7 +6,7 @@ use Module::Install::Base ();
use vars qw{$VERSION @ISA $ISCORE};
BEGIN {
- $VERSION = '1.08';
+ $VERSION = '1.12';
@ISA = qw{Module::Install::Base};
$ISCORE = 1;
}
@@ -17,7 +17,7 @@ package Module::Install;
# 3. The ./inc/ version of Module::Install loads
# }
-use 5.005;
+use 5.006;
use strict 'vars';
use Cwd ();
use File::Find ();
@@ -31,7 +31,7 @@ BEGIN {
# This is not enforced yet, but will be some time in the next few
# releases once we can make sure it won't clash with custom
# Module::Install extensions.
- $VERSION = '1.08';
+ $VERSION = '1.12';
# Storage for the pseudo-singleton
$MAIN = undef;
@@ -156,10 +156,10 @@ END_DIE
sub autoload {
my $self = shift;
my $who = $self->_caller;
- my $cwd = Cwd::cwd();
+ my $cwd = Cwd::getcwd();
my $sym = "${who}::AUTOLOAD";
$sym->{$cwd} = sub {
- my $pwd = Cwd::cwd();
+ my $pwd = Cwd::getcwd();
if ( my $code = $sym->{$pwd} ) {
# Delegate back to parent dirs
goto &$code unless $cwd eq $pwd;
@@ -239,7 +239,7 @@ sub new {
# ignore the prefix on extension modules built from top level.
my $base_path = Cwd::abs_path($FindBin::Bin);
- unless ( Cwd::abs_path(Cwd::cwd()) eq $base_path ) {
+ unless ( Cwd::abs_path(Cwd::getcwd()) eq $base_path ) {
delete $args{prefix};
}
return $args{_self} if $args{_self};
@@ -338,7 +338,7 @@ sub find_extensions {
if ( $subpath eq lc($subpath) || $subpath eq uc($subpath) ) {
my $content = Module::Install::_read($subpath . '.pm');
my $in_pod = 0;
- foreach ( split //, $content ) {
+ foreach ( split /\n/, $content ) {
$in_pod = 1 if /^=\w/;
$in_pod = 0 if /^=cut/;
next if ($in_pod || /^=cut/); # skip pod text
@@ -434,7 +434,7 @@ END_OLD
# _version is for processing module versions (eg, 1.03_05) not
# Perl versions (eg, 5.8.1).
-sub _version ($) {
+sub _version {
my $s = shift || 0;
my $d =()= $s =~ /(\.)/g;
if ( $d >= 2 ) {
@@ -450,12 +450,12 @@ sub _version ($) {
return $l + 0;
}
-sub _cmp ($$) {
+sub _cmp {
_version($_[1]) <=> _version($_[2]);
}
# Cloned from Params::Util::_CLASS
-sub _CLASS ($) {
+sub _CLASS {
(
defined $_[0]
and
@@ -0,0 +1,873 @@
+#line 1
+use 5.008001; # sane UTF-8 support
+use strict;
+use warnings;
+package YAML::Tiny;
+BEGIN {
+ $YAML::Tiny::AUTHORITY = 'cpan:ADAMK';
+}
+# git description: v1.61-3-g0a82466
+$YAML::Tiny::VERSION = '1.62';
+# XXX-INGY is 5.8.1 too old/broken for utf8?
+# XXX-XDG Lancaster consensus was that it was sufficient until
+# proven otherwise
+
+
+#####################################################################
+# The YAML::Tiny API.
+#
+# These are the currently documented API functions/methods and
+# exports:
+
+use Exporter;
+our @ISA = qw{ Exporter };
+our @EXPORT = qw{ Load Dump };
+our @EXPORT_OK = qw{ LoadFile DumpFile freeze thaw };
+
+###
+# Functional/Export API:
+
+sub Dump {
+ return YAML::Tiny->new(@_)->_dump_string;
+}
+
+# XXX-INGY Returning last document seems a bad behavior.
+# XXX-XDG I think first would seem more natural, but I don't know
+# that it's worth changing now
+sub Load {
+ my $self = YAML::Tiny->_load_string(@_);
+ if ( wantarray ) {
+ return @$self;
+ } else {
+ # To match YAML.pm, return the last document
+ return $self->[-1];
+ }
+}
+
+# XXX-INGY Do we really need freeze and thaw?
+# XXX-XDG I don't think so. I'd support deprecating them.
+BEGIN {
+ *freeze = \&Dump;
+ *thaw = \&Load;
+}
+
+sub DumpFile {
+ my $file = shift;
+ return YAML::Tiny->new(@_)->_dump_file($file);
+}
+
+sub LoadFile {
+ my $file = shift;
+ my $self = YAML::Tiny->_load_file($file);
+ if ( wantarray ) {
+ return @$self;
+ } else {
+ # Return only the last document to match YAML.pm,
+ return $self->[-1];
+ }
+}
+
+
+###
+# Object Oriented API:
+
+# Create an empty YAML::Tiny object
+# XXX-INGY Why do we use ARRAY object?
+# NOTE: I get it now, but I think it's confusing and not needed.
+# Will change it on a branch later, for review.
+#
+# XXX-XDG I don't support changing it yet. It's a very well-documented
+# "API" of YAML::Tiny. I'd support deprecating it, but Adam suggested
+# we not change it until YAML.pm's own OO API is established so that
+# users only have one API change to digest, not two
+sub new {
+ my $class = shift;
+ bless [ @_ ], $class;
+}
+
+# XXX-INGY It probably doesn't matter, and it's probably too late to
+# change, but 'read/write' are the wrong names. Read and Write
+# are actions that take data from storage to memory
+# characters/strings. These take the data to/from storage to native
+# Perl objects, which the terms dump and load are meant. As long as
+# this is a legacy quirk to YAML::Tiny it's ok, but I'd prefer not
+# to add new {read,write}_* methods to this API.
+
+sub read_string {
+ my $self = shift;
+ $self->_load_string(@_);
+}
+
+sub write_string {
+ my $self = shift;
+ $self->_dump_string(@_);
+}
+
+sub read {
+ my $self = shift;
+ $self->_load_file(@_);
+}
+
+sub write {
+ my $self = shift;
+ $self->_dump_file(@_);
+}
+
+
+
+
+#####################################################################
+# Constants
+
+# Printed form of the unprintable characters in the lowest range
+# of ASCII characters, listed by ASCII ordinal position.
+my @UNPRINTABLE = qw(
+ 0 x01 x02 x03 x04 x05 x06 a
+ b t n v f r x0E x0F
+ x10 x11 x12 x13 x14 x15 x16 x17
+ x18 x19 x1A e x1C x1D x1E x1F
+);
+
+# Printable characters for escapes
+my %UNESCAPES = (
+ 0 => "\x00", z => "\x00", N => "\x85",
+ a => "\x07", b => "\x08", t => "\x09",
+ n => "\x0a", v => "\x0b", f => "\x0c",
+ r => "\x0d", e => "\x1b", '\\' => '\\',
+);
+
+# XXX-INGY
+# I(ngy) need to decide if these values should be quoted in
+# YAML::Tiny or not. Probably yes.
+
+# These 3 values have special meaning when unquoted and using the
+# default YAML schema. They need quotes if they are strings.
+my %QUOTE = map { $_ => 1 } qw{
+ null true false
+};
+
+# The commented out form is simpler, but overloaded the Perl regex
+# engine due to recursion and backtracking problems on strings
+# larger than 32,000ish characters. Keep it for reference purposes.
+# qr/\"((?:\\.|[^\"])*)\"/
+my $re_capture_double_quoted = qr/\"([^\\"]*(?:\\.[^\\"]*)*)\"/;
+my $re_capture_single_quoted = qr/\'([^\']*(?:\'\'[^\']*)*)\'/;
+# unquoted re gets trailing space that needs to be stripped
+my $re_capture_unquoted_key = qr/([^:]+(?::+\S(?:[^:]*|.*?(?=:)))*)(?=\s*\:(?:\s+|$))/;
+my $re_trailing_comment = qr/(?:\s+\#.*)?/;
+my $re_key_value_separator = qr/\s*:(?:\s+(?:\#.*)?|$)/;
+
+
+
+
+
+#####################################################################
+# YAML::Tiny Implementation.
+#
+# These are the private methods that do all the work. They may change
+# at any time.
+
+
+###
+# Loader functions:
+
+# Create an object from a file
+sub _load_file {
+ my $class = ref $_[0] ? ref shift : shift;
+
+ # Check the file
+ my $file = shift or $class->_error( 'You did not specify a file name' );
+ $class->_error( "File '$file' does not exist" )
+ unless -e $file;
+ $class->_error( "'$file' is a directory, not a file" )
+ unless -f _;
+ $class->_error( "Insufficient permissions to read '$file'" )
+ unless -r _;
+
+ # Open unbuffered with strict UTF-8 decoding and no translation layers
+ open( my $fh, "<:unix:encoding(UTF-8)", $file );
+ unless ( $fh ) {
+ $class->_error("Failed to open file '$file': $!");
+ }
+
+ # flock if available (or warn if not possible for OS-specific reasons)
+ if ( _can_flock() ) {
+ flock( $fh, Fcntl::LOCK_SH() )
+ or warn "Couldn't lock '$file' for reading: $!";
+ }
+
+ # slurp the contents
+ my $contents = eval {
+ use warnings FATAL => 'utf8';
+ local $/;
+ <$fh>
+ };
+ if ( my $err = $@ ) {
+ $class->_error("Error reading from file '$file': $err");
+ }
+
+ # close the file (release the lock)
+ unless ( close $fh ) {
+ $class->_error("Failed to close file '$file': $!");
+ }
+
+ $class->_load_string( $contents );
+}
+
+# Create an object from a string
+sub _load_string {
+ my $class = ref $_[0] ? ref shift : shift;
+ my $self = bless [], $class;
+ my $string = $_[0];
+ eval {
+ unless ( defined $string ) {
+ die \"Did not provide a string to load";
+ }
+
+ # Check if Perl has it marked as characters, but it's internally
+ # inconsistent. E.g. maybe latin1 got read on a :utf8 layer
+ if ( utf8::is_utf8($string) && ! utf8::valid($string) ) {
+ die \<<'...';
+Read an invalid UTF-8 string (maybe mixed UTF-8 and 8-bit character set).
+Did you decode with lax ":utf8" instead of strict ":encoding(UTF-8)"?
+...
+ }
+
+ # Ensure Unicode character semantics, even for 0x80-0xff
+ utf8::upgrade($string);
+
+ # Check for and strip any leading UTF-8 BOM
+ $string =~ s/^\x{FEFF}//;
+
+ # Check for some special cases
+ return $self unless length $string;
+
+ # Split the file into lines
+ my @lines = grep { ! /^\s*(?:\#.*)?\z/ }
+ split /(?:\015{1,2}\012|\015|\012)/, $string;
+
+ # Strip the initial YAML header
+ @lines and $lines[0] =~ /^\%YAML[: ][\d\.]+.*\z/ and shift @lines;
+
+ # A nibbling parser
+ my $in_document = 0;
+ while ( @lines ) {
+ # Do we have a document header?
+ if ( $lines[0] =~ /^---\s*(?:(.+)\s*)?\z/ ) {
+ # Handle scalar documents
+ shift @lines;
+ if ( defined $1 and $1 !~ /^(?:\#.+|\%YAML[: ][\d\.]+)\z/ ) {
+ push @$self,
+ $self->_load_scalar( "$1", [ undef ], \@lines );
+ next;
+ }
+ $in_document = 1;
+ }
+
+ if ( ! @lines or $lines[0] =~ /^(?:---|\.\.\.)/ ) {
+ # A naked document
+ push @$self, undef;
+ while ( @lines and $lines[0] !~ /^---/ ) {
+ shift @lines;
+ }
+ $in_document = 0;
+
+ # XXX The final '-+$' is to look for -- which ends up being an
+ # error later.
+ } elsif ( ! $in_document && @$self ) {
+ # only the first document can be explicit
+ die \"YAML::Tiny failed to classify the line '$lines[0]'";
+ } elsif ( $lines[0] =~ /^\s*\-(?:\s|$|-+$)/ ) {
+ # An array at the root
+ my $document = [ ];
+ push @$self, $document;
+ $self->_load_array( $document, [ 0 ], \@lines );
+
+ } elsif ( $lines[0] =~ /^(\s*)\S/ ) {
+ # A hash at the root
+ my $document = { };
+ push @$self, $document;
+ $self->_load_hash( $document, [ length($1) ], \@lines );
+
+ } else {
+ # Shouldn't get here. @lines have whitespace-only lines
+ # stripped, and previous match is a line with any
+ # non-whitespace. So this clause should only be reachable via
+ # a perlbug where \s is not symmetric with \S
+
+ # uncoverable statement
+ die \"YAML::Tiny failed to classify the line '$lines[0]'";
+ }
+ }
+ };
+ if ( ref $@ eq 'SCALAR' ) {
+ $self->_error(${$@});
+ } elsif ( $@ ) {
+ $self->_error($@);
+ }
+
+ return $self;
+}
+
+sub _unquote_single {
+ my ($self, $string) = @_;
+ return '' unless length $string;
+ $string =~ s/\'\'/\'/g;
+ return $string;
+}
+
+sub _unquote_double {
+ my ($self, $string) = @_;
+ return '' unless length $string;
+ $string =~ s/\\"/"/g;
+ $string =~
+ s{\\([Nnever\\fartz0b]|x([0-9a-fA-F]{2}))}
+ {(length($1)>1)?pack("H2",$2):$UNESCAPES{$1}}gex;
+ return $string;
+}
+
+# Load a YAML scalar string to the actual Perl scalar
+sub _load_scalar {
+ my ($self, $string, $indent, $lines) = @_;
+
+ # Trim trailing whitespace
+ $string =~ s/\s*\z//;
+
+ # Explitic null/undef
+ return undef if $string eq '~';
+
+ # Single quote
+ if ( $string =~ /^$re_capture_single_quoted$re_trailing_comment\z/ ) {
+ return $self->_unquote_single($1);
+ }
+
+ # Double quote.
+ if ( $string =~ /^$re_capture_double_quoted$re_trailing_comment\z/ ) {
+ return $self->_unquote_double($1);
+ }
+
+ # Special cases
+ if ( $string =~ /^[\'\"!&]/ ) {
+ die \"YAML::Tiny does not support a feature in line '$string'";
+ }
+ return {} if $string =~ /^{}(?:\s+\#.*)?\z/;
+ return [] if $string =~ /^\[\](?:\s+\#.*)?\z/;
+
+ # Regular unquoted string
+ if ( $string !~ /^[>|]/ ) {
+ die \"YAML::Tiny found illegal characters in plain scalar: '$string'"
+ if $string =~ /^(?:-(?:\s|$)|[\@\%\`])/ or
+ $string =~ /:(?:\s|$)/;
+ $string =~ s/\s+#.*\z//;
+ return $string;
+ }
+
+ # Error
+ die \"YAML::Tiny failed to find multi-line scalar content" unless @$lines;
+
+ # Check the indent depth
+ $lines->[0] =~ /^(\s*)/;
+ $indent->[-1] = length("$1");
+ if ( defined $indent->[-2] and $indent->[-1] <= $indent->[-2] ) {
+ die \"YAML::Tiny found bad indenting in line '$lines->[0]'";
+ }
+
+ # Pull the lines
+ my @multiline = ();
+ while ( @$lines ) {
+ $lines->[0] =~ /^(\s*)/;
+ last unless length($1) >= $indent->[-1];
+ push @multiline, substr(shift(@$lines), length($1));
+ }
+
+ my $j = (substr($string, 0, 1) eq '>') ? ' ' : "\n";
+ my $t = (substr($string, 1, 1) eq '-') ? '' : "\n";
+ return join( $j, @multiline ) . $t;
+}
+
+# Load an array
+sub _load_array {
+ my ($self, $array, $indent, $lines) = @_;
+
+ while ( @$lines ) {
+ # Check for a new document
+ if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
+ while ( @$lines and $lines->[0] !~ /^---/ ) {
+ shift @$lines;
+ }
+ return 1;
+ }
+
+ # Check the indent level
+ $lines->[0] =~ /^(\s*)/;
+ if ( length($1) < $indent->[-1] ) {
+ return 1;
+ } elsif ( length($1) > $indent->[-1] ) {
+ die \"YAML::Tiny found bad indenting in line '$lines->[0]'";
+ }
+
+ if ( $lines->[0] =~ /^(\s*\-\s+)[^\'\"]\S*\s*:(?:\s+|$)/ ) {
+ # Inline nested hash
+ my $indent2 = length("$1");
+ $lines->[0] =~ s/-/ /;
+ push @$array, { };
+ $self->_load_hash( $array->[-1], [ @$indent, $indent2 ], $lines );
+
+ } elsif ( $lines->[0] =~ /^\s*\-\s*\z/ ) {
+ shift @$lines;
+ unless ( @$lines ) {
+ push @$array, undef;
+ return 1;
+ }
+ if ( $lines->[0] =~ /^(\s*)\-/ ) {
+ my $indent2 = length("$1");
+ if ( $indent->[-1] == $indent2 ) {
+ # Null array entry
+ push @$array, undef;
+ } else {
+ # Naked indenter
+ push @$array, [ ];
+ $self->_load_array(
+ $array->[-1], [ @$indent, $indent2 ], $lines
+ );
+ }
+
+ } elsif ( $lines->[0] =~ /^(\s*)\S/ ) {
+ push @$array, { };
+ $self->_load_hash(
+ $array->[-1], [ @$indent, length("$1") ], $lines
+ );
+
+ } else {
+ die \"YAML::Tiny failed to classify line '$lines->[0]'";
+ }
+
+ } elsif ( $lines->[0] =~ /^\s*\-(\s*)(.+?)\s*\z/ ) {
+ # Array entry with a value
+ shift @$lines;
+ push @$array, $self->_load_scalar(
+ "$2", [ @$indent, undef ], $lines
+ );
+
+ } elsif ( defined $indent->[-2] and $indent->[-1] == $indent->[-2] ) {
+ # This is probably a structure like the following...
+ # ---
+ # foo:
+ # - list
+ # bar: value
+ #
+ # ... so lets return and let the hash parser handle it
+ return 1;
+
+ } else {
+ die \"YAML::Tiny failed to classify line '$lines->[0]'";
+ }
+ }
+
+ return 1;
+}
+
+# Load a hash
+sub _load_hash {
+ my ($self, $hash, $indent, $lines) = @_;
+
+ while ( @$lines ) {
+ # Check for a new document
+ if ( $lines->[0] =~ /^(?:---|\.\.\.)/ ) {
+ while ( @$lines and $lines->[0] !~ /^---/ ) {
+ shift @$lines;
+ }
+ return 1;
+ }
+
+ # Check the indent level
+ $lines->[0] =~ /^(\s*)/;
+ if ( length($1) < $indent->[-1] ) {
+ return 1;
+ } elsif ( length($1) > $indent->[-1] ) {
+ die \"YAML::Tiny found bad indenting in line '$lines->[0]'";
+ }
+
+ # Find the key
+ my $key;
+
+ # Quoted keys
+ if ( $lines->[0] =~
+ s/^\s*$re_capture_single_quoted$re_key_value_separator//
+ ) {
+ $key = $self->_unquote_single($1);
+ }
+ elsif ( $lines->[0] =~
+ s/^\s*$re_capture_double_quoted$re_key_value_separator//
+ ) {
+ $key = $self->_unquote_double($1);
+ }
+ elsif ( $lines->[0] =~
+ s/^\s*$re_capture_unquoted_key$re_key_value_separator//
+ ) {
+ $key = $1;
+ $key =~ s/\s+$//;
+ }
+ elsif ( $lines->[0] =~ /^\s*\?/ ) {
+ die \"YAML::Tiny does not support a feature in line '$lines->[0]'";
+ }
+ else {
+ die \"YAML::Tiny failed to classify line '$lines->[0]'";
+ }
+
+ # Do we have a value?
+ if ( length $lines->[0] ) {
+ # Yes
+ $hash->{$key} = $self->_load_scalar(
+ shift(@$lines), [ @$indent, undef ], $lines
+ );
+ } else {
+ # An indent
+ shift @$lines;
+ unless ( @$lines ) {
+ $hash->{$key} = undef;
+ return 1;
+ }
+ if ( $lines->[0] =~ /^(\s*)-/ ) {
+ $hash->{$key} = [];
+ $self->_load_array(
+ $hash->{$key}, [ @$indent, length($1) ], $lines
+ );
+ } elsif ( $lines->[0] =~ /^(\s*)./ ) {
+ my $indent2 = length("$1");
+ if ( $indent->[-1] >= $indent2 ) {
+ # Null hash entry
+ $hash->{$key} = undef;
+ } else {
+ $hash->{$key} = {};
+ $self->_load_hash(
+ $hash->{$key}, [ @$indent, length($1) ], $lines
+ );
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+###
+# Dumper functions:
+
+# Save an object to a file
+sub _dump_file {
+ my $self = shift;
+
+ require Fcntl;
+
+ # Check the file
+ my $file = shift or $self->_error( 'You did not specify a file name' );
+
+ my $fh;
+ # flock if available (or warn if not possible for OS-specific reasons)
+ if ( _can_flock() ) {
+ # Open without truncation (truncate comes after lock)
+ my $flags = Fcntl::O_WRONLY()|Fcntl::O_CREAT();
+ sysopen( $fh, $file, $flags );
+ unless ( $fh ) {
+ $self->_error("Failed to open file '$file' for writing: $!");
+ }
+
+ # Use no translation and strict UTF-8
+ binmode( $fh, ":raw:encoding(UTF-8)");
+
+ flock( $fh, Fcntl::LOCK_EX() )
+ or warn "Couldn't lock '$file' for reading: $!";
+
+ # truncate and spew contents
+ truncate $fh, 0;
+ seek $fh, 0, 0;
+ }
+ else {
+ open $fh, ">:unix:encoding(UTF-8)", $file;
+ }
+
+ # serialize and spew to the handle
+ print {$fh} $self->_dump_string;
+
+ # close the file (release the lock)
+ unless ( close $fh ) {
+ $self->_error("Failed to close file '$file': $!");
+ }
+
+ return 1;
+}
+
+# Save an object to a string
+sub _dump_string {
+ my $self = shift;
+ return '' unless ref $self && @$self;
+
+ # Iterate over the documents
+ my $indent = 0;
+ my @lines = ();
+
+ eval {
+ foreach my $cursor ( @$self ) {
+ push @lines, '---';
+
+ # An empty document
+ if ( ! defined $cursor ) {
+ # Do nothing
+
+ # A scalar document
+ } elsif ( ! ref $cursor ) {
+ $lines[-1] .= ' ' . $self->_dump_scalar( $cursor );
+
+ # A list at the root
+ } elsif ( ref $cursor eq 'ARRAY' ) {
+ unless ( @$cursor ) {
+ $lines[-1] .= ' []';
+ next;
+ }
+ push @lines, $self->_dump_array( $cursor, $indent, {} );
+
+ # A hash at the root
+ } elsif ( ref $cursor eq 'HASH' ) {
+ unless ( %$cursor ) {
+ $lines[-1] .= ' {}';
+ next;
+ }
+ push @lines, $self->_dump_hash( $cursor, $indent, {} );
+
+ } else {
+ die \("Cannot serialize " . ref($cursor));
+ }
+ }
+ };
+ if ( ref $@ eq 'SCALAR' ) {
+ $self->_error(${$@});
+ } elsif ( $@ ) {
+ $self->_error($@);
+ }
+
+ join '', map { "$_\n" } @lines;
+}
+
+sub _has_internal_string_value {
+ my $value = shift;
+ my $b_obj = B::svref_2object(\$value); # for round trip problem
+ return $b_obj->FLAGS & B::SVf_POK();
+}
+
+sub _dump_scalar {
+ my $string = $_[1];
+ my $is_key = $_[2];
+ # Check this before checking length or it winds up looking like a string!
+ my $has_string_flag = _has_internal_string_value($string);
+ return '~' unless defined $string;
+ return "''" unless length $string;
+ if (Scalar::Util::looks_like_number($string)) {
+ # keys and values that have been used as strings get quoted
+ if ( $is_key || $has_string_flag ) {
+ return qq['$string'];
+ }
+ else {
+ return $string;
+ }
+ }
+ if ( $string =~ /[\x00-\x09\x0b-\x0d\x0e-\x1f\x7f-\x9f\'\n]/ ) {
+ $string =~ s/\\/\\\\/g;
+ $string =~ s/"/\\"/g;
+ $string =~ s/\n/\\n/g;
+ $string =~ s/[\x85]/\\N/g;
+ $string =~ s/([\x00-\x1f])/\\$UNPRINTABLE[ord($1)]/g;
+ $string =~ s/([\x7f-\x9f])/'\x' . sprintf("%X",ord($1))/ge;
+ return qq|"$string"|;
+ }
+ if ( $string =~ /(?:^[~!@#%&*|>?:,'"`{}\[\]]|^-+$|\s|:\z)/ or
+ $QUOTE{$string}
+ ) {
+ return "'$string'";
+ }
+ return $string;
+}
+
+sub _dump_array {
+ my ($self, $array, $indent, $seen) = @_;
+ if ( $seen->{refaddr($array)}++ ) {
+ die \"YAML::Tiny does not support circular references";
+ }
+ my @lines = ();
+ foreach my $el ( @$array ) {
+ my $line = (' ' x $indent) . '-';
+ my $type = ref $el;
+ if ( ! $type ) {
+ $line .= ' ' . $self->_dump_scalar( $el );
+ push @lines, $line;
+
+ } elsif ( $type eq 'ARRAY' ) {
+ if ( @$el ) {
+ push @lines, $line;
+ push @lines, $self->_dump_array( $el, $indent + 1, $seen );
+ } else {
+ $line .= ' []';
+ push @lines, $line;
+ }
+
+ } elsif ( $type eq 'HASH' ) {
+ if ( keys %$el ) {
+ push @lines, $line;
+ push @lines, $self->_dump_hash( $el, $indent + 1, $seen );
+ } else {
+ $line .= ' {}';
+ push @lines, $line;
+ }
+
+ } else {
+ die \"YAML::Tiny does not support $type references";
+ }
+ }
+
+ @lines;
+}
+
+sub _dump_hash {
+ my ($self, $hash, $indent, $seen) = @_;
+ if ( $seen->{refaddr($hash)}++ ) {
+ die \"YAML::Tiny does not support circular references";
+ }
+ my @lines = ();
+ foreach my $name ( sort keys %$hash ) {
+ my $el = $hash->{$name};
+ my $line = (' ' x $indent) . $self->_dump_scalar($name, 1) . ":";
+ my $type = ref $el;
+ if ( ! $type ) {
+ $line .= ' ' . $self->_dump_scalar( $el );
+ push @lines, $line;
+
+ } elsif ( $type eq 'ARRAY' ) {
+ if ( @$el ) {
+ push @lines, $line;
+ push @lines, $self->_dump_array( $el, $indent + 1, $seen );
+ } else {
+ $line .= ' []';
+ push @lines, $line;
+ }
+
+ } elsif ( $type eq 'HASH' ) {
+ if ( keys %$el ) {
+ push @lines, $line;
+ push @lines, $self->_dump_hash( $el, $indent + 1, $seen );
+ } else {
+ $line .= ' {}';
+ push @lines, $line;
+ }
+
+ } else {
+ die \"YAML::Tiny does not support $type references";
+ }
+ }
+
+ @lines;
+}
+
+
+
+#####################################################################
+# DEPRECATED API methods:
+
+# Error storage (DEPRECATED as of 1.57)
+our $errstr = '';
+
+# Set error
+sub _error {
+ require Carp;
+ $errstr = $_[1];
+ $errstr =~ s/ at \S+ line \d+.*//;
+ Carp::croak( $errstr );
+}
+
+# Retrieve error
+my $errstr_warned;
+sub errstr {
+ require Carp;
+ Carp::carp( "YAML::Tiny->errstr and \$YAML::Tiny::errstr is deprecated" )
+ unless $errstr_warned++;
+ $errstr;
+}
+
+
+
+
+#####################################################################
+# Helper functions. Possibly not needed.
+
+
+# Use to detect nv or iv
+use B;
+
+# XXX-INGY Is flock YAML::Tiny's responsibility?
+# Some platforms can't flock :-(
+# XXX-XDG I think it is. When reading and writing files, we ought
+# to be locking whenever possible. People (foolishly) use YAML
+# files for things like session storage, which has race issues.
+my $HAS_FLOCK;
+sub _can_flock {
+ if ( defined $HAS_FLOCK ) {
+ return $HAS_FLOCK;
+ }
+ else {
+ require Config;
+ my $c = \%Config::Config;
+ $HAS_FLOCK = grep { $c->{$_} } qw/d_flock d_fcntl_can_lock d_lockf/;
+ require Fcntl if $HAS_FLOCK;
+ return $HAS_FLOCK;
+ }
+}
+
+
+# XXX-INGY Is this core in 5.8.1? Can we remove this?
+# XXX-XDG Scalar::Util 1.18 didn't land until 5.8.8, so we need this
+#####################################################################
+# Use Scalar::Util if possible, otherwise emulate it
+
+BEGIN {
+ local $@;
+ if ( eval { require Scalar::Util; Scalar::Util->VERSION(1.18); } ) {
+ *refaddr = *Scalar::Util::refaddr;
+ }
+ else {
+ eval <<'END_PERL';
+# Scalar::Util failed to load or too old
+sub refaddr {
+ my $pkg = ref($_[0]) or return undef;
+ if ( !! UNIVERSAL::can($_[0], 'can') ) {
+ bless $_[0], 'Scalar::Util::Fake';
+ } else {
+ $pkg = undef;
+ }
+ "$_[0]" =~ /0x(\w+)/;
+ my $i = do { no warnings 'portable'; hex $1 };
+ bless $_[0], $pkg if defined $pkg;
+ $i;
+}
+END_PERL
+ }
+}
+
+
+
+
+1;
+
+# XXX-INGY Doc notes I'm putting up here. Changing the doc when it's wrong
+# but leaving grey area stuff up here.
+#
+# I would like to change Read/Write to Load/Dump below without
+# changing the actual API names.
+#
+# It might be better to put Load/Dump API in the SYNOPSIS instead of the
+# dubious OO API.
+#
+# null and bool explanations may be outdated.
+
+__END__
+
+#line 1488
@@ -0,0 +1,417 @@
+#line 1
+# !!!!!!! DO NOT EDIT THIS FILE !!!!!!!
+# This file is machine-generated by lib/unicore/mktables from the Unicode
+# database, Version 6.3.0. Any changes made here will be lost!
+
+
+# !!!!!!! INTERNAL PERL USE ONLY !!!!!!!
+# This file is for internal use by core Perl only. The format and even the
+# name or existence of this file are subject to change without notice. Don't
+# use it directly. Use Unicode::UCD to access the Unicode character data
+# base.
+
+
+package charnames;
+
+# This module contains machine-generated tables and code for the
+# algorithmically-determinable Unicode character names. The following
+# routines can be used to translate between name and code point and vice versa
+
+{ # Closure
+
+ # Matches legal code point. 4-6 hex numbers, If there are 6, the first
+ # two must be 10; if there are 5, the first must not be a 0. Written this
+ # way to decrease backtracking. The first regex allows the code point to
+ # be at the end of a word, but to work properly, the word shouldn't end
+ # with a valid hex character. The second one won't match a code point at
+ # the end of a word, and doesn't have the run-on issue
+ my $run_on_code_point_re = qr/(?^aax: (?: 10[0-9A-F]{4} | [1-9A-F][0-9A-F]{4} | [0-9A-F]{4} ) \b)/;
+ my $code_point_re = qr/(?^aa:\b(?^aax: (?: 10[0-9A-F]{4} | [1-9A-F][0-9A-F]{4} | [0-9A-F]{4} ) \b))/;
+
+ # In the following hash, the keys are the bases of names which include
+ # the code point in the name, like CJK UNIFIED IDEOGRAPH-4E01. The value
+ # of each key is another hash which is used to get the low and high ends
+ # for each range of code points that apply to the name.
+ my %names_ending_in_code_point = (
+'CJK COMPATIBILITY IDEOGRAPH' =>
+{
+'high' =>
+[
+64109,
+64217,
+195101,
+],
+'low' =>
+[
+63744,
+64112,
+194560,
+],
+},
+'CJK UNIFIED IDEOGRAPH' =>
+{
+'high' =>
+[
+19893,
+40908,
+173782,
+177972,
+178205,
+],
+'low' =>
+[
+13312,
+19968,
+131072,
+173824,
+177984,
+],
+},
+
+ );
+
+ # The following hash is a copy of the previous one, except is for loose
+ # matching, so each name has blanks and dashes squeezed out
+ my %loose_names_ending_in_code_point = (
+'CJKCOMPATIBILITYIDEOGRAPH' =>
+{
+'high' =>
+[
+64109,
+64217,
+195101,
+],
+'low' =>
+[
+63744,
+64112,
+194560,
+],
+},
+'CJKUNIFIEDIDEOGRAPH' =>
+{
+'high' =>
+[
+19893,
+40908,
+173782,
+177972,
+178205,
+],
+'low' =>
+[
+13312,
+19968,
+131072,
+173824,
+177984,
+],
+},
+
+ );
+
+ # And the following array gives the inverse mapping from code points to
+ # names. Lowest code points are first
+ my @code_points_ending_in_code_point = (
+
+{
+'high' => 19893,
+'low' => 13312,
+'name' => 'CJK UNIFIED IDEOGRAPH',
+},
+{
+'high' => 40908,
+'low' => 19968,
+'name' => 'CJK UNIFIED IDEOGRAPH',
+},
+{
+'high' => 64109,
+'low' => 63744,
+'name' => 'CJK COMPATIBILITY IDEOGRAPH',
+},
+{
+'high' => 64217,
+'low' => 64112,
+'name' => 'CJK COMPATIBILITY IDEOGRAPH',
+},
+{
+'high' => 173782,
+'low' => 131072,
+'name' => 'CJK UNIFIED IDEOGRAPH',
+},
+{
+'high' => 177972,
+'low' => 173824,
+'name' => 'CJK UNIFIED IDEOGRAPH',
+},
+{
+'high' => 178205,
+'low' => 177984,
+'name' => 'CJK UNIFIED IDEOGRAPH',
+},
+{
+'high' => 195101,
+'low' => 194560,
+'name' => 'CJK COMPATIBILITY IDEOGRAPH',
+},
+,
+
+ );
+
+ # Convert from code point to Jamo short name for use in composing Hangul
+ # syllable names
+ my %Jamo = (
+4352 => 'G',
+4353 => 'GG',
+4354 => 'N',
+4355 => 'D',
+4356 => 'DD',
+4357 => 'R',
+4358 => 'M',
+4359 => 'B',
+4360 => 'BB',
+4361 => 'S',
+4362 => 'SS',
+4363 => '',
+4364 => 'J',
+4365 => 'JJ',
+4366 => 'C',
+4367 => 'K',
+4368 => 'T',
+4369 => 'P',
+4370 => 'H',
+4449 => 'A',
+4450 => 'AE',
+4451 => 'YA',
+4452 => 'YAE',
+4453 => 'EO',
+4454 => 'E',
+4455 => 'YEO',
+4456 => 'YE',
+4457 => 'O',
+4458 => 'WA',
+4459 => 'WAE',
+4460 => 'OE',
+4461 => 'YO',
+4462 => 'U',
+4463 => 'WEO',
+4464 => 'WE',
+4465 => 'WI',
+4466 => 'YU',
+4467 => 'EU',
+4468 => 'YI',
+4469 => 'I',
+4520 => 'G',
+4521 => 'GG',
+4522 => 'GS',
+4523 => 'N',
+4524 => 'NJ',
+4525 => 'NH',
+4526 => 'D',
+4527 => 'L',
+4528 => 'LG',
+4529 => 'LM',
+4530 => 'LB',
+4531 => 'LS',
+4532 => 'LT',
+4533 => 'LP',
+4534 => 'LH',
+4535 => 'M',
+4536 => 'B',
+4537 => 'BS',
+4538 => 'S',
+4539 => 'SS',
+4540 => 'NG',
+4541 => 'J',
+4542 => 'C',
+4543 => 'K',
+4544 => 'T',
+4545 => 'P',
+4546 => 'H',
+
+ );
+
+ # Leading consonant (can be null)
+ my %Jamo_L = (
+'' => 11,
+'B' => 7,
+'BB' => 8,
+'C' => 14,
+'D' => 3,
+'DD' => 4,
+'G' => 0,
+'GG' => 1,
+'H' => 18,
+'J' => 12,
+'JJ' => 13,
+'K' => 15,
+'M' => 6,
+'N' => 2,
+'P' => 17,
+'R' => 5,
+'S' => 9,
+'SS' => 10,
+'T' => 16,
+
+ );
+
+ # Vowel
+ my %Jamo_V = (
+'A' => 0,
+'AE' => 1,
+'E' => 5,
+'EO' => 4,
+'EU' => 18,
+'I' => 20,
+'O' => 8,
+'OE' => 11,
+'U' => 13,
+'WA' => 9,
+'WAE' => 10,
+'WE' => 15,
+'WEO' => 14,
+'WI' => 16,
+'YA' => 2,
+'YAE' => 3,
+'YE' => 7,
+'YEO' => 6,
+'YI' => 19,
+'YO' => 12,
+'YU' => 17,
+
+ );
+
+ # Optional trailing consonant
+ my %Jamo_T = (
+'B' => 17,
+'BS' => 18,
+'C' => 23,
+'D' => 7,
+'G' => 1,
+'GG' => 2,
+'GS' => 3,
+'H' => 27,
+'J' => 22,
+'K' => 24,
+'L' => 8,
+'LB' => 11,
+'LG' => 9,
+'LH' => 15,
+'LM' => 10,
+'LP' => 14,
+'LS' => 12,
+'LT' => 13,
+'M' => 16,
+'N' => 4,
+'NG' => 21,
+'NH' => 6,
+'NJ' => 5,
+'P' => 26,
+'S' => 19,
+'SS' => 20,
+'T' => 25,
+
+ );
+
+ # Computed re that splits up a Hangul name into LVT or LV syllables
+ my $syllable_re = qr/(|B|BB|C|D|DD|G|GG|H|J|JJ|K|M|N|P|R|S|SS|T)(A|AE|E|EO|EU|I|O|OE|U|WA|WAE|WE|WEO|WI|YA|YAE|YE|YEO|YI|YO|YU)(B|BS|C|D|G|GG|GS|H|J|K|L|LB|LG|LH|LM|LP|LS|LT|M|N|NG|NH|NJ|P|S|SS|T)?/;
+
+ my $HANGUL_SYLLABLE = "HANGUL SYLLABLE ";
+ my $loose_HANGUL_SYLLABLE = "HANGULSYLLABLE";
+
+ # These constants names and values were taken from the Unicode standard,
+ # version 5.1, section 3.12. They are used in conjunction with Hangul
+ # syllables
+ my $SBase = 0xAC00;
+ my $LBase = 0x1100;
+ my $VBase = 0x1161;
+ my $TBase = 0x11A7;
+ my $SCount = 11172;
+ my $LCount = 19;
+ my $VCount = 21;
+ my $TCount = 28;
+ my $NCount = $VCount * $TCount;
+
+ sub name_to_code_point_special {
+ my ($name, $loose) = @_;
+
+ # Returns undef if not one of the specially handled names; otherwise
+ # returns the code point equivalent to the input name
+ # $loose is non-zero if to use loose matching, 'name' in that case
+ # must be input as upper case with all blanks and dashes squeezed out.
+
+ if ((! $loose && $name =~ s/$HANGUL_SYLLABLE//)
+ || ($loose && $name =~ s/$loose_HANGUL_SYLLABLE//))
+ {
+ return if $name !~ qr/^$syllable_re$/;
+ my $L = $Jamo_L{$1};
+ my $V = $Jamo_V{$2};
+ my $T = (defined $3) ? $Jamo_T{$3} : 0;
+ return ($L * $VCount + $V) * $TCount + $T + $SBase;
+ }
+
+ # Name must end in 'code_point' for this to handle.
+ return if (($loose && $name !~ /^ (.*?) ($run_on_code_point_re) $/x)
+ || (! $loose && $name !~ /^ (.*) ($code_point_re) $/x));
+
+ my $base = $1;
+ my $code_point = CORE::hex $2;
+ my $names_ref;
+
+ if ($loose) {
+ $names_ref = \%loose_names_ending_in_code_point;
+ }
+ else {
+ return if $base !~ s/-$//;
+ $names_ref = \%names_ending_in_code_point;
+ }
+
+ # Name must be one of the ones which has the code point in it.
+ return if ! $names_ref->{$base};
+
+ # Look through the list of ranges that apply to this name to see if
+ # the code point is in one of them.
+ for (my $i = 0; $i < scalar @{$names_ref->{$base}{'low'}}; $i++) {
+ return if $names_ref->{$base}{'low'}->[$i] > $code_point;
+ next if $names_ref->{$base}{'high'}->[$i] < $code_point;
+
+ # Here, the code point is in the range.
+ return $code_point;
+ }
+
+ # Here, looked like the name had a code point number in it, but
+ # did not match one of the valid ones.
+ return;
+ }
+
+ sub code_point_to_name_special {
+ my $code_point = shift;
+
+ # Returns the name of a code point if algorithmically determinable;
+ # undef if not
+
+ # If in the Hangul range, calculate the name based on Unicode's
+ # algorithm
+ if ($code_point >= $SBase && $code_point <= $SBase + $SCount -1) {
+ use integer;
+ my $SIndex = $code_point - $SBase;
+ my $L = $LBase + $SIndex / $NCount;
+ my $V = $VBase + ($SIndex % $NCount) / $TCount;
+ my $T = $TBase + $SIndex % $TCount;
+ $name = "$HANGUL_SYLLABLE$Jamo{$L}$Jamo{$V}";
+ $name .= $Jamo{$T} if $T != $TBase;
+ return $name;
+ }
+
+ # Look through list of these code points for one in range.
+ foreach my $hash (@code_points_ending_in_code_point) {
+ return if $code_point < $hash->{'low'};
+ if ($code_point <= $hash->{'high'}) {
+ return sprintf("%s-%04X", $hash->{'name'}, $code_point);
+ }
+ }
+ return; # None found
+ }
+} # End closure
+
+1;
@@ -4,7 +4,7 @@ use strict;
use DateTime;
use DateTime::Set;
-our $VERSION = "0.20";
+our $VERSION = "1.00";
RT->AddStyleSheets('calendar.css');
@@ -103,36 +103,13 @@ sub SearchDefaultCalendar {
}
}
-package RT::Interface::Web::Menu;
-
-# we should get an add_after method in 4.0.6 (hopefully), but until then
-# shim this in so I don't copy the code.
-unless (RT::Interface::Web::Menu->can('add_after')) {
- *RT::Interface::Web::Menu::add_after = sub {
- my $self = shift;
- my $parent = $self->parent;
- my $sort_order;
- for my $contemporary ($parent->children) {
- if ( $contemporary->key eq $self->key ) {
- $sort_order = $contemporary->sort_order + 1;
- next;
- }
- if ( $sort_order ) {
- $contemporary->sort_order( $contemporary->sort_order + 1 );
- }
- }
- $parent->child( @_, sort_order => $sort_order );
- };
-}
-
-
1;
__END__
=head1 NAME
-RTx::Calendar - Calendar for RT due tasks
+RTx::Calendar - Calendar for RT due dates
=head1 DESCRIPTION
@@ -142,104 +119,88 @@ the menu Search->Calendar.
There's a portlet to put on your home page (see Prefs/MyRT.html)
-You can also enable ics (ICal) feeds for your default calendar and all
-your private searches in Prefs/Calendar.html. Authentication is magic
-number based so that you can give those feeds to other people.
-
=head1 INSTALLATION
-If you upgrade from 0.02, see next part before.
+=over
-You need to install those two modules :
+=item C<perl Makefile.PL>
- * Data::ICal
- * DateTime::Set
+=item C<make>
-Install it like a standard perl module
+=item C<make install>
- perl Makefile.PL
- make
- make install
+May need root permissions
-If your RT is not in the default path (/opt/rt3) you must set RTHOME
-before doing the Makefile.PL
+=item Edit your F</opt/rt4/etc/RT_SiteConfig.pm>
-=head1 CONFIGURATION
+If you are using RT 4.2 or greater, add this line:
-=head2 Base configuration
+ Plugin('RTx::Calendar');
-In RT 3.8 and later, to enable calendar plugin, you must add something
-like that in your etc/RT_SiteConfig.pm :
+For RT 4.0, add this line:
- Set(@Plugins,(qw(RTx::Calendar)));
+ Set(@Plugins, qw(RTx::Calendar));
-To use MyCalendar portlet you must add MyCalendar to
-$HomepageComponents in etc/RT_SiteConfig.pm like that :
+or add C<RTx::Calendar> to your existing C<@Plugins> line.
+
+=item Clear your mason cache
+
+ rm -rf /opt/rt4/var/mason_data/obj
+
+=item Restart your webserver
+
+=back
+
+=head1 CONFIGURATION
+
+=head2 Base configuration
+
+To use the C<MyCalendar> portlet, you must add C<MyCalendar> to
+C<$HomepageComponents> in F<etc/RT_SiteConfig.pm>:
Set($HomepageComponents, [qw(QuickCreate Quicksearch MyCalendar
MyAdminQueues MySupportQueues MyReminders RefreshHomepage)]);
-To enable private searches ICal feeds, you need to give
-CreateSavedSearch and LoadSavedSearch rights to your users.
-
=head2 Display configuration
You can show the owner in each day box by adding this line to your
-etc/RT_SiteConfig.pm :
+F<etc/RT_SiteConfig.pm>:
Set($CalendarDisplayOwner, 1);
You can change which fields show up in the popup display when you
-mouse over a date in etc/RT_SiteConfig.pm :
+mouse over a date in F<etc/RT_SiteConfig.pm>:
- @CalendarPopupFields = ('Status', 'OwnerObj->Name', 'DueObj->ISO');
-
-=head2 ICAL feed configuration
-
-By default, tickets are todo and reminders event. You can change this
-by setting $RT::ICalTicketType and $RT::ICalReminderType in etc/RT_SiteConfig.pm :
-
- Set($ICalTicketType, "Data::ICal::Entry::Event");
- Set($ICalReminderType ,"Data::ICal::Entry::Todo");
+ Set(@CalendarPopupFields, ('Status', 'OwnerObj->Name', 'DueObj->ISO'));
=head1 USAGE
A small help section is available in /Prefs/Calendar.html
-=head1 UPGRADE FROM 0.02
+=head1 AUTHOR
-As I've change directory structure, if you upgrade from 0.02 you need
-to delete old files manually. Go in RTHOME/share/html (by default
-/opt/rt3/share/html) and delete those files :
+Best Practical Solutions, LLC E<lt>modules@bestpractical.comE<gt>
- rm -rf Callbacks/RTx-Calendar
- rm Tools/Calendar.html
-
-RTx-Calendar may work without this but it's not very clean.
+Originally written by Nicolas Chuche E<lt>nchuche@barna.beE<gt>
=head1 BUGS
-All bugs should be reported via
-L<http://rt.cpan.org/Public/Dist/Display.html?Name=RTx-Calendar>
-or L<bug-RTx-Calendar@rt.cpan.org>.
-
-=head1 AUTHORS
+All bugs should be reported via email to
-Best Practical Solutions
+ L<bug-RTx-Calendar@rt.cpan.org|mailto:bug-RTx-Calendar@rt.cpan.org>
-Nicolas Chuche E<lt>nchuche@barna.beE<gt>
+or via the web at
-Idea borrowed from redmine's calendar (Thanks Jean-Philippe).
+ L<rt.cpan.org|http://rt.cpan.org/Public/Dist/Display.html?Name=RTx-Calendar>.
-=head1 COPYRIGHT
+=head1 LICENSE AND COPYRIGHT
-Copyright 2007-2009 by Nicolas Chuche E<lt>nchuche@barna.beE<gt>
+This software is Copyright (c) 2010-2014 by Best Practical Solutions
-Copyright 2010-2014 by Best Practical Solutions.
+Copyright 2007-2009 by Nicolas Chuche
-This program is free software; you can redistribute it and/or
-modify it under the same terms as Perl itself.
+This is free software, licensed under:
-See L<http://www.perl.com/perl/misc/Artistic.html>
+ The GNU General Public License, Version 2, June 1991
=cut