summaryrefslogtreecommitdiff
path: root/rt/docs
diff options
context:
space:
mode:
Diffstat (limited to 'rt/docs')
-rw-r--r--rt/docs/UPGRADING-3.810
-rw-r--r--rt/docs/UPGRADING-4.020
-rw-r--r--rt/docs/UPGRADING-4.2337
-rw-r--r--rt/docs/authentication.pod168
-rw-r--r--rt/docs/automating_rt.pod234
-rw-r--r--rt/docs/backups.pod106
-rw-r--r--rt/docs/charts.pod246
-rw-r--r--rt/docs/customizing/approvals.pod6
-rw-r--r--rt/docs/customizing/articles_introduction.pod21
-rw-r--r--rt/docs/customizing/styling_rt.pod46
-rw-r--r--rt/docs/customizing/templates.pod56
-rw-r--r--rt/docs/dashboards.pod206
-rw-r--r--rt/docs/extending/clickable_links.pod1
-rw-r--r--rt/docs/extending/external_custom_fields.pod10
-rw-r--r--rt/docs/extensions.pod102
-rw-r--r--rt/docs/full_text_indexing.pod157
-rw-r--r--rt/docs/hacking.pod12
-rw-r--r--rt/docs/initialdata.pod85
-rw-r--r--rt/docs/reminders.pod67
-rw-r--r--rt/docs/rt_perl.pod163
-rw-r--r--rt/docs/schema.dot7
-rw-r--r--rt/docs/security.pod6
-rw-r--r--rt/docs/web_deployment.pod67
-rw-r--r--rt/docs/writing_extensions.pod376
24 files changed, 2338 insertions, 171 deletions
diff --git a/rt/docs/UPGRADING-3.8 b/rt/docs/UPGRADING-3.8
index ba7177764..9c3f93fca 100644
--- a/rt/docs/UPGRADING-3.8
+++ b/rt/docs/UPGRADING-3.8
@@ -7,13 +7,13 @@ authentication itself, it may still store these weak password hashes -- using
ExternalAuth does not guarantee that you are not vulnerable! To upgrade
stored passwords to a stronger hash, run:
- perl etc/upgrade/vulnerable-passwords
+ /opt/rt4/etc/upgrade/vulnerable-passwords
We have also proved that it's possible to delete a notable set of records from
Transactions table without losing functionality. To delete these records, run
the following script:
- perl -I /opt/rt4/local/lib -I /opt/rt4/lib etc/upgrade/shrink_transactions_table.pl
+ /opt/rt4/etc/upgrade/shrink-transactions-table
If you chose not to run the shrink_cgm_table.pl script when you upgraded to
3.8, you should read more about it below and run it at this point.
@@ -63,7 +63,7 @@ Custom fields with categories can optionally be split out into hierarchical
custom fields. If you wish to convert your old category-based custom fields,
run:
- perl etc/upgrade/split-out-cf-categories
+ /opt/rt4/etc/upgrade/split-out-cf-categories
It will prompt you for each custom field with categories that it finds, and
the name of the custom field to create to store the categories.
@@ -138,7 +138,7 @@ CachedGroupMembers table without losing functionality; in fact, failing to do
so may result in occasional problems where RT miscounts users, particularly in
the chart functionality. To delete these records run the following script:
- perl -I /opt/rt4/local/lib -I /opt/rt4/lib etc/upgrade/shrink_cgm_table.pl
+ /opt/rt4/etc/upgrade/shrink-cgm-table
After you run this, you will have significantly reduced the number of records
in your CachedGroupMembers table, and may need to tell your database to
@@ -174,7 +174,7 @@ RT::Action::LinearEscalate extension has been integrated into core, so you
MUST uninstall it before upgrading.
RT::Extension::iCal has been integrated into core, so you MUST uninstall it
-before upgrading. In addition, you must run etc/upgrade/3.8-ical-extension
+before upgrading. In addition, you must run /opt/rt4/etc/upgrade/3.8-ical-extension
script to convert old data.
diff --git a/rt/docs/UPGRADING-4.0 b/rt/docs/UPGRADING-4.0
index 766964f42..0a3249c3f 100644
--- a/rt/docs/UPGRADING-4.0
+++ b/rt/docs/UPGRADING-4.0
@@ -1,5 +1,8 @@
=head1 UPGRADING FROM BEFORE 4.0.0
+See F<devel/docs/UPGRADING-4.0> for internals changes relevant to
+extension writers. The following is tailored to RT administrators:
+
=head2 Common issues
RT now defaults to a database name of rt4 and an installation root of
@@ -34,7 +37,8 @@ new configuration.
RT::Extension::CustomField::Checkbox has been integrated into core, so you
MUST uninstall it before upgrading. In addition, you must run
-etc/upgrade/4.0-customfield-checkbox-extension script to convert old data.
+/opt/rt4/etc/upgrade/4.0-customfield-checkbox-extension script to convert old
+data.
=head2 RT_SiteConfig.pm
@@ -60,7 +64,7 @@ the new schema.
RT4 now includes an Articles functionality, merged from RTFM. You should not
install and enable the RT::FM plugin separately on RT 4. If you have existing
-data in RTFM, you can use the etc/upgrade/upgrade-articles script to upgrade
+data in RTFM, you can use the /opt/rt4/etc/upgrade/upgrade-articles script to upgrade
that data.
When running normal upgrade scripts, RT will warn if it finds existing RTFM
@@ -73,7 +77,7 @@ spectacularly. Do *not* run this except on a fresh upgrade of RT.
You can run this as
- etc/upgrade/upgrade-articles
+ /opt/rt4/etc/upgrade/upgrade-articles
It will ouput a lot of data about what it is changing. You should review this
for errors.
@@ -84,14 +88,6 @@ to RT4.
You must also remove RT::FM from your @Plugins line in RT_SiteConfig.pm.
-
-=head2 Removals and updates
-
-The deprecated classes RT::Action::Generic, RT::Condition::Generic and
-RT::Search::Generic have been removed, but you shouldn't have been using them
-anyway. You should have been using RT::Action, RT::Condition and RT::Search,
-respectively.
-
=over
=item *
@@ -245,7 +241,7 @@ version of DBD::Pg RT will stop the upgrade during the 3.9.8 step and
remind you to upgrade DBD::Pg. If this happens, you can re-start your
upgrade by running:
- ./sbin/rt-setup-database --action insert --datadir etc/upgrade/3.9.8/
+ /opt/rt4/sbin/rt-setup-database --action insert --datadir etc/upgrade/3.9.8/
Followed by re-running make upgrade-database and answering 3.9.8 when
prompted for which RT version you're upgrading from.
diff --git a/rt/docs/UPGRADING-4.2 b/rt/docs/UPGRADING-4.2
new file mode 100644
index 000000000..76aa96d15
--- /dev/null
+++ b/rt/docs/UPGRADING-4.2
@@ -0,0 +1,337 @@
+=head1 UPGRADING FROM RT 4.0.0 and greater
+
+The 4.2 release is a major upgrade and as such there are more changes
+than in a minor bugfix release (e.g., 4.0.13 to 4.0.14) and some of these
+changes are backward-incompatible. The following lists some of the notable
+changes, especially those that might require you to change a configuration
+option or other setting due to a change in RT. Read this section carefully
+before you upgrade and look for changes to features you currently use.
+
+See F<devel/docs/UPGRADING-4.0> for internals changes relevant to
+extension writers.
+
+=over
+
+=item *
+
+The L<RT_Config/$UseSQLForACLChecks> option defaults to on. This provides
+a number of improvements, most notably no longer showing pages of empty results
+if the user doesn't have permissions to view the tickets in question.
+It may, in some cases, have performance impacts, but these have been
+found to be minimal in existing 4.0 installs.
+
+=item *
+
+The C<$LogToScreen> config setting is now named
+L<< "C<$LogToSTDERR>"|RT_Config/"$LogToSyslog, $LogToSTDERR" >> which
+better describes what the log level controls. Setting C<$LogToScreen> will
+still work, but an informational notice will be issued on server start telling
+you about the rename. To avoid this you should set C<$LogToSTDERR> instead.
+
+=item *
+
+C<$LinkTransactionsRun1Scrip> is removed. If you were relying on this behavior
+(by setting it to 1), you should adjust your scrips to ignore one of the link
+transactions.
+
+=item *
+
+The C<$AttachmentUnits> option was removed in preference of always displaying in
+megabytes, kilobytes, or bytes as appropriate. The option was incompletely
+implemented and controlled display in the attachments list but not history.
+
+=item *
+
+C<$MessageBoxWrap> was removed. Wrapping is now always C<SOFT>. If you want hard
+line breaks, enter them manually.
+
+=item *
+
+Rich text (HTML) messages are now preferred for display. If you prefer plain
+text messages, set L<RT_Config/$PreferRichText> to 0.
+
+=item *
+
+User email addresses are now validated by default and multiple,
+comma-separated addresses for a single user are no longer allowed. Existing
+users with invalid addresses will continue to work until the next time they
+are updated by an administrator on the modify user page. If you prefer no
+address validation, set L<RT_Config/$ValidateUserEmailAddresses> to 0.
+
+=item *
+
+The C<smtp> option for L<RT_Config/$MailCommand>, along with the associated
+C<$SMTPServer>, C<$SMTPFrom>, and C<$SMTPDebug> options, has been removed
+because it did not guarantee delivery. Instead, use a local MTA for
+outgoing mail, via the 'sendmailpipe' setting to C<$MailCommand>.
+
+=item *
+
+The L<RT_Config/@JSFiles> config now only keeps additional JavaScript filenames; if
+you had copied C<@JSFiles> to add extra entries in your C<RT_SiteConfig.pm>,
+remove the core JS from the list, or RT will serve those files
+multiple times.
+
+=item *
+
+The C<$DeferTransactionLoading> option was combined into the new option
+L<RT_Config/$ShowHistory>. If you had enabled C<$DeferTransactionLoading>,
+you may want to set C<$ShowHistory> to C<click>. However, C<$ShowHistory>
+provides a new mode, C<delay>, which is the default and may be a more
+appealing alternative to C<click>.
+
+=item *
+
+A C<Status> transaction is now recorded when a ticket status changes as a
+result of a queue change. Scrips with conditions relying on Status changes
+may start to trigger on these transitions; previously these Status changes
+never triggered scrips.
+
+=item *
+
+The C<Googleish> search has been renamed to C<Simple>. If you were
+using this in an L<< C<rt-crontool> >> cronjob or had used a
+C<Googleish_Local.pm> to add features, you will need to convert to
+using L<RT::Search::Simple> instead.
+
+=item *
+
+On merge, RT retains transactions from both tickets. Previously, RT
+also recorded explicit time change transactions during a
+merge to adjust the total time spent. This caused the total time
+spent, as summed from transactions, to be different from the ticket's
+overall time spent. This has been fixed: time is adjusted during the
+merge commit itself, removing the need for the confusing
+extra transactions, and keeping the summed time spent consistent.
+
+In order to fix the history records of old ticket you can run the following
+command:
+
+ /opt/rt4/etc/upgrade/time-worked-history
+
+This command deletes records from the Transactions table. This script can only fix
+TimeWorked mismatches, but not TimeLeft or TimeEstimated.
+
+=item *
+
+A new action, "Open Inactive Tickets", has been added, and on new
+installs the default scrip "On Correspond Open Tickets" has been
+replaced by "On Correspond Open Inactive Tickets". The key difference
+between "Open Tickets" and "Open Inactive Tickets" is that the latter
+will not adjust the status of a ticket if it is already active. This
+is particularly useful when creating complex workflows using
+Lifecycles.
+
+=item *
+
+There are now HTML versions of the standard plain text templates. Running
+make upgrade as described in the F<README> will insert the new templates into
+existing installs. While new installs use the HTML templates by default,
+upgrades from older versions don't automatically switch to the HTML versions.
+To switch existing scrips, run:
+
+ /opt/rt4/etc/upgrade/switch-templates-to html
+
+To switch from HTML back to text, run:
+
+ /opt/rt4/etc/upgrade/switch-templates-to text
+
+=item *
+
+The Articles menu is now a top-level menu item and display is controlled by
+the right C<ShowArticlesMenu>. This right is only grantable globally to groups
+or users. During the upgrade, the new right will be automatically granted to
+Privileged users so that the menu doesn't disappear for anyone previously
+using it. You may wish to revoke the right from Privileged and grant it
+more selectively.
+
+=item *
+
+The Owner drop-down now only includes privileged users (no matter if
+unprivileged users have been granted the OwnTicket right) because
+configurations which have unprivileged Owners are exceedingly rare,
+and granting Everyone the OwnTicket right is a common cause of
+performance problems. Unprivileged Owners (if they exist) may still
+be set using the Autocompleter.
+
+=item *
+
+The functionality that changed the ticket status to Open when the Started
+date is set has been moved to a Scrip called 'On transaction and SetStarted
+Open Ticket'. If you do not depend on this functionality, the Scrip can
+be deleted.
+
+=item *
+
+New installs will notify Ccs and one-time Ccs/Bccs on create and Owners on
+create and correspond. Upgraded installations will not. If you'd like to
+adjust your scrips to match the new install behavior, create and edit the
+following scrips from the admin scrip page:
+
+To notify Ccs on create, on the 'Create a global scrip' page:
+
+ Description: On Create Notify Ccs
+ Condition: On Create
+ Action: Notify Ccs
+ Template: Correspondence in HTML
+
+To notify one-time Ccs/Bccs on create, on the 'Create a global scrip' page:
+
+ Description: On Create Notify Other Recipients
+ Condition: On Create
+ Action: Notify Other Recipients
+ Template: Correspondence in HTML
+
+To notify Owners on create, click 'On Create Notify AdminCcs'. Change the
+fields listed below to their corresponding values:
+
+ Description: On Create Notify Owner and AdminCcs
+ Action: Notify Owner and AdminCcs
+
+To notify Owners on correspond, click 'On Correspond Notify AdminCcs'. Change
+the fields listed below to their corresponding values:
+
+ Description: On Correspond Notify Owner and AdminCcs
+ Action: Notify Owner and AdminCcs
+
+=item *
+
+Notifications to AdminCcs on approvals are now handled via the New Pending
+Approval template in the hidden ___Approvals queue. If you customized the
+Transaction template, you should port your changes to New Pending Approval.
+
+=item *
+
+On Oracle, sessions are now stored in the database by default instead of
+on-disk. If you wish to preserve the original behavior, ensure that
+L<RT_Config/$WebSessionClass> is set in your C<RT_SiteConfig.pm>:
+
+ Set($WebSessionClass, "Apache::Session::File");
+
+=item *
+
+Configuration options dealing with "external authentication" have been
+renamed to reduce confusion with the common extension
+L<RT::Authen::ExternalAuth>. The old names will work, but produce
+deprecation warnings. The old names, and their new counterparts, are:
+
+ WebExternalAuth => WebRemoteUserAuth
+ WebExternalAuthContinuous => WebRemoteUserContinuous
+ WebFallbackToInternalAuth => WebFallbackToRTLogin
+ WebExternalGecos => WebRemoteUserGecos
+ WebExternalAuto => WebRemoteUserAutocreate
+ AutoCreate => UserAutocreateDefaultsOnLogin
+
+=item *
+
+Due to many long-standing bugs and limitations, the "Offline Tool" was
+removed.
+
+=item *
+
+To increase security against offline brute-force attacks, RT's default
+password encryption has been switched to the popular bcrypt() key
+derivation function. Passwords cannot be automatically bulk upgraded to
+the new format, but will be replaced with bcrypt versions upon the first
+successful login.
+
+=item *
+
+We updated default "Forward" and "Forward Ticket" templates to support
+customizing messages on forward. They will be updated automatically if you
+didn't change them before.
+
+But in case you have changed them already, you need to update them manually.
+You can use $ForwardTransaction to refer to the customized message in the
+templates, e.g. "Forward" template could be updated to:
+
+{ $ForwardTransaction->Content =~ /\S/ ? $ForwardTransaction->Content : "This is a forward of transaction #".$Transaction->id." of ticket #". $Ticket->id }
+
+=item *
+
+RT has generated RT-Ticket: RT-Originator: and Managed-By: headers in
+compliance with RFC2822/6648 but we've discovered that some smarthost
+providers are requiring strict adherence to RFC822 which mandates X-
+prefixes on these headers. We've made this change in 4.2 for users
+relying on those providers.
+
+Any external scripts which were parsing on these RT mail headers will
+need to be updated.
+
+=item *
+
+GnuPG and S/MIME are no longer enabled in F<RT_Config.pm> merely by the
+presence of the C<gpg> or C<openssl> binaries. Systems which depended
+on C<configure> enabling these in F<RT_Config.pm> implicitly will need
+to pass C<--enable-gpg> to C<configure>, or alter their
+C<RT_SiteConfig.pm> to enable the functionality explicitly.
+
+=item *
+
+In TicketSQL, "Starts = '1970-01-01'" will no longer find tickets with
+no Starts date set. Instead, use "Starts IS NULL". As a direct
+consequence, "Starts < 'today'" will no longer also find tickets with no
+Starts date; use "Starts < 'today' OR Starts IS NULL" to have the
+equivalent results in RT 4.2.
+
+=back
+
+=head1 UPGRADING FROM 4.2.3 AND EARLIER
+
+RT 4.2.4's upgrade scripts contain two fixes to normalize upgraded RTs
+with those installed new from a release of RT 4.2.
+
+We neglected to add the "Open Inactive Tickets" action mentioned earlier
+in this documents. It was available to fresh installs but not on
+upgrades. This Scrip Action is now created if needed.
+
+RT expects the ___Approvals queue to have a special value in the
+Disabled column so that it is hidden B<but> tickets can still be created
+(normal disabled Queues disallow ticket creation). Users who enabled
+and then disabled the Queue on earlier releases will have the incorrect
+Disabled value, so we fix that. A similar problem applies to the
+lifecycle, which must be set to the internal "approvals" lifecycle --
+which is not listed as an option. RT 4.2.4 also includes enhancements
+to the Queue admin page for ___Approvals to prevent editing things which
+might cause problems.
+
+=head1 UPGRADING FROM 4.2.5 AND EARLIER
+
+RT 4.2.6 includes a new Scrip Action "Notify Owner or AdminCc". This
+action will send the given correspondence to the Owner, if not Nobody,
+otherwise it will notify the AdminCcs. If using this, you will likely
+want to modify or remove the Notify Owner and AdminCcs scrip to avoid
+duplicate notifications. This Scrip Action is not used in any default
+Scrips at this time.
+
+=head1 UPGRADING FROM 4.2.6 AND EARLIER
+
+The C<$LogoImageHeight> and C<$LogoImageWidth> configuration options
+have been overridden by CSS since 4.0.0, and thus did not affect
+display. They have been removed, and setting them will trigger an
+informational message that setting them is ineffective.
+
+=head1 UPGRADING FROM 4.2.9 AND EARLIER
+
+An additional optional dependency, L<HTML::FormatExternal>, has been
+added. This allows RT to use C<w3m>, C<elinks>, C<html2text>, or other
+external tools to render HTML to text. This dependency is not installed
+by default; however, its use is strongly encouraged, and will resolve
+issues with blank outgoing emails.
+
+=head1 UPGRADING FROM 4.2.10 AND EARLIER
+
+The C<$DatabaseRequireSSL> option has never affected whether the
+database connection was performed using SSL, even under Postgres; the
+functionality can now be implemented via C<%DatabaseExtraDSN>.
+C<$DatabaseRequireSSL> has been removed, and setting it will trigger an
+informational message that setting it is ineffective.
+
+The full-text indexing defaults for PostgreSQL have changed; GiST is now
+the suggested index, as well as storing data in a separate
+AttachmentsIndex table. Both changes improve lookup speed. For
+improved search performance, you may wish to drop existing C<tsvector>
+and C<GIN> indexes on C<Attachments>, and re-generate the index using
+C<rt-setup-fulltext-index>.
+
+=cut
diff --git a/rt/docs/authentication.pod b/rt/docs/authentication.pod
new file mode 100644
index 000000000..26599cd6e
--- /dev/null
+++ b/rt/docs/authentication.pod
@@ -0,0 +1,168 @@
+=encoding utf-8
+
+=head1 RT Authentication
+
+RT allows for several different ways to authenticate users including an
+internal user management system and a number of ways to integrate with existing
+authentication systems.
+
+=head1 Internal Authentication
+
+RT's native internal authentication system provides administration tools to
+manage usernames and passwords. If you plan to run your RT as a stand-alone
+system and don't need to use accounts associated with any other system, this
+may be all you need. The administration pages under Admin → Users
+provide new user creation as well as password setting and control of RT's
+privileged flag for existing users.
+
+=head1 External Authentication
+
+There are two primary types of external authentication: in one you type your
+username and password into RT's login form, and in the other your web server
+(such as Apache) handles authentication, often seamlessly, and tells RT the
+user logged in.
+
+The second is supported by RT out of the box under the configuration option
+C<$WebRemoteUserAuth> and other related options. The first is supported by an RT
+extension named L</RT::Authen::ExternalAuth>. These two types may be used
+independently or together, and both can fallback to RT's internal
+authentication.
+
+No matter what type of external authentication you use, RT still maintains user
+records in its database that correspond to your external source. This is
+necessary so RT can link tickets, groups, rights, dashboards, etc. to users.
+
+All that is necessary for integration with external authentication systems is a
+shared username or email address. However, in RT you may want to leverage
+additional information from your external source. Synchronization of users,
+user data, and groups is provided by an extension named
+L</RT::Extension::LDAPImport>. It uses an external LDAP source, such an
+OpenLDAP or Active Directory server, as the authoritative repository and keeps
+RT up to date accordingly. This can be used in tandem with any of the external
+authentication options as it does not provide any authentication itself.
+
+=head2 Via your web server, aka C<$WebRemoteUserAuth>, aka C<REMOTE_USER>
+
+This type of external authentication is built-in to RT and bypasses the RT
+login form. Instead, RT defers authentication to the web server which is
+expected to set a C<REMOTE_USER> environment variable. Upon a request, RT
+checks the value of C<REMOTE_USER> against its internal database and logs in
+the matched user.
+
+It is often used to provide single sign-on (SSO) support via Apache modules
+such as C<mod_auth_kerb> (to talk to Active Directory). C<$WebRemoteUserAuth> is
+widely used by organizations with existing authentication standards for web
+services that leverge web server modules for central authentication services.
+The flexibility of RT's C<$WebRemoteUserAuth> support means that it can be setup
+with almost any authentication system.
+
+In order to keep user data in sync, this type of external auth is almost always
+used in combination with one or both of L</RT::Authen::ExternalAuth> and
+L</RT::Extension::LDAPImport>.
+
+=head3 Apache configuration
+
+When configuring Apache to protect RT, remember that the RT mail gateway
+uses the web interface to upload the incoming email messages. You will
+thus need to provide an exception for the mail gateway endpoint.
+
+An example of using LDAP authentication and HTTP Basic auth:
+
+ <Location />
+ Require valid-user
+ AuthType Basic
+ AuthName "RT access"
+ AuthBasicProvider ldap
+ AuthLDAPURL \
+ "ldap://ldap.example.com/dc=example,dc=com"
+ </Location>
+ <Location /REST/1.0/NoAuth/mail-gateway>
+ <IfVersion >= 2.4> # For Apache 2.4
+ Require local
+ </IfVersion>
+ <IfVersion < 2.4> # For Apache 2.2
+ Order deny,allow
+ Deny from all
+ Allow from localhost
+ Satisfy any
+ </IfVersion>
+ </Location>
+
+
+=head3 RT configuration options
+
+All of the following options control the behaviour of RT's built-in external
+authentication which relies on the web server. They are documented in detail
+under the "Authorization and user configuration" section of C<etc/RT_Config.pm>
+and you can read the documentation by running C<perldoc /opt/rt4/etc/RT_Config.pm>.
+
+The list below is meant to make you aware of what's available. You should read
+the full documentation as described above.
+
+=head4 C<$WebRemoteUserAuth>
+
+Enables or disables RT's expectation that the web server will provide
+authentication using the C<REMOTE_USER> environment variable.
+
+=head4 C<$WebRemoteUserContinuous>
+
+Check C<REMOTE_USER> on every request rather than the initial request.
+
+When this is off, users will remain logged into RT even after C<REMOTE_USER> is
+no longer provided. This provides a separation of sessions, but it may not be
+desirable in all cases. For example, if a user logs out of the external
+authentication system their RT session will remain active unless
+C<$WebRemoteUserContinuous> is on.
+
+=head4 C<$WebFallbackToRTLogin>
+
+If true, allows internal logins as well as C<REMOTE_USER> by providing a login
+form if external authentication fails. This is useful to provide local admin
+access (usually as root) or self service access for people without external
+user accounts.
+
+=head4 C<$WebRemoteUserAutocreate>
+
+Enables or disables auto-creation of RT users when a new C<REMOTE_USER> is
+encountered.
+
+=head4 C<$UserAutocreateDefaultsOnLogin>
+
+Specifies the default properties of auto-created users.
+
+=head4 C<$WebRemoteUserGecos>
+
+Tells RT to compare C<REMOTE_USER> to the C<Gecos> field of RT users instead of
+the C<Name> field.
+
+=head2 Via RT's login form, aka RT::Authen::ExternalAuth
+
+L<RT::Authen::ExternalAuth> is an RT extension which provides authentication
+B<using> RT's login form. It can be configured to talk to an LDAP source (such
+as Active Directory), an external database, or an SSO cookie.
+
+The key difference between C<$WebRemoteUserAuth> and L<RT::Authen::ExternalAuth>
+is the use of the RT login form and what part of the system talks to your
+authentication source (your web server vs. RT itself).
+
+=head3 Info mode and Authentication mode
+
+There are two modes of operation in L<RT::Authen::ExternalAuth>: info and auth.
+Usually you want to configure both so that successfully authenticated users
+also get their information pulled and updated from your external source.
+
+Auth-only configurations are rare, and generally not as useful.
+
+Info-only configurations are commonly setup in tandem with C<$WebRemoteUserAuth>.
+This lets your web server handle authentication (usually for SSO) and
+C<RT::Authen::ExternalAuth> ensures user data is updated every time someone
+logs in.
+
+=head2 RT::Extension::LDAPImport
+
+L<RT::Extension::LDAPImport> provides no authentication, but is worth
+mentioning because it provides user data and group member synchronization from
+any LDAP source into RT. It provides a similar but more complete sync solution
+than L<RT::Authen::ExternalAuth> (which only updates upon login and doesn't
+handle groups). It may be used with either of RT's external authentication
+sources, or on it's own.
diff --git a/rt/docs/automating_rt.pod b/rt/docs/automating_rt.pod
new file mode 100644
index 000000000..11960c38b
--- /dev/null
+++ b/rt/docs/automating_rt.pod
@@ -0,0 +1,234 @@
+=head1 Automating Tasks in RT
+
+As RT tickets are created, worked on, and resolved, there are sometimes
+updates or notifications that have defined rules and could be automatic.
+These might include increasing ticket priority over time so tickets don't
+get lost, resolving old tickets that haven't had any activity for a period of
+time, or sending email notifications based on some ticket criteria like
+being 3 days old and still having a status of new.
+
+The tool for automating RT tasks is L<rt-crontool>. It's designed to be
+run from the cron scheduler and accepts a set of parameters that define
+what RT objects it should operate on and what it should do. The sections
+below describe some common L<rt-crontool> tasks as examples of the
+different ways you can automate tasks.
+
+All of the options for L<rt-crontool> are documented with the tool itself:
+
+ $ perldoc /opt/rt4/bin/rt-crontool
+
+and on the Best Practical web site.
+
+=head2 Running C<rt-crontool>
+
+As you'll see in the examples below, this tool gives full access to RT.
+To manage the scope of changes that could be performed by the tool, we
+recommended creating a dedicated unix user with limited privileges for
+this purpose. Then create a user in RT with just enough access to
+perform the changes you need to automate, and set the "Unix login" field
+of the RT user to the username of the unix user you created. See the
+L<rt-crontool> documentation for more information.
+
+=head2 Testing Tips
+
+When setting up a new automated crontool job, keep in mind that you might be
+modifying a large number of tickets, especially the first time you run it.
+Changes to tickets can trigger scrips just like the same change made via
+the user interface. For example, changing the status to resolved will trigger
+the 'On Resolve' scrips, which often means sending email. Depending on the
+modification, you could end up sending a lot of email or triggering other
+actions.
+
+You can test your TicketSQL search queries in the RT web interface
+(using the Advanced tab of ticket search), and use bulk update if you
+want to prepare things for your new automated job. You can also disable
+scrips which you wish to avoid, or turn off outgoing mail with the
+L<RT_Config.pm/"$MailCommand"> option. This can be useful if you want to
+clean up older tickets without sending notifications to requestors for
+tickets that were resolved years ago.
+
+To help with debugging, the C<--verbose> option will give you more output.
+The C<--log> option accepts all of the valid log levels for RT and allows
+you to change the logging level just for the automated job. While testing,
+it's often convenient to set:
+
+ --log debug
+
+to see what's happening.
+
+=head1 A Simple Search
+
+Starting with a simple example, this command performs a search and
+displays output, but doesn't do anything to the returned tickets.
+This can be useful for safely testing search criteria.
+
+ /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
+ --search-arg "Owner = 'root'" \
+ --action RT::Action \
+ --verbose \
+ --log debug
+
+The C<--search> argument sets the search module RT should use, in this
+case L<RT::Search::FromSQL> which processes TicketSQL. The second
+argument, C<--search-arg>, is the search query to use. These are
+the same queries you create in the RT search interface, so can use
+the RT web UI to refine your queries before setting up your job.
+
+The C<--action> argument is set to L<RT::Action> which is the base class
+for RT actions. Since this class doesn't perform any action itself, this
+command will just output the results of the TicketSQL search.
+
+=head1 Auto-resolve Aged Tickets
+
+You can auto-set status based on any criteria you can define in
+a TicketSQL statement. For example, this command will resolve all
+active tickets that haven't been acted on in a month or more:
+
+ /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
+ --search-arg "(Status != 'resolved' AND Status != 'rejected') \
+ AND LastUpdated <= '1 month ago'" \
+ --action RT::Action::SetStatus \
+ --action-arg resolved
+
+The search is similar to the previous example with a slightly more
+complicated search argument. Note that since LastUpdated is treated as
+a timestamp (which increases over time) C<LastUpdated <= '1 month ago'>
+means "the timestamp when it was updated is before the timestamp one
+month ago" and not "updated less than a month ago."
+
+The C<--action> in this case uses the L<RT::Action::SetStatus> module
+with an C<--action-arg> of C<resolved>. For each of the tickets
+returned from the search query, the status is set to resolved. When
+setting up automated tasks, you can use actions provided as part of RT,
+actions available from extensions, or actions you create yourself.
+
+As noted previously, the normal RT rules apply when running actions
+with L<rt-crontool>, so for this example applicable 'On Resolve'
+scrips will run. If a ticket has unresolved dependencies, it will
+log an error since tickets can't be resolved until dependencies are
+resolved. Also, the status argument must be valid for the lifecycle of
+the selected tickets, and the transition must be allowed.
+
+=head1 Commenting and Corresponding on a Ticket
+
+The following command records a comment on all tickets returned from the
+query -- in this case, tickets that are new and unowned after 3 days.
+
+ /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
+ --search-arg "Owner = 'Nobody' AND Status = 'new' \
+ AND Created < '3 days ago'" \
+ --action RT::Action::RecordComment \
+ --template 'Unowned tickets'
+
+The L<RT::Action::RecordComment> action does just that, it records a
+comment just like replying to a comment email or commenting in the
+RT UI. It uses the global RT template defined by C<--template>, so you
+could put whatever you like in that template. For example:
+
+ Subject: {$Ticket->id} new and unowned
+ RT-Send-Cc: support-backup@example.com
+
+ Ticket {$Ticket->id} is still new and unowned after 3 days!
+
+You can set up a similar command to send a reply rather than a comment
+using the L<RT::Action::RecordCorrespondence> module.
+
+=head1 Sending Notifications
+
+While the example above sends notifications as a side-effect of recording
+a comment, you can also send notifications directly.
+
+ /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
+ --search-arg "(Status != 'resolved' AND Status != 'rejected') \
+ AND Queue = 'Project Work'" \
+ --condition RT::Condition::Overdue \
+ --action RT::Action::NotifyGroup \
+ --action-arg 'project-manager@example.com' \
+ --template 'Overdue task'
+
+This example shows the C<--condition> argument and the
+L<RT::Condition::Overdue> module, which returns true if the current
+time (the time the cron job is running) is past the Due date on the
+ticket. Like the C<--action> argument, you can use conditions
+provided with RT, added from extensions, or conditions you have
+created.
+
+L<RT::Action::NotifyGroup>, despite the "Group" in the name, can accept a
+bare email address or list of addresses as the action argument and it will
+send mail to them. A combination of email addresses and group names separated
+by commas also works. RT usernames are valid unless they conflict with group
+names.
+
+The action sends email, but unlike comment and correspond above, it
+doesn't record a transaction in the ticket history.
+
+=head1 Escalating Priority
+
+RT has a built-in ticket priority system with priority values from
+0 to 99. Depending on how you configure your queues, you can set 1 as the
+top priority with lower numbers meaning more important, or 99 can be the
+top priority with higher numbers meaning more important. You can set this
+in your queue configuration at Tools -> Configuration -> Queues. On the queue
+configuration page, set "Priority starts at" and "Over time, priority moves
+toward".
+
+Whichever scheme you choose, RT's L<RT::Action::EscalatePriority> can
+escalate the priority over time so tickets that are closer to their due
+date and are still not resolved have priority escalated automatically.
+
+This command escalates tickets in a designated queue:
+
+ /opt/rt4/bin/rt-crontool --search RT::Search::ActiveTicketsInQueue \
+ --search-arg "General" \
+ --action RT::Action::EscalatePriority
+
+The C<--search-arg> is the name of the queue in which to escalate tickets.
+As shown in previous examples, you can also set your criteria using a
+TicketSQL query as well:
+
+ /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
+ --search-arg "(Status='new' OR Status='open') AND Due > 'Jan 1, 1970'" \
+ --action RT::Action::EscalatePriority
+
+This example will find new and open tickets in all queues, but will skip tickets
+with no explicit due dates set. Maybe you only want to bump the priority on tasks
+that have to be done by a certain date.
+
+L<RT::Action::LinearEscalate> is an alternative escalation module that
+handles the "Due date not set" condition for you. It also offers some
+configuration options to control whether a transaction is recorded on the
+ticket and whether LastUpdated is modified.
+
+=head1 Transactions
+
+Many actions and conditions are also used in RT in scrips and may require
+a transaction in addition to a ticket. For such cases, L<rt-crontool>
+provides a C<--transaction> argument to designate a transaction. Valid
+values are C<first>, C<last>, and C<all> and these are relative to the
+current ticket being processed. C<first> and C<last> are the first and
+last transaction on the ticket. Be careful with the C<all> option since
+it will run the action on all transactions for the ticket.
+
+Since actions and conditions can be used in different contexts, you
+may need to provide a transaction object even if it doesn't seem
+necessary for your automated job. If you're seeing errors about
+a missing transaction, setting C<--transaction> to C<first> or
+C<last> is usually safe and will resolve the error.
+
+You can also target specific transaction types with C<--transation-type>.
+This argument accepts one or more transaction types as a comma-separated
+list.
+
+Using these options together, you can set up a command that sets the
+appropriate transaction object for your conditions and actions. For
+example, if you had an action you wanted to perform based on the content
+of the last reply on stalled tickets, you could do something like:
+
+ /opt/rt4/bin/rt-crontool --search RT::Search::FromSQL \
+ --search-arg "Status = 'stalled' AND Queue = 'General'" \
+ --action RT::Action::CheckLastCorrespond \
+ --transaction last \
+ --transaction-type Correspond
+
+
+=cut
diff --git a/rt/docs/backups.pod b/rt/docs/backups.pod
index 648105c66..554336fb9 100644
--- a/rt/docs/backups.pod
+++ b/rt/docs/backups.pod
@@ -31,13 +31,9 @@ RT. :)
=head3 MySQL
- ( mysqldump rt4 --tables sessions --no-data; \
+ ( mysqldump rt4 --tables sessions --no-data --single-transaction; \
mysqldump rt4 --ignore-table rt4.sessions --single-transaction ) \
- | gzip > rt-`date +%Y%M%d`.sql.gz
-
-If you're using a MySQL version older than 4.1.2 (only supported on RT 3.8.x
-and older), you should be also pass the C<--default-character-set=binary>
-option to the second C<mysqldump> command.
+ | gzip > rt-`date +%Y%m%d`.sql.gz
The dump will be much faster if you can connect to the MySQL server over
localhost. This will use a local socket instead of the network.
@@ -50,11 +46,105 @@ you have more resources, you can also setup replication to a slave using binary
logs and backup from there as necessary. This not only duplicates the data,
but lets you take backups without putting load on your production server.
+=head4 Restoring from backups
+
+=over
+
+=item New Database Server (Catastrophic Failure)
+
+If you are starting fresh with a new database server (because your old
+one no longer works or because you want to set up a dev machine to
+test on) you will need to create a fresh database and database user
+for RT to use. RT can do that for you using:
+
+ /opt/rt4/sbin/rt-setup-database --action create,acl
+
+By default, this will create an rt4 database and an rt_user user. If
+you've specified a custom password in RT_SiteConfig.pm, RT will use
+that. Once the database and user exist, you can restore from your
+backup using:
+
+ gunzip -c rt-20141014.sql.gz | mysql -uroot -p rt4
+
+Changing -uroot -p as needed to access the database as a user with
+enough rights to handle creating tables.
+
+=item Restore over an existing database
+
+If something terrible happened this morning and you want to roll back to
+your backups, or if you want to update a dev server using your backups,
+this is straightforward on MySQL.
+
+ gunzip -c rt-20141014.sql.gz | mysql -uroot -p rt4
+
+MySQL will drop any existing tables before recreating and repopulating
+them. It will leave the database and the rt_user untouched. This is
+not suitable for restoring on a fresh database install since there will
+be no rt4 database or rt_user user.
+
+=back
+
=head3 PostgreSQL
( pg_dump rt4 --table=sessions --schema-only; \
pg_dump rt4 --exclude-table=sessions ) \
- | gzip > rt-`date +%Y%M%d`.sql.gz
+ | gzip > rt-`date +%Y%m%d`.sql.gz
+
+=head4 Restoring from backups
+
+=over
+
+=item New Database Server (Catastrophic Failure)
+
+If you are starting fresh with a new database server (because your old
+one no longer works or because you want to set up a dev machine to
+test on) you will need to create a fresh database and database user
+for RT to use. RT can do part of that for you using:
+
+ /opt/rt4/sbin/rt-setup-database --action create
+
+You will need to create the rt_user separately.
+
+ createuser -P rt_user
+
+This will prompt you for a password. You should ensure that it is the
+same password you have configured in RT_SiteConfig.pm or RT_Config.pm
+using C<$DatabasePassword>.
+
+Once the database and user exist, you can restore from your backup which
+will create tables, insert data and configure rights for your rt_user
+user.
+
+ gunzip -c rt-20141014.sql.gz | psql rt4
+
+This may need to be run as the postgres user or some other admin level
+user who can create tables.
+
+=item Restore over an existing database
+
+If something terrible happened this morning and you want to roll back to
+your backups, or if you want to update a dev server using your backups,
+you will need to drop your database and recreate a fresh one to restore
+into. RT can drop and recreate the database for you using:
+
+ /opt/rt4/sbin/rt-setup-database --action drop
+ /opt/rt4/sbin/rt-setup-database --action create
+
+Remember that this will completely destroy the existing data and create
+a fresh database. Your rt_user user will remain untouched. Once this
+is complete, you can restore from your backup which will create tables
+and insert data and configure rights for the rt_user.
+
+ gunzip -c rt-20141014.sql.gz | psql rt4
+
+=item After Restoring
+
+Postgres will generally perform poorly after restoring from backups
+because it has outdated index statistics. You should run C<analyze>
+after your restore is complete. If you'd like to watch the progress, you
+can run C<analyze verbose>.
+
+=back
=head2 FILESYSTEM
@@ -102,7 +192,7 @@ recreate those.
Simply saving a tarball should be sufficient, with something like:
- tar czvpf rt-backup-`date +%Y%M%d`.tar.gz /opt/rt4 /etc/aliases /etc/httpd ...
+ tar czvpf rt-backup-`date +%Y%m%d`.tar.gz /opt/rt4 /etc/aliases /etc/httpd ...
Be sure to include all the directories and files you enumerated above!
diff --git a/rt/docs/charts.pod b/rt/docs/charts.pod
new file mode 100644
index 000000000..52db66f8c
--- /dev/null
+++ b/rt/docs/charts.pod
@@ -0,0 +1,246 @@
+=head1 RT Charts
+
+RT has a built-in charting feature to allow you to create charts
+and graphs to visualize ticket data. Charts can be useful for
+anything from one-off reports (how many tickets did we process
+last year?) to regular status reports that you then include in
+shared dashboards that everyone can see.
+
+RT has had charts for a long time, but many significant improvements
+came in RT 4.2. If you're running a version of RT earlier than
+4.2 some options and features described here may not be available.
+
+=head1 Enabling Charts
+
+=head2 Installing GD
+
+While charts is a core part of RT, you do need to enable it using
+the C<--enable-gd> option and install the required dependencies when
+you install RT. If you didn't originally install with this flag, you can
+enable it by re-running the L<< C<configure> >> script from the RT
+distribution (including all previous options passed to it originally)
+or doing the following in your current install:
+
+=over
+
+=item 1
+
+In your C<RT_SiteConfig.pm> set C<$DisableGD> to 0:
+
+ Set($DisableGD, 0);
+
+=item 2
+
+Run the RT dependency checker:
+
+ $ /opt/rt4/sbin/rt-test-dependencies --with-gd --verbose
+
+=item 3
+
+Install GD libraries
+
+GD is an open source graphics library and it is available as a package
+for most Linux systems. The package might be called C<gd>, C<gd2>, C<libgd2>,
+or something similar. On some systems you will also need additional package
+required to compile code using the library. The package might be called
+C<gd-devel>, C<gd2-dev>, or something similar.
+
+=item 4
+
+Install Perl GD modules:
+
+ $ /opt/rt4/sbin/rt-test-dependencies --with-gd --install --verbose
+
+
+=back
+
+=head2 Chart Configuration Options
+
+By default, RT is configured to use the "Droid Sans" font for Unicode support
+across English, many western european languages, Chinese (Traditional and
+Simplified), and Japanese. If you prefer to use a different font, you can
+change the L<< "C<%ChartFont>"|RT_Config/ChartFont >> option.
+
+There is also an option to use database timezone conversion for PostgreSQL
+and MySQL to enable timezone conversion for time-based reports. See
+F<docs/customizing/timezones_in_charts.pod> for details.
+
+Search for "Chart" entries in L<< C<RT_Config> >> for more information on these
+options.
+
+=head1 Basic Charting
+
+Charts are based on the set of tickets returned by a search, so every chart starts
+with a search of your RT tickets. When constructing your search, think about
+the report you need to generate and try to narrow the results to the set
+of tickets that will have the information you want.
+
+=head2 Basic Ticket Search
+
+As a basic example, assume you want to look at activity in July 2012 for
+the General queue. First use the Query Builder to build a query with
+something like:
+
+ Queue = 'General'
+ AND Created >= '2012-07-01'
+ AND Created <= '2012-07-31'
+
+This search will give you tickets for July because the criteria uses before
+and after for the dates.
+
+This search shows one of the initial things you'll want to consider, which is
+the element of ticket metadata you want to use as the basis for time. In
+the example we're using Created, but depending on what you are reporting
+on you might want Started, Resolved, or any of the other ticket time values.
+
+When selecting the criteria for the time search, make sure it
+is appropriate to the report you want to see and be consistent so you
+are looking at the right set of tickets in the search and the resulting
+charts and reports.
+
+For this example, we'll say the activity we want to look at is new
+tickets coming into the queue, and Created works well for that.
+
+=head2 Ticket Charts
+
+If we run the search and look at the results, we get the standard
+RT search results page. From this page we can click on Chart in the submenu
+on the upper right of the page. This brings us to the Charts page with a
+default bar chart showing tickets by status in the General queue.
+
+=for html <img alt="General Queue Status Chart" src="images/general-status-chart.png">
+
+=for :text [General Queue Status Chart F<docs/images/general-status-chart.png>]
+
+=for :man [General Queue Status Chart F<docs/images/general-status-chart.png>]
+
+This chart gives us a nice view of tickets by status and the good news is
+most of the tickets in this time period have been resolved. Under the graph
+is a "Group by" section and we can see "Status" is selected as the criteria
+in the first dropdown in the first section. The second dropdown is also Status
+since status only has one representation.
+
+Now let's assume we want to see who was working on those tickets. You can
+select Owner from the first 'Group tickets by' dropdown and you'll see
+the second dropdown now has options to display labels based on RT user
+entries. Select an option and click 'Update Chart' and now you'll see
+the tickets displayed by Owner.
+
+=for html <img alt="General Owner Chart" src="images/general-owner-chart.png">
+
+=for :text [General Owner Chart F<docs/images/general-owner-chart.png>]
+
+=for :man [General Owner Chart F<docs/images/general-owner-chart.png>]
+
+In this case, we can see that although people are resolving tickets, they
+aren't Taking the tickets and Owner is not getting set. We may want to
+remind people to take tickets or even create a scrip to set Owner
+automatically on reply or resolve.
+
+Before we do that, we can use more chart features to find out more about
+what's going on. The "Group by" portlet allows us to set multiple criteria,
+so in the second set of dropdowns we'll select LastUpdatedBy and Name
+and click 'Update Chart'.
+
+=for html <img alt="General Owner LastUpdatedBy Chart" src="images/general-owner-lastupdated-chart.png">
+
+=for :text [General Owner LastUpdatedBy Chart F<docs/images/general-owner-lastupdated-chart.png>]
+
+=for :man [General Owner LastUpdatedBy Chart F<docs/images/general-owner-lastupdated-chart.png>]
+
+Now we can see that our culprit seems to primarily be the root user, who
+is getting a bunch of work done but isn't taking tickets. Maybe we just
+need to remind root to take tickets.
+
+=head2 Using Multiple Group Bys
+
+As you can see in the previous example, RT's charts allow you to define
+multiple criteria for grouping data from your search results. In many cases,
+grouping multiple levels of criteria can reveal interesting and useful graphs.
+To give you the greatest flexibility possible, the RT interface allows you
+to select from nearly all ticket values, but not all combinations of group
+by criteria will make sense or create a helpful chart. If you select some
+options and produce a chart that looks jumbled, consider again what
+you're trying to visualize from the data.
+
+
+=head1 Calculated Values
+
+The Calculate section of the RT charts interface allows you to generate
+charts with calculated time values. You can select time values used in time
+tracking (e.g., TimeWorked) and calculated values from the various timestamps
+on tickets like Created, Resolved, etc. Once you have selected the values or
+ranges you want to view, you can choose to see an Average, Total, Maximum,
+Minimum or a summary presenting them all.
+
+=head2 Viewing Ticket Response Times
+
+As described above, the Calculate section allows you to pull out durations
+like how long it took for tickets to be opened, which is the difference
+between Created and Started. To create a chart with this information,
+we first create a new search to return all resolved tickets for a select
+group of queues we're interested in. You could also add some date criteria
+to narrow the search to a range of time as in the previous example.
+
+After getting our result set and clicking on Charts, we select
+Queue from the "Group by" section so we see data grouped by the queues we
+selected. In the Calculate section we select Created-Started from the
+first dropdown and the Summary option from the second dropdown and click
+"Update Chart".
+
+This generates a detailed chart with a bunch of time data for all of the
+queues we selected in our search. It's a little busy, so we might look at
+some of the other display options available in the second dropdown.
+What we're really interested in is the average time from Created to Started,
+since this will give us a general idea how long it's taking people to
+initially respond to requests.
+
+The second dropdown in the Calculate section has an option for
+"Average Created-Started". If we select that and update the
+chart, we see a nice graph of average time for tickets to be opened across
+all of the queues we selected.
+
+=for html <img alt="Queue Created Started Chart" src="images/queue-created-started-chart.png">
+
+=for :text [Queue Created Started Chart F<docs/images/queue-created-started-chart.png>]
+
+=for :man [Queue Created Started Chart F<docs/images/queue-created-started-chart.png>]
+
+Now perhaps we also want to see how long tickets stay active. In the Calculate
+section you can add Started-Resolved to the first "and then" and select
+"Average Started-Resolved" from the second dropdown. Click "Update Chart"
+and you've now got a graphical view of how long, on average, tickets are
+waiting to be opened and how long people are working on them.
+
+If you use RT for time tracking, you can create similar useful charts
+using TimeEstimated, TimeWorked, and TimeLeft.
+
+=head1 Chart Style and Size
+
+Charts default to a bar style, but you can display data as a pie chart
+by selecting pie in the "Picture" portlet. You can also adjust the width
+height of the generated chart by entering a size in pixels. These width
+and height values are saved if you save the chart and are used if
+you include the chart on a Dashboard as well.
+
+=head1 Saving Charts
+
+Much like searches, you can save charts once you get them configured the
+way you want. The Privacy setting determines who else on the RT system
+will be able to see your saved charts. Note that this setting applies only
+to the chart itself and not necessarily the data included which may still
+be blocked from other users.
+
+To save a chart, select a Privacy setting, give it a Description and click
+Save. Once saved, you can retrieve the chart later by coming to the chart
+page and selecting it from the "Load saved search" dropdown and clicking
+Load.
+
+When you save a chart, it also becomes available to the Dashboard interface.
+This allows you to go to Home > New Dashboard and create a Dashboard that
+shows the chart you have created. This can be very useful for charts you
+want to monitor frequently or create for others.
+
+If you need to change a chart, load it, make your changes, then click
+Update. Delete deletes the saved chart and will also remove it from all
+Dashboards that are using it.
diff --git a/rt/docs/customizing/approvals.pod b/rt/docs/customizing/approvals.pod
index af5aa3b0a..c42dede70 100644
--- a/rt/docs/customizing/approvals.pod
+++ b/rt/docs/customizing/approvals.pod
@@ -24,8 +24,8 @@ and process the approval or rejection.
Since this example will use a change management queue as the
queue where tickets need approval, first we'll set up the queue.
-Login into UI as the 'root' user. Go to Tools -> Configuration ->
-Queues and create a new 'Change requests' queue.
+Login into UI as the 'root' user. Go to Admin -> Queues and create a new
+'Change requests' queue.
When you set up this queue, do not select the "approvals" Lifecycle.
That selection is for the ___Approvals queue itself, not for queues that
@@ -94,7 +94,7 @@ queue.
___Approvals is a special queue where all approvals are created. The queue
is disabled and is not shown in until you search for it.
-Go to Tools -> Configuration -> Queues, leave "Name is" in the search
+Go to Admin -> Queues, leave "Name is" in the search
area and enter ___Approvals into the search
field. Check 'Include disabled queues in listing.' and click Go!
You should now see the ___Approvals queue configuration page.
diff --git a/rt/docs/customizing/articles_introduction.pod b/rt/docs/customizing/articles_introduction.pod
index 73b5c334d..363a3859d 100644
--- a/rt/docs/customizing/articles_introduction.pod
+++ b/rt/docs/customizing/articles_introduction.pod
@@ -8,11 +8,16 @@ RT. They are organized into classes and topics.
=head2 UI
-The user interface to Articles is available from the Tools -> Articles
-menu. Admin functionality can be found under Tools -> Configuration ->
-Articles. Once configured, articles will become available for searching
-on the Reply/Comment page on tickets. There are L</"Configuration Options">
-to make Articles available on ticket creation.
+The user interface to Articles is available from the Articles menu. Admin
+functionality can be found under Admin -> Articles. Once configured, articles
+will become available for searching on the Reply/Comment page on tickets.
+There are L</"Configuration Options"> to make Articles available on ticket
+creation.
+
+For the Articles menu to be visible to your Privileged users, you must grant
+Privileged the ShowArticlesMenu right globally (Admin -> Global -> Group
+Rights). You may grant the right as selectively as you wish if, for example,
+you only want a certain group of your users to use articles.
=head2 Basics
@@ -27,7 +32,7 @@ Classes can be made available globally or on a per-Queue basis.
=head3 Classes
Classes are equivalent to RT's queues. They can be created by going
-to Tools -> Configuration -> Articles -> Classes -> New Class. Articles
+to Admin -> Articles -> Classes -> New Class. Articles
are assigned to one Class. When you create Custom Fields for use with
Articles, they will be applied Globally or to a Class, like Custom
Fields are applied to a Queue in RT.
@@ -40,7 +45,7 @@ when inserting the Article in a reply. You can control this behavior on
the Class configuration page.
Classes need to be Applied, just like a Custom Field, by using the
-Applies To link on the Modify Class page (Tools -> Configuration ->
+Applies To link on the Modify Class page (Admin ->
Articles -> Classes, select the class to modify). You can apply
them globally or on a queue-by-queue basis.
@@ -48,7 +53,7 @@ them globally or on a queue-by-queue basis.
You can also use Topics to organize your Articles. While editing a
Class, there is a Topics tab for Class-specific Topics. You can create
-global Topics from the Global tab under Tools -> Configuration.
+global Topics from the Global tab under Admin.
When editing Topics, type the name (and optionally description) of the
Topic, and then click the button at the appropriate location in the
diff --git a/rt/docs/customizing/styling_rt.pod b/rt/docs/customizing/styling_rt.pod
index c5802a84b..7e37d009e 100644
--- a/rt/docs/customizing/styling_rt.pod
+++ b/rt/docs/customizing/styling_rt.pod
@@ -12,18 +12,22 @@ RT versions have a default, and the RT admin can set the system-wide
theme with the C<$WebDefaultStylesheet> configuration value in the
F<RT_SiteConfig.pm> file.
-RT 4.0 comes with the following themes:
+RT comes with the following themes:
=over
-=item web2
+=item rudder
-An approximation of the 3.8 style
+The default layout for RT 4.2
=item aileron
The default layout for RT 4.0
+=item web2
+
+An approximation of the 3.8 style
+
=item ballard
Theme which doesn't rely on JavaScript for menuing
@@ -32,14 +36,14 @@ Theme which doesn't rely on JavaScript for menuing
If you have granted the ModifySelf right to users on your system,
they can pick a different theme for themselves by going to
-Logged in as -> Settings -> Options and selecting a different theme.
+Logged in as -> Settings -> Preferences and selecting a different theme.
=head1 RT Theme Editor
RT has some built-in controls to manage the look of the theme you select.
To use the Theme Editor, log in as a SuperUser (like root), and navigate
-to Tools -> Configuration -> Tools -> Theme.
+to Admin -> Tools -> Theme.
=for html <img alt="RT theme editor, defaults" src="../images/theme_editor_defaults.png">
@@ -89,38 +93,18 @@ default CSS styles, via the C<@CSSFiles> configuration option. To add
an extra CSS file, for example F<my-site.css>, create the local overlay
directory:
- $ mkdir -p local/html/NoAuth/css/
+ $ mkdir -p local/static/css/
And place your F<my-site.css> file in it. Finally, adjust your
C<@CSSFiles> in your F<RT_SiteConfig.pm>:
Set( @CSSFiles, ('my-site.css') );
-This technique is preferred to callbacks (below) because CSS included
-via this way will be minified. It is also included across all styles,
-unlike the callback technique.
+CSS added this way is included across all themes.
If you are writing an extension, see L<RT/AddStyleSheets> for how to
simply and programmatically add values to C<@CSSFiles>.
-=head2 Callbacks
-
-RT's CSS files are also Mason templates and the main CSS file,
-conveniently called C<main.css>, has a C<Begin> and C<End> callback
-allowing you to inject custom CSS.
-
-To create an End callback, create the callback directory and an
-End file in that directory:
-
- $ mkdir -p local/html/Callbacks/MyRT/NoAuth/css/aileron/main.css
- $ touch local/html/Callbacks/MyRT/NoAuth/css/aileron/main.css/End
-
-You can use any name you want for the C<MyRT> directory and the theme
-directory should correspond with the theme you want to change.
-
-RT will now evaluate the contents of that file after it processes all
-of the C<@import> statements in C<main.css>.
-
=head1 Designing Your Own Theme
@@ -134,11 +118,11 @@ local modifications to RT. Run the following commands in your
C</opt/rt4> directory (or wherever your RT is installed) to get
started:
- $ mkdir -p local/html/NoAuth/css/localstyle
- $ cp -R share/html/NoAuth/css/aileron/* local/html/NoAuth/css/localstyle/
+ $ mkdir -p local/static/css/localstyle
+ $ cp -R share/static/css/rudder/* local/static/css/localstyle/
You can call your "localstyle" directory whatever you want and you don't
-have to copy the aileron theme to start from, but it's a good place to
+have to copy the rudder theme to start from, but it's a good place to
start off for RT4.
Now set C<$WebDefaultStylesheet> in RT_SiteConfig.pm to the new directory
@@ -147,7 +131,7 @@ name you selected, for example:
Set( $WebDefaultStylesheet, 'localstyle' );
If you restart your RT it should look just the same (assuming you copied
-your current default theme), but if you go to your Options page you'll
+your current default theme), but if you go to your Preferences page you'll
see that the system default theme is now your new "localtheme."
If you look at the CSS being loaded, you'll also see that the main css
diff --git a/rt/docs/customizing/templates.pod b/rt/docs/customizing/templates.pod
index 5733f606c..331534cfe 100644
--- a/rt/docs/customizing/templates.pod
+++ b/rt/docs/customizing/templates.pod
@@ -1,7 +1,14 @@
=head1 Templates
-Each template is split into two sections. A block of headers and a body. These
-sections are separated by a blank line.
+Templates are used in RT to send notifications, typically email. You have
+access to RT data via variables available to you in the scope of the template.
+Templates can also be used for some special actions like creating a new ticket
+as part of the execution of a scrip.
+
+Each template is split into two sections: a block of headers and a body. These
+sections are separated by a blank line. Blank lines are not allowed before
+the headers, but can be included in the body as needed after the headers
+section.
Templates are processed by the L<Text::Template> module. This module
allows you to embed arbitrary Perl code into your templates. Text wrapped
@@ -28,17 +35,17 @@ readable, while users with clients which can display HTML will receive the full
experience. Please be aware that HTML support in mail clients varies greatly,
much more so than different web browsers.
-We welcome contributions of HTML-ization of builtin templates.
+Starting in RT 4.2, HTML templates are included along with plain text templates
+for the standard RT notifications.
=back
=head2 Template Types
-Templates have a Type which dictates which level of code execution is
-allowed.
+Templates have a Type which dictates the level of code execution allowed.
Templates of type C<Perl> are evaluated using L<Text::Template>
-which allows arbitrary code execution. Only users which have the global
+which allows arbitrary code execution. Only users with the global
C<ExecuteCode> privilege may write templates of type C<Perl>. Prior to
RT 4.0, this was the only type of Template available.
@@ -82,6 +89,24 @@ A localization function. See L<Locale::Maketext>.
=back
+The C<$Transaction> and C<$Ticket> objects are particularly useful. For
+example, here are some values you can get from each:
+
+ $Ticket->Status # Current status
+ $Ticket->Owner # Current owner
+ $Ticket->FirstCustomFieldValue('CustomFieldName') # CF value
+ $Ticket->DueAsString # Current due date as a string
+ $Ticket->DueObj # Due as an RT::Date object
+ $Ticket->QueueObj # Queue object for this ticket
+
+ $Transaction->Type # Type of transaction
+ $Transaction->OldValue # Previous value, if type is Set
+ $Transaction->NewValue # New value, if type is Set
+ $Transaction->CreatorObj->EmailAddress # Email address of trans creator
+
+You can see the methods available in the L<RT::Ticket> and L<RT::Transaction>
+documentation.
+
=head3 Selected Simple template variables
Since method calls are not allowed in simple templates, many common
@@ -104,7 +129,9 @@ use. Among them:
=item $TicketCF(Name)
-For example, C<$TicketCFDepartment>.
+For example, C<$TicketCFDepartment>. For CFs with more complicated
+names, all non-word characters (anything that is not letters, numbers,
+or underscores) are stripped to determine the appropriate variable name.
=item $TransactionType
@@ -128,5 +155,20 @@ For example, C<$TransactionCFLocation>.
=back
+=head2 Templates Provided with RT
+
+RT comes with a set of templates for the default notifications. As you start to
+customize your templates, these templates are a good place to look for
+examples. As you customize, it can be helpful to create new templates and
+update your scrips to reference your new templates. This leaves the original RT
+templates in place for easy reference.
+
+Starting in RT 4.2, each template has a plain text version and an HTML
+version. For example, the "Correspondence" template is the plain text version
+of the default template for correspondence (replies) and the "Correspondence in
+HTML" template is the same template formatted in HTML. The 4.2 upgrade provides
+a C<switch-templates-to> script to switch all default templates from plain text
+to HTML or the reverse. See the L<UPGRADING-4.2> notes for details.
+
=cut
diff --git a/rt/docs/dashboards.pod b/rt/docs/dashboards.pod
new file mode 100644
index 000000000..0a96521b5
--- /dev/null
+++ b/rt/docs/dashboards.pod
@@ -0,0 +1,206 @@
+=head1 Dashboards
+
+RT's dashboard feature provides a convenient way to create your own pages
+focused on the tickets and charts you need. Dashboards are available right from
+the Home menu, can be set up individually or shared, and can even be sent out
+via email on a schedule. To show some of the dashboard features, we'll set up a
+dashboard and notifications to track outstanding invoice tickets.
+
+There are several different rights you can grant to allow users access to the
+features described here. These rights are described in L</"Dashboard Rights">.
+
+=head2 Creating a Personal Dashboard
+
+Saved searches and charts are the building blocks of dashboards, so to set up a
+new dashboard you first need to create and save a search that displays the
+ticket data you want. We want to view new and open invoice tickets and, for our
+example, assume we have an Accounts Receivable queue. On the ticket search
+page, we create a new search with this query:
+
+ Queue = 'Accounts Receivable'
+ AND (
+ Status = 'new'
+ OR Status = 'open' )
+
+We also want to modify the sort order of the search to use Due rather than the
+default id. In the Sorting section, we select Due for the initial sort, then
+add Created as the second sort value. Finally, we set Rows per page to
+Unlimited so we don't miss any invoices.
+
+=for html <img alt="Dashboard search sorting"
+src="images/dashboard-search-sorting.png">
+
+=for :text [Search sorting F<docs/images/dashboard-search-sorting.png>]
+
+=for :man [Search sorting F<docs/images/dashboard-search-sorting.png>]
+
+Once you have those set, you can click "Add these terms and Search" or "Update
+format and Search" to see the results. If it's still not quite right, you can
+click "Edit Search" in the submenu and continue to refine things.
+
+When you're finished tweaking the search, return to Query Builder page again so
+you can save it. Under the "Saved Searches" box, type "Outstanding Invoices"
+in the Description box. For now, leave Privacy set to "My saved searches" and
+click Save. You now have a saved search you can use for your dashboard.
+
+To create the dashboard, select Home > New Dashboard. Type "Outstanding
+Invoices" for the name and leave the privacy set to "My Dashboards". Click
+Create and the new dashboard is created.
+
+Now we want to populate the new dashboard with the saved search we created.
+Click Content in the submenu to go to the content selection page. Dashboards
+allow you to put content in the main body or the sidebar, much like the default
+RT homepage, so you'll see a Body section and a Sidebar section to set the
+content. Find your saved "Outstanding Invoices" search, select it, and click
+the arrow to move it to the righthand box and add it to the dashboard.
+
+=for html <img alt="Adding dashboard content"
+src="images/dashboard-content-invoices.png">
+
+=for :text [Adding dashboard content
+F<docs/images/dashboard-content-invoices.png>]
+
+=for :man [Adding dashboard content
+F<docs/images/dashboard-content-invoices.png>]
+
+Click Show in the submenu and you'll see your new dashboard. Click Home to
+return to the "RT at a glance" page and you'll see your new dashboard is in the
+Dashboards portlet on the right side of the page.
+
+On dashboard pages, you can click on the title of any section and go to the
+search results page for the saved search. This makes it easy to find the saved
+search and update it, or modify it ad-hoc for a one-off search based on the
+saved dashboard search.
+
+In this example we're only adding one search, but you can add multiple searches
+to each individual dashboard to track different types of interrelated
+information and see it at a glance. For instance, two queries, "outstanding
+invoices" and "overdue invoices," could form a dashboard called "all
+outstanding invoices." Software engineers using RT might combine three queries,
+"bug fixes," "feature requests," and "documentation," into a dashboard
+called "our new release."
+
+=head2 Charts in Dashboards
+
+You can also display saved charts in dashboards, creating a powerful visual of
+ticket data in a convenient page. To add a chart, start with a search, refine
+your query, then click Chart in the submenu in the Query Builder or Search
+Results page. Configure your chart as described in L<charts>, select a Privacy
+setting, name it "Outstanding Invoices", and click Save.
+
+Return to the dashboard, click Content, and you'll see a new "Chart:
+Outstanding Invoices" option in the Available column. Select it and click the
+arrow to add it to the dashboard. Now when you load the dashboard, the chart
+will be rendered right below the saved search.
+
+=for html <img alt="Dashboard chart" src="images/dashboard-chart.png">
+
+=for :text [Dashboard chart F<docs/images/dashboard-chart.png>]
+
+=for :man [Dashboard chart F<docs/images/dashboard-chart.png>]
+
+=head2 Dashboard Menu Entries
+
+In addition to having dashboards available on the "RT at a glance" page, you
+can also add them to the Home menu. To modify the Home menu, select Home >
+"Update This Menu" or "Logged in as" > Settings > "Dashboards in menu". You'll
+see the Customize dashboard page which is similar to the Dashboard Content page.
+
+=for html <img alt="Customize dashboard menu"
+src="images/customize-dashboards-menu.png">
+
+=for :text [Customize dashboard menu
+F<docs/images/customize-dashboards-menu.png>]
+
+=for :man [Customize dashboard menu F<docs/images/customize-dashboards-menu.png>]
+
+Select the dashboard you want, click the arrow to move it to the righthand
+column, then check your Home menu. You'll see your dashboard is now available
+from the menu.
+
+As an RT administrator, you can populate the dashboard menu for other users on
+the system. Find a user using Search > Users or Admin > Users > Select, then
+click on the user to open the modify user page. In the submenu, you'll see a
+"Dashboards in menu" option, and it works the same as the personal setting.
+
+=head2 Group Dashboards
+
+You're enjoying your new dashboard but it's time for some vacation and it would
+be nice for someone else in the accounting department to be able to use your
+dashboard while you're gone. RT makes this easy with group-level dashboards.
+
+As we've seen, the dashboard is based on a saved search, so you first need to
+make that available. Go to the ticket search page (Query Builder), find your
+saved search in the "Load saved search" dropdown, and click Load. If you are in
+a group, like the Accounting group, there will be an option in the Privacy
+dropdown called "Accounting's saved searches". Select that option and click
+Update to make the search available to the Accounting group.
+
+To update your dashboard, select it from the menu to view it, then click Basics
+in the submenu. Like on Query Builder page, you'll see your group listed in the
+Privacy dropdown. Assuming your group is Accounting, select "Accounting's
+Dashboards" and click Save Changes.
+
+Click on Content and you'll see a message that a query has been deleted and
+removed from the dashboard. This is because RT has detected that you have moved
+the saved search from personal to group privacy. Select "Outstanding Invoices"
+from the Available column and click the arrow to add the group-based search to
+the dashboard.
+
+All members of the Accounting group should now have access to your dashboard.
+They can now add it to their Home menu if they want. If other members can't see
+it, make sure you have granted sufficent rights to the group (see L</"Dashboard
+Rights">).
+
+=head2 System-wide Dashboards
+
+You can also set up dashboards for all users on your RT system. Follow the
+steps above for group dashboards, but for Privacy, select "RT System" for the
+saved search and dashboard.
+
+If you want to make sure everyone has the dashboard in their Home menu, you can
+set this globally as well if you are the RT administrator. The Admin > Global >
+"Dashboards in menu" opens a page similar to the personal dashboard menu page,
+but it puts the selected dashboards into everyone's dashboard menu.
+
+=head2 Dashboard Subscriptions
+
+RT's dashboard subscription feature allows you to email dashboards based on a
+schedule you set. These scheduled dashboards can be particularly useful for
+time-based reports that you want to see on a regular basis.
+
+To set up a subscription, go to the dashboard you'd like to have emailed and
+click on Subscription in the submenu. This will take you to the subscription
+page.
+
+=for html <img alt="Dashboard subscription"
+src="images/dashboard-subscription.png">
+
+=for :text [Dashboard subscription F<docs/images/dashboard-subscription.png>]
+
+=for :man [Dashboard subscription F<docs/images/dashboard-subscription.png>]
+
+Select the frequency and timing you want and enter the email address the
+dashboard should go to. You can leave it blank to send mail to your RT email
+address. Click Subscribe and that's it, you'll start getting dashboards via
+email.
+
+This feature requires the F<rt-email-dashboards> script to be scheduled in
+C<cron> as described in RT's F<README> file.
+
+=head2 Dashboard Rights
+
+There are several rights you can selectively grant to allow users access to
+dashboard features. As with any RT rights, you can grant these to individual
+users (usually difficult to maintain over time), to system roles like
+Privileged, or to groups you define.
+
+Since dashboards rely on saved searches, you need to grant "Allow loading of
+saved searches" (LoadSavedSearch) for users to see the searches. You may want
+to also grant "Allow creation of saved searches" (CreateSavedSearch) to allow
+users to create their own and "View saved searches" (ShowSavedSearches)
+
+For dashboards themselves, there are See, Create, Modify, and Delete rights for
+each of personal, group, and system dashboards. This allows you to select the
+right combination of rights for users and groups on your system. For
+subscriptions, there is a "Subscribe to dashboards" (SubscribeDashboard) right. \ No newline at end of file
diff --git a/rt/docs/extending/clickable_links.pod b/rt/docs/extending/clickable_links.pod
index dd80ff10f..d52ea5996 100644
--- a/rt/docs/extending/clickable_links.pod
+++ b/rt/docs/extending/clickable_links.pod
@@ -23,6 +23,7 @@ after the URL.
=item C<httpurl_overwrite>
Detects URLs as C<httpurl> format, but replaces the URL with a link.
+This action is enabled by default.
=back
diff --git a/rt/docs/extending/external_custom_fields.pod b/rt/docs/extending/external_custom_fields.pod
index f32bda769..5e70d3e40 100644
--- a/rt/docs/extending/external_custom_fields.pod
+++ b/rt/docs/extending/external_custom_fields.pod
@@ -57,6 +57,10 @@ web interface. See L</Configuration>.
This method should return an array reference of hash references. The
hash references should contain keys for C<name>, C<description>, and
C<sortorder>. C<name> is most important one; the others are optional.
+You can also optionally provide a key for C<category> and use the
+"Categories are based on" option on the custom field configuration
+page to make the values displayed for this custom field vary based
+on the value selected in the "based on" custom field.
=back
@@ -77,9 +81,9 @@ Here's a simple static example:
# return reference to array ([])
return [
# each element of the array is a reference to hash that describe a value
- # possible keys are name, description and sortorder
- { name => 'value1', description => 'external value', sortorder => 1 },
- { name => 'value2', description => 'another external value', sortorder => 2 },
+ # possible keys are name, description, sortorder, and category
+ { name => 'value1', description => 'external value', sortorder => 1, category => 'Other CF' },
+ { name => 'value2', description => 'another external value', sortorder => 2, category => 'Other CF' },
# values without description are also valid, the default description is empty string
{ name => 'value3', sortorder => 3 },
# you can skip sortorder too, but note that the default sortorder is 0 (zero)
diff --git a/rt/docs/extensions.pod b/rt/docs/extensions.pod
new file mode 100644
index 000000000..502e37f28
--- /dev/null
+++ b/rt/docs/extensions.pod
@@ -0,0 +1,102 @@
+=head1 Introduction
+
+RT has a lot of core features, but sometimes you have a problem to solve
+that's beyond the scope of just configuration. The standard way to add
+features to RT is with an extension, or plugin -- RT uses the terms
+interchangably.
+
+=head1 Finding extensions
+
+Most of the extensions written by Best Practical (and quite a few
+contributed by the community) are available from CPAN; a L<search for
+RT::Extension|https://metacpan.org/search?q=RT::Extension::> will turn
+up most of them. The Best Practical website also maintains a list, at
+L<http://www.bestpractical.com/rt/extensions.html>
+
+=head1 Installing extensions
+
+RT extensions should be installed by downloading the C<.tar.gz> file for
+the extensions, extracting it (with C<tar xzf filename.tar.gz>), and
+following the instructions in its included F<README>.
+
+The instructions under C<INSTALLING> in the F<README> always take
+precedence over those found here. In general, however, the process is
+as follows:
+
+=over
+
+=item 1.
+
+B<Run C<perl Makefile.PL>> to check for dependencies, and minimum
+versions of RT. If your RT is in an unusual location (not
+C</opt/rt4/>), you may need to set the C<RTHOME> environment variable to
+the root of your RT location.
+
+=item 2.
+
+B<Run C<make>> to prepare the package for installation.
+
+=item 3.
+
+B<Run C<make install>>; you may need to run this step as C<root>, or at
+least a user that has permission to install into RT's directories.
+
+=item 4.
+
+If the extension contains database changes or new queues, scrips,
+templates, or the like, you will need to B<run C<make initdb>> to install
+them. Not all extensions have database changes, and most of them only
+need this step run when they are first installed, and not on later
+updates. Refer to the C<INSTALLING> section of the module's
+documentation.
+
+=item 5.
+
+B<Add the plugin to RT's configuration.> By default, newly installed
+plugins are not enabled. On RT 4.2, each plugin should be enabled by
+the C<Plugin()> command:
+
+ Plugin( 'RT::Extension::Example' );
+ Plugin( 'RT::Extension::Sample' );
+
+
+On RT 4.0, enabling them instead requires adding them to the C<@Plugins>
+configuration:
+
+ Set( @Plugins, 'RT::Extension::Example', 'RT::Extension::Sample' );
+
+=item 6.
+
+B<Configure any additional settings> that the extension requires. Many
+options that must be set before the plugin can be used. Read the
+documentation carefully.
+
+=item 7.
+
+Next, B<clear the cache>. RT caches the files it serves, and installing
+a plugin requires clearing this cache to ensure that the changes are
+served. This is done by removing files in the
+F</opt/rt4/var/mason_data/obj> directory:
+
+ rm -rf /opt/rt4/var/mason_data/obj
+
+This step may not be necessary if the extension does not affect RT's
+display.
+
+=item 8.
+
+Finally, B<restart your webserver>. The steps for this will vary from
+webserver to webserver.
+
+=back
+
+Again, the above are generalizations. The C<README> shipped with the
+extension always takes precedence over the above steps.
+
+
+We do not suggest using the command-line C<cpan> or C<cpanm> client to
+install RT extensions, despite them being available from CPAN. Those
+command-line clients are not aware of steps 4-8 listed above, and may
+result in an incomplete installation.
+
+=cut
diff --git a/rt/docs/full_text_indexing.pod b/rt/docs/full_text_indexing.pod
index 6b0025d62..24169cb14 100644
--- a/rt/docs/full_text_indexing.pod
+++ b/rt/docs/full_text_indexing.pod
@@ -21,34 +21,31 @@ Postgres 8.3 and above support full-text searching natively; to set up
the required C<ts_vector> column, and create either a C<GiN> or C<GiST>
index on it, run:
- sbin/rt-setup-fulltext-index
+ /opt/rt4/sbin/rt-setup-fulltext-index
If you have a non-standard database administrator username or password,
you may need to pass the C<--dba> or C<--dba-password> options:
- sbin/rt-setup-fulltext-index --dba postgres --dba-password secret
+ /opt/rt4/sbin/rt-setup-fulltext-index --dba postgres --dba-password secret
-This will also output an appropriate C<%FullTextSearch> configuration to
-add to your F<RT_SiteConfig.pm>; you will need to restart your webserver
-after making these changes. However, the index will also need to be
-filled before it can be used. To update the index initially, run:
+This will then tokenize and index all existing attachments in your
+database; it may take quite a while if your database already has a large
+number of tickets in it.
- sbin/rt-fulltext-indexer --all
+Finally, it will output an appropriate C<%FullTextSearch> configuration
+to add to your F<RT_SiteConfig.pm>; you will need to restart your
+webserver after making these changes.
-This will tokenize and index all existing attachments in your database;
-it may take quite a while if your database already has a large number of
-tickets in it.
=head2 Updating the index
To keep the index up-to-date, you will need to run:
- sbin/rt-fulltext-indexer
+ /opt/rt4/sbin/rt-fulltext-indexer
-...at regular intervals. By default, this will only tokenize up to 100
-tickets at a time; you can adjust this upwards by passing
-C<--limit 500>. Larger batch sizes will take longer and
-consume more memory.
+...at regular intervals. By default, this will only tokenize up to 200
+tickets at a time; you can adjust this upwards by passing C<--limit
+500>. Larger batch sizes will take longer and consume more memory.
If there is already an instances of C<rt-fulltext-indexer> running, new
ones will exit abnormally (with exit code 1) and the error message
@@ -57,37 +54,103 @@ and end those processes normally (with exit code 0) using the C<--quiet>
option; this is particularly useful when running the command via
C<cron>:
- sbin/rt-fulltext-indexer --quiet
+ /opt/rt4/sbin/rt-fulltext-indexer --quiet
=head1 MYSQL
-MySQL does not support full-text indexing natively. However, it does
-integrate with the external Sphinx engine, available from
+On MySQL, full-text search can either be done using native support
+(which may use MyISAM tables on pre-5.6 versions of MySQL), or RT can
+integrate with the external Sphinx full-text search engine.
+
+=head2 Native MySQL
+
+As RT marks attachment data as C<BINARY>, MySQL cannot index this
+content without creating an additional table. To create the required
+table (which is InnoDB on versions of MySQL which support it), run:
+
+ /opt/rt4/sbin/rt-setup-fulltext-index
+
+If you have a non-standard database administrator username or password,
+you may need to pass the C<--dba> or C<--dba-password> options:
+
+ /opt/rt4/sbin/rt-setup-fulltext-index --dba root --dba-password secret
+
+This will then tokenize and index all existing attachments in your
+database; it may take quite a while if your database already has a large
+number of tickets in it.
+
+Finally, it will output an appropriate C<%FullTextSearch> configuration
+to add to your F<RT_SiteConfig.pm>; you will need to restart your
+webserver after making these changes.
+
+
+=head3 Updating the index
+
+To keep the index up-to-date, you will need to run:
+
+ /opt/rt4/sbin/rt-fulltext-indexer
+
+...at regular intervals. By default, this will only tokenize up to 200
+tickets at a time; you can adjust this upwards by passing C<--limit
+500>. Larger batch sizes will take longer and consume more memory.
+
+If there is already an instances of C<rt-fulltext-indexer> running, new
+ones will exit abnormally (with exit code 1) and the error message
+"rt-fulltext-indexer is already running." You can suppress this message
+and end those processes normally (with exit code 0) using the C<--quiet>
+option; this is particularly useful when running the command via
+C<cron>:
+
+ /opt/rt4/sbin/rt-fulltext-indexer --quiet
+
+=head3 Caveats
+
+Searching is done in "boolean mode." As such, the TicketSQL query
+C<Content LIKE 'winter 2014'> will return tickets with transactions that
+contain I<either> word. To find transactions which contain both (but
+not necessarily adjacent), use C<Content LIKE '+winter +2014'>. To find
+transactions containing the precise phrase, use C<Content LIKE '"winter
+2014">.
+
+See the mysql documentation, at
+L<http://dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html>, for a
+list of the full capabilities.
+
+
+=head2 MySQL with Sphinx
+
+RT can also integrate with the external Sphinx engine, available from
L<http://sphinxsearch.com>. Unfortunately, Sphinx integration (using
SphinxSE) does require that you recompile MySQL from source. Most
distribution-provided packages for MySQL do not include SphinxSE
integration, merely the external Sphinx tools; these are not sufficient
for RT's needs.
-=head2 Compiling MySQL and SphinxSE
+=head3 Compiling MySQL and SphinxSE
-SphinxSE requires MySQL 5.0 or 5.1; later versions of MySQL have not
-been tested at this time. Sphinx version 2.0.1 has been tested to work,
-but version 0.9.9 may work as well. Compilation and installation
+MySQL 5.1 supports adding pluggable storage engines; after compiling
+against the appropriate version of MySQL, the F<ha_sphinx.so> file is
+the only that needs to be installed in production, generally into
+C</usr/lib/mysql/plugin/>. It can then be enabled via:
+
+ INSTALL PLUGIN Sphinx SONAME "ha_sphinx.so"
+
+Sphinx versions 0.9.x and 2.0.x are known-working versions, but later
+versions may work as well. Complete compilation and installation
instructions for MySQL with SphinxSE can be found at
-L<http://sphinxsearch.com/docs/current.html#sphinxse-installing>.
+L<http://sphinxsearch.com/docs/current.html#sphinxse-mysql51>.
-=head2 Creating and configuring the index
+=head3 Creating and configuring the index
Once MySQL has been recompiled with SphinxSE, and Sphinx itself is
installed, you may create the required SphinxSE communication table via:
- sbin/rt-setup-fulltext-index
+ /opt/rt4/sbin/rt-setup-fulltext-index
If you have a non-standard database administrator username or password,
you may need to pass the C<--dba> or C<--dba-password> options:
- sbin/rt-setup-fulltext-index --dba root --dba-password secret
+ /opt/rt4/sbin/rt-setup-fulltext-index --dba root --dba-password secret
This will also provide you with the appropriate C<%FullTextSearch>
configuration to add to your F<RT_SiteConfig.pm>; you will need to
@@ -104,7 +167,7 @@ Finally, start the Sphinx search daemon:
searchd
-=head2 Updating the index
+=head3 Updating the index
To keep the index up-to-date, you will need to run:
@@ -113,15 +176,23 @@ To keep the index up-to-date, you will need to run:
...at regular intervals in order to pick up new and updated attachments
from RT's database. Failure to do so will result in stale data.
-=head2 Caveats
+=head3 Caveats
+
+RT's integration with Sphinx relies on the use of a special index; there
+exist queries where the MySQL optimizer elects to I<not> use that index,
+instead electing to scan the table, which causes no results to be
+returned. However, this is rare, and generally only occurs on complex
+queries.
-Sphinx only returns a finite number of matches to any query; this number
-is controlled by C<max_matches> in F</etc/sphinx.conf> and
+Sphinx also only returns a finite number of matches to any query; this
+number is controlled by C<max_matches> in F</etc/sphinx.conf> and
C<%FullTextSearch>'s C<MaxMatches> in C<RT_SiteConfig.pm>, which must be
kept in sync. The default, set during C<rt-setup-fulltext-index>, is
10000. This limit may lead to false negatives in search results if the
maximum number of matches is reached but the results returned do not
-match RT's other criteria.
+match RT's other criteria. However, a too-large value will notably
+degrade performance, as it adds memory allocation overhead to every
+query.
Take, for example, the instance where Sphinx is configured to return a
maximum of three results, and tickets 1, 2, 3, 4, and 5 contain the
@@ -142,12 +213,12 @@ C<RT_SiteConfig.pm> must be updated.
Oracle supports full-text indexing natively using the Oracle Text
package. Once Oracle Text is installed and configured, run:
- sbin/rt-setup-fulltext-index
+ /opt/rt4/sbin/rt-setup-fulltext-index
If you have a non-standard database administrator username or password,
you may need to pass the C<--dba> or C<--dba-password> options:
- sbin/rt-setup-fulltext-index --dba sysdba --dba-password secret
+ /opt/rt4/sbin/rt-setup-fulltext-index --dba sysdba --dba-password secret
This will create an Oracle CONTEXT index on the Content column in the
Attachments table, as well as several preferences, functions and
@@ -160,7 +231,7 @@ F<RT_SiteConfig>.
To update the index, you will need to run the following at regular
intervals:
- sbin/rt-fulltext-indexer
+ /opt/rt4/sbin/rt-fulltext-indexer
This, in effect, simply runs:
@@ -171,7 +242,7 @@ This, in effect, simply runs:
The amount of memory used for the sync can be controlled with the
C<--memory> option:
- rt-fulltext-indexer --memory 10M
+ /opt/rt4/sbin/rt-fulltext-indexer --memory 10M
If there is already an instance of C<rt-fulltext-indexer> running, new
ones will exit abnormally (with exit code 1) and the error message
@@ -180,7 +251,7 @@ and end those processes normally (with exit code 0) using the C<--quiet>
option; this is particularly useful when running the command via
C<cron>:
- sbin/rt-fulltext-indexer --quiet
+ /opt/rt4/sbin/rt-fulltext-indexer --quiet
Instead of being run via C<cron>, this may instead be run via a
DBMS_JOB; read the B<Managing DML Operations for a CONTEXT Index>
@@ -188,4 +259,18 @@ chapter of Oracle's B<Text Application Developer's Guide> for details
how to keep the index optimized, perform garbage collection, and other
tasks.
+=head1 UNINDEXED SEARCH
+
+It is also possible to enable full-text search without database indexing
+support, simply by setting the C<Enable> key of the C<%FullTextSearch>
+option to 1, while leaving C<Indexed> set to 0:
+
+ Set(%FullTextSearch,
+ Enable => 1,
+ Indexed => 0,
+ );
+
+This is not generally suggested, as unindexed full-text searching can
+cause severe performance problems.
+
=cut
diff --git a/rt/docs/hacking.pod b/rt/docs/hacking.pod
index 7c50ee901..23ce51e3a 100644
--- a/rt/docs/hacking.pod
+++ b/rt/docs/hacking.pod
@@ -153,8 +153,14 @@ C<#loc_left_pair> is used for declaring that the I<key> of a
particular C<< key => value >> pair is translatable. This is of
very limited usefulness.
-C<#loc_right_pair> does NOT exist. C<#loc> works in such cases since
-its parser does not extend beyond the string at the end of a line.
+C<#loc_right_pair> does NOT exist. C<#loc> works in such cases since its
+parser does not extend beyond the string at the end of a line. However,
+if the string is I<not> at the end of the line, C<#loc{word}> declares
+that the value associated with the key I<word> (earlier on the same
+line) is to be loc'd. This is useful for inline hashes:
+
+ # Note the string "baz" is to be loc'd
+ foo => { bar => "baz", troz => "zort" }, # loc{bar}
=head1 Development tips
@@ -172,7 +178,7 @@ can create and drop databases:
You'll need to configure RT and make sure you have all the dependencies
before running tests. To do this in place without installing:
- ./configure.ac --with-my-user-group --enable-layout=inplace --with-devel-mode
+ ./configure.ac --with-my-user-group --enable-layout=inplace --enable-developer
make testdeps
make fixdeps
diff --git a/rt/docs/initialdata.pod b/rt/docs/initialdata.pod
index 6445fb0cd..853e711cf 100644
--- a/rt/docs/initialdata.pod
+++ b/rt/docs/initialdata.pod
@@ -70,8 +70,10 @@ descriptions of the values to place in them, is below.
Each hashref in C<@Users> is treated as a new user to create and passed
straight into C<< RT::User->Create >>. All of the normal user fields are
-available, as well as C<Privileged> and C<Disabled> (both booleans) which will
-do the appropriate internal group/flag handling.
+available, as well as C<Privileged> and C<Disabled> (both booleans) which
+will do the appropriate internal group/flag handling. Also accepts an
+C<Attributes> key, which is equivalent to pushing its arrayref of values
+onto C<@Attributes>, below, with C<Object> set to the new user.
For a full list of fields, read the documentation for L<RT::User/Create>.
@@ -131,6 +133,10 @@ groups. An example, using a convenience function to avoid repeating yourself:
}
}
+It also accepts an C<Attributes> key, which is equivalent to pushing its
+arrayref of values onto C<@Attributes>, below, with C<Object> set to the
+new group.
+
=head2 C<@Queues>
push @Queues, {
@@ -140,12 +146,14 @@ groups. An example, using a convenience function to avoid repeating yourself:
};
Creates a new L<RT::Queue> for each hashref. Refer to the documentation of
-L<RT::Queue/Create> for the fields you can use.
+L<RT::Queue/Create> for the fields you can use. It also accepts an
+C<Attributes> key, which is equivalent to pushing its arrayref of values
+onto C<@Attributes>, below, with C<Object> set to the new queue.
+
=head2 C<@CustomFields>
push @CustomFields, {
- Queue => 0,
Name => 'Favorite color',
Type => 'FreeformSingle',
LookupType => 'RT::Queue-RT::Ticket',
@@ -164,10 +172,15 @@ The name of this CF as displayed in RT.
A short summary of what this CF is for.
-=item C<Queue>
+=item C<ApplyTo>
+
+May be a single value, or an array reference of such; each should be
+either an ID or Name. If omitted, the CF is applied globally. This
+should not be used for User or Group custom fields.
-May be a Name or ID. The single queue or array ref of queues to apply this CF
-to. This does not apply when C<LookupType> does not start with C<RT::Queue>.
+This argument may also be passed via C<Queue>, for backwards
+compatibility, which also defaults the C<LookupType> to
+C<RT::Queue-RT::Ticket>.
=item C<Type>
@@ -215,6 +228,7 @@ is for Tickets, Transactions, Users, Groups, or Queues. Possible values:
RT::User # Users
RT::Group # Groups
RT::Queue # Queues
+ RT::Class-RT::Article # Articles
Ticket CFs are the most common, meaning C<RT::Queue-RT::Ticket> is the most
common C<LookupType>.
@@ -247,7 +261,6 @@ field. This only makes sense for "Select" CFs. An example:
my $i = 1;
push @CustomFields, {
- Queue => 0, # Globally applied
LookupType => 'RT::Queue-RT::Ticket', # for Tickets
Name => 'Type of food',
Type => 'SelectSingle', # SelectSingle is the same as: Type => 'Select', MaxValues => 1
@@ -275,6 +288,10 @@ The regular expression text (not C<qr//>!) used to validate values.
=back
+It also accepts an C<Attributes> key, which is equivalent to pushing its
+arrayref of values onto C<@Attributes>, below, with C<Object> set to the
+new custom field.
+
Refer to the documentation and implementation of L<RT::CustomField/Create> and
L<RT::CustomFieldValue/Create> for the full list of available fields and
allowed values.
@@ -285,10 +302,11 @@ C<@ACL> is very useful for granting rights on your newly created records or
setting up a standard system configuration. It is one of the most complex
initialdata structures.
-=head3 Pick a Right
+=head3 Pick one or more C<Right>s
-All ACL definitions expect a key named C<Right> with the internal right name
-you want to grant. The internal right names are visible in RT's admin
+All ACL definitions expect a key named C<Right> with the internal right
+name you want to grant; alternately, it may contain an array reference
+of right names. The internal right names are visible in RT's admin
interface in grey next to the longer descriptions.
=head3 Pick a level: on a queue, on a CF, or globally
@@ -301,6 +319,7 @@ granted. This is B<different> than the user/group/role receiving the right.
=item Granted on a custom field by name (or ID), potentially a global or queue
CF => 'Name',
+ LookupType => 'RT::User', # optional, in case you need to disambiguate
=item Granted on a queue
@@ -311,6 +330,19 @@ granted. This is B<different> than the user/group/role receiving the right.
CF => 'Name',
Queue => 'Name',
+=item Granted on a custom field applied to some other object
+
+ # This finds the CF named "Name" applied to Articles in the
+ # "Responses" class
+ CF => 'Name',
+ LookupType => RT::Article->CustomFieldLookupType,
+ ObjectId => 'Responses',
+
+=item Granted on some other object (article Classes, etc)
+
+ ObjectType => 'RT::Class',
+ ObjectId => 'Name',
+
=item Granted globally
Specifying none of the above will get you a global right.
@@ -446,8 +478,33 @@ L<RT::Template/Create> for the fields you can use.
An array of L<RT::Attribute>s to create. You likely don't need to mess with
this. If you do, know that the key C<Object> is expected to be an
-L<RT::Record> object on which to call C<AddAttribute>. If you don't provide
-C<Object> or it's undefined, C<< RT->System >> will be used.
+L<RT::Record> object or a subroutine reference that returns an object on which
+to call C<AddAttribute>. If you don't provide C<Object> or it's undefined,
+C<< RT->System >> will be used.
+
+Here is an example of using a subroutine reference as a value for Object:
+
+ @Attributes = ({
+ Name => 'SavedSearch',
+ Description => 'New Tickets in SomeQueue',
+ Object => sub {
+ my $GroupName = 'SomeQueue Group';
+ my $group = RT::Group->new( RT->SystemUser );
+
+ my( $ret, $msg ) = $group->LoadUserDefinedGroup( $GroupName );
+ die $msg unless $ret;
+
+ return $group;
+ },
+ Content => {
+ Format => <<' END_OF_FORMAT',
+ ....
+ END_OF_FORMAT
+ Query => "Status = 'new' AND Queue = 'SomeQueue'",
+ OrderBy => 'id',
+ Order => 'DESC'
+ },
+ });
=head2 C<@Initial>
@@ -471,7 +528,7 @@ to easily create B<Classes>, B<Topics>, or B<Articles> from initialdata files.
=head1 Running an initialdata file
- sbin/rt-setup-database --action insert --datafile /path/to/your/initialdata
+ /opt/rt4/sbin/rt-setup-database --action insert --datafile /path/to/your/initialdata
This may prompt you for a database password.
diff --git a/rt/docs/reminders.pod b/rt/docs/reminders.pod
new file mode 100644
index 000000000..e3af88133
--- /dev/null
+++ b/rt/docs/reminders.pod
@@ -0,0 +1,67 @@
+=head1 Reminders
+
+Reminders can be attached to a ticket to notify you take some action
+on the ticket. Although there are fields like "Due" on tickets, some
+tickets have dependencies or sub-tasks that need to be completed before you
+can do the ticket. For a "Deploy New Certificate" ticket, for example, you may
+need to remind yourself to order the new cert first.
+
+Reminders are sort of mini-tickets and in fact they are implemented as
+tickets themselves.
+
+Each Reminder has:
+
+=over
+
+=item * Subject
+
+=item * Owner
+
+=item * Due date
+
+=item * Status (new, open, resolved, ...)
+
+=back
+
+=head1 Creating a Reminder
+
+Reminders are attached to tickets, so you create them in the Reminders section of
+the ticket display. Once you give it an Owner and a Due date, the Reminder will
+appear on the Owner's "At-a-glance" page by default.
+
+If you don't see reminders, it may be turned off. Display of reminders can be
+disabled with the C<$EnableReminders> flag in C<RT_SiteConfig.pm>. By default,
+reminders are turned on.
+
+=head1 Email Reminders
+
+While seeing reminders in the web display is handy, you may also want to send out
+email based on reminders that are due or are soon to be due. You can use the
+C<rt-crontool> utility to schedule a job to send these emails for you.
+
+To schedule the reminders, add a line like the following to your RT crontab:
+
+ 0 6 * * * root /opt/rt4/bin/rt-crontool \
+ --search RT::Search::FromSQL \
+ --search-arg 'Type = "reminder" and (Status = "open" or Status = "new")' \
+ --condition RT::Condition::BeforeDue \
+ --condition-arg 2d \
+ --action RT::Action::Notify \
+ --action-arg Owner,AlwaysNotifyActor \
+ --transaction first \
+ --template 'Reminder'
+
+If you have modified the status values for reminders such that you have more
+active statuses than "open" and "new" you should add them as part of your
+"FromSQL" query. You typically won't want to send out email on "resolved"
+reminders, but you could add that to the query as well.
+
+The argument to C<RT::Condition::BeforeDue> is an amount of time in the form
+"1d2h3m4s" for 1 day and 2 hours and 3 minutes and 4 seconds. As shown in the
+example, single values can also be passed. The run frequency in your crontab
+should be consistent with the time period you set to avoid missing reminders.
+
+The template value refers to a Template in your RT system. You can use the
+default Reminder template or create your own in Admin > Global > Templates >
+Create. You can look at the default template for examples of the values
+you can use to populate the email.
diff --git a/rt/docs/rt_perl.pod b/rt/docs/rt_perl.pod
new file mode 100644
index 000000000..513bb596f
--- /dev/null
+++ b/rt/docs/rt_perl.pod
@@ -0,0 +1,163 @@
+=head1 Perl for RT
+
+RT runs on Perl and there are many different approaches to installing
+and maintaining your Perl installation. This document reviews some of the
+options and pros and cons of different approaches.
+
+Perl has been around for a long time, so many different versions are
+installed on systems everywhere. We try to maintain a reasonable
+timeframe for backward compatibility, but beyond a certain age, running
+old versions of Perl is no longer safe or even possible with modern
+applications. We currently require at least version 5.10.1 which is
+old enough to be default on OSes from many years ago, but sufficiently
+new to support RT and the modules RT depends on.
+
+=head1 Default System Perls
+
+All Linux and Unix-type variants come with a version of Perl installed
+and many provide Perl and many CPAN modules as packages for easier
+maintenance and management. You can run RT on the vendor Perl on your
+system as long as it meets the minimum version requirement.
+
+When you run C<make testdeps> as part of your RT installation,
+you'll likely find that the RT will require you to upgrade some of the
+dependent modules to newer versions than those provided in the
+vendor packages. If you have any IT policy requirements to only use
+vendor packaged versions of software, this might be an issue. If
+so, you can consider installing an RT-only version of Perl.
+See L<"Stand-alone Perl">.
+
+Occasionally vendors introduce their own changes to their packaged version
+of Perl or modules and these might create issues when running RT.
+Also, the system Perl is also often used by other utilities on the system
+and modifying the default Perl too heavily can introduce issues for these
+other applications which might rely on an older version of a module, for
+example. Consider these factors before modifying your system Perl.
+
+Many packaging systems restore the system to the official packaged
+version of software when updates are applied. Since a Perl update is
+likely to have many or all packaged Perl modules as dependencies, this
+means an update to the vendor Perl will restore all of the modules you
+upgraded to their previous version. Therefore, if you decide to use
+the vendor Perl on your system, you need to note somewhere that you'll
+need to upgrade RT's dependencies any time the system Perl packages are
+updated. The L<rt-test-dependencies> tool provided in RT's sbin
+directory can help with this.
+
+=head1 Stand-alone Perl
+
+To avoid having modules unexpectedly downgraded as described above,
+we typically recommend installing a separate Perl to run RT. In doing so
+you take on the extra responsibility to patch that Perl if necessary,
+but you can plan this work as necessary rather than being surprised if
+RT has issues after a security package update is applied.
+
+Having a Perl version installed specifically for RT gives you the flexibility
+to upgrade or install a new module if needed to add a new extension or address
+a bug. You can then test just RT and not worry about possible side-effects
+on your system.
+
+You can install this Perl in an alternate location like C</opt/perl>, or
+to make it clear it's for RT, even C</opt/rt4/perl>. To make future
+upgrades easier, install in a version-specific directory like
+C</opt/perl-5.14.2>, then symlink C</opt/perl> to that directory. This
+makes it easy to switch to a newer version of Perl later by installing
+and just moving the symlink.
+
+If you install a stand-alone Perl, update your shell to put the path
+of the new C<perl> executable before the system Perl. You may want
+to set this in your shell profile for the user account you use to manage
+RT so you don't accidentally run commands or install modules in the
+wrong Perl installation.
+
+The following sections describe several approaches to installing a
+stand-alone Perl.
+
+=head2 Install from Source
+
+You can download Perl directly from L<http://www.perl.org> and follow
+the installation instructions. Typically this involves running C<Configure>,
+then C<make && make test && sudo make install>. For most installations,
+this C<Configure> command should be sufficient:
+
+ ./Configure -d -Dprefix=/opt/perl
+
+You can set the prefix to wherever you want Perl installed. Read the
+documentation provided with the distribution for more options.
+
+=head2 Perlbrew
+
+L<Perlbrew|http://perlbrew.pl> is a tool that makes it easy to manage multiple
+Perl installations. Once installed, the C<perlbrew> command provides options to
+build various versions of Perl, switch between version, update installed
+versions, and more.
+
+By default, C<perlbrew> installs all of its Perls in your C<$HOME> directory. If
+you want to install in an alternate location, you can set the C<PERLBREW_ROOT>
+environment variable:
+
+ export PERLBREW_ROOT=/opt/perl5
+ curl -kL http://install.perlbrew.pl | bash
+
+Since C<perlbrew> has a C<switch> command to use different installed Perl
+versions, you don't need to manually manage symlinks as described above.
+
+=head2 mod_perl
+
+If you plan to run RT with L<mod_perl|http://perl.apache.org> on a 64-bit system, you
+may need to run Configure with these options:
+
+ ./Configure -d -Dprefix=/opt/perl -A ccflags=-fPIC
+
+Then make sure you use your stand-alone perl when building and installing
+mod_perl. You find more details on these flags in the
+L<mod_perl installation documentation|http://perl.apache.org/docs/2.0/user/install/install.html#Prerequisites>.
+
+=head1 CPAN Modules
+
+RT requires modules from the
+L<Comprehensive Perl Archive Network|http://www.cpan.org> to run.
+Below are a few of the tools available to help download and install
+these modules from CPAN. These tools can work with RT's L<rt-test-dependencies>
+tool and the C<make testdeps> and C<make fixdeps> part of the installation
+process to get these modules installed.
+
+=head2 CPAN Shell
+
+The traditional tool for managing Perl modules is the CPAN shell,
+accessed with the C<cpan> command installed as part of Perl. To set up
+C<cpan> on an initial install, run the C<cpan> command and follow the
+prompts to set the initial configuration. You can set each option or allow
+it to automatically set some sensible defaults.
+
+The main options you'll need to set are the list of download servers and
+options for C<make install>. For download servers, you'll typically want to
+select some mirrors geographically close to you. If you typically run installs
+using C<sudo>, set C<make_install_make_command> to C<'sudo make'> and
+C<mbuild_install_build_command> to C<'sudo ./Build'>. Then install
+the CPAN bundle:
+
+ cpan>install Bundle::CPAN
+
+This installs some additional modules to add features to C<cpan>.
+
+Once you finish this initialization, RT's C<make fixdeps> should be able
+to handle the rest. Any time you need to install a new module or upgrade
+a module, you can just type C<cpan> and manage it from the cpan shell.
+
+=head2 cpanminus
+
+C<cpanminus>, or C<cpanm>, is a utility built to make it as easy as possible
+to install modules from CPAN. You can install the L<App::cpanminus> module
+itself from CPAN, or have it install itself:
+
+ curl -L http://cpanmin.us | perl - --sudo App::cpanminus
+
+Once installed, set the C<RT_FIX_DEPS_CMD> environment variable to
+have RT use C<cpanm> to install modules:
+
+ export RT_FIX_DEPS_CMD=/opt/perl/bin/cpanm
+
+Then run C<make fixdeps> and let RT install all of its dependencies.
+
+=cut
diff --git a/rt/docs/schema.dot b/rt/docs/schema.dot
index d81ceee12..d70141a03 100644
--- a/rt/docs/schema.dot
+++ b/rt/docs/schema.dot
@@ -57,8 +57,11 @@ edge [
"Scrips" [shape = record, fontsize = 18, label = "<col0> \N " ];
"Scrips" -> "ScripConditions" [label="ScripCondition → id"];
"Scrips" -> "ScripActions" [label="ScripAction → id"];
-"Scrips" -> "Templates" [label="Template → id"];
-"Scrips" -> "Queues" [label="Queue → id"];
+"Scrips" -> "Templates" [label="Template → Name"];
+"Scrips" -> "ObjectScrips" [label="id → Scrip"]
+
+"ObjectScrips" [shape = record, fontsize = 18, label = "<col0> \N " ];
+"ObjectScrips" -> "Queues" [label="ObjectId → id"];
"Templates" [shape = record, fontsize = 18, label = "<col0> \N " ];
"Templates" -> "Queues" [label ="Queue → id" ];
diff --git a/rt/docs/security.pod b/rt/docs/security.pod
index 620f8687c..5bf42919c 100644
--- a/rt/docs/security.pod
+++ b/rt/docs/security.pod
@@ -32,11 +32,7 @@ months before being added to the public RT repository.
Protect your RT installation by making it only accessible via SSL. This
will protect against users' passwords being sniffed as they go over the
-wire, as well as helping prevent phishing attacks. If you use SSL, you
-will need to install some additional Perl libraries so that C<rt-mailgate>
-can connect. You can use the C<--enable-ssl-mailgate> command to
-configure to automate the installation of these dependencies. This is
-documented further in step 10 of the README.
+wire, as well as helping prevent phishing attacks.
You should use a certificate signed by a reputable authority, or at very
least a certificate signed by a consistent local CA, which you configure
diff --git a/rt/docs/web_deployment.pod b/rt/docs/web_deployment.pod
index 5a9bd93a8..a6cba442b 100644
--- a/rt/docs/web_deployment.pod
+++ b/rt/docs/web_deployment.pod
@@ -22,12 +22,6 @@ to use L<Starman>, a high performance preforking server:
/opt/rt4/sbin/rt-server --server Starman --port 8080
-B<NOTICE>: After you run the standalone server as root, you will need to
-remove your C<var/mason_data> directory, or the non-standalone servers
-(Apache, etc), which run as a non-privileged user, will not be able to
-write to it and will not work.
-
-
=head2 Apache
B<WARNING>: Both C<mod_speling> and C<mod_cache> are known to break RT.
@@ -35,6 +29,9 @@ C<mod_speling> will cause RT's CSS and JS to not be loaded, making RT
appear unstyled. C<mod_cache> will cache cookies, making users be
spontaneously logged in as other users in the system.
+See also L<authentication/Apache configuration>, in case you intend to
+use Apache to provide authentication.
+
=head3 mod_fastcgi
# Tell FastCGI to put its temporary files somewhere sane; this may
@@ -52,13 +49,17 @@ spontaneously logged in as other users in the system.
AddDefaultCharset UTF-8
- Alias /NoAuth/images/ /opt/rt4/share/html/NoAuth/images/
ScriptAlias / /opt/rt4/sbin/rt-server.fcgi/
DocumentRoot "/opt/rt4/share/html"
<Location />
- Order allow,deny
- Allow from all
+ <IfVersion >= 2.4> # For Apache 2.4
+ Require all granted
+ </IfVersion>
+ <IfVersion < 2.4> # For Apache 2.2
+ Order allow,deny
+ Allow from all
+ </IfVersion>
Options +ExecCGI
AddHandler fastcgi-script fcgi
@@ -89,13 +90,17 @@ to return to the old default.
AddDefaultCharset UTF-8
- Alias /NoAuth/images/ /opt/rt4/share/html/NoAuth/images/
ScriptAlias / /opt/rt4/sbin/rt-server.fcgi/
DocumentRoot "/opt/rt4/share/html"
<Location />
- Order allow,deny
- Allow from all
+ <IfVersion >= 2.4> # For Apache 2.4
+ Require all granted
+ </IfVersion>
+ <IfVersion < 2.4> # For Apache 2.2
+ Order allow,deny
+ Allow from all
+ </IfVersion>
Options +ExecCGI
AddHandler fcgid-script fcgi
@@ -128,8 +133,13 @@ C<SetHandler modperl>, as the example below uses.
DocumentRoot "/opt/rt4/share/html"
<Location />
- Order allow,deny
- Allow from all
+ <IfVersion >= 2.4> # For Apache 2.4
+ Require all granted
+ </IfVersion>
+ <IfVersion < 2.4> # For Apache 2.2
+ Order allow,deny
+ Allow from all
+ </IfVersion>
SetHandler modperl
PerlResponseHandler Plack::Handler::Apache2
@@ -187,10 +197,6 @@ With the nginx configuration:
fastcgi_param SERVER_NAME $server_name;
fastcgi_pass 127.0.0.1:9000;
}
-
- location /NoAuth/images {
- root /opt/rt4/share/html;
- }
}
@@ -198,21 +204,16 @@ With the nginx configuration:
server.modules += ( "mod_fastcgi" )
$HTTP["host"] =~ "^rt.example.com" {
- alias.url = (
- "/NoAuth/images/" => "/opt/rt4/share/html/NoAuth/images/",
- )
- $HTTP["url"] !~ "^/NoAuth/images/" {
- fastcgi.server = (
- "/" => (
- "rt" => (
- "port" => "9000",
- "bin-path" => "/opt/rt4/sbin/rt-server.fcgi",
- "check-local" => "disable",
- "fix-root-scriptname" => "enable",
- )
+ fastcgi.server = (
+ "/" => (
+ "rt" => (
+ "socket" => "/opt/rt4/var/socket",
+ "bin-path" => "/opt/rt4/sbin/rt-server.fcgi",
+ "check-local" => "disable",
+ "fix-root-scriptname" => "enable",
)
)
- }
+ )
}
@@ -226,14 +227,13 @@ F<RT_SiteConfig.pm>:
Set($WebPath, "/rt");
Then you need to update your Apache configuration to match. Prefix any RT
-related C<Alias>, C<ScriptAlias> and C<Location> directives with C</rt>. You
+related C<ScriptAlias> and C<Location> directives with C</rt>. You
should also make sure C<DocumentRoot> is B<not> set to
C</opt/rt4/share/html/>, otherwise RT's source will be served from C</>.
For example: if you're using the sample FastCGI config above, you might change
the relevant directives to:
- Alias /rt/NoAuth/images/ /opt/rt4/share/html/NoAuth/images/
ScriptAlias /rt /opt/rt4/sbin/rt-server.fcgi/
# Set DocumentRoot as appropriate for the other content you want to serve
@@ -248,4 +248,3 @@ C<Location> directive.
If you're not using Apache, please see L<Plack::Handler::FCGI> or the web
server's own documentation for configuration examples.
-
diff --git a/rt/docs/writing_extensions.pod b/rt/docs/writing_extensions.pod
new file mode 100644
index 000000000..10d146633
--- /dev/null
+++ b/rt/docs/writing_extensions.pod
@@ -0,0 +1,376 @@
+=head1 Introduction
+
+RT has a lot of core features, but sometimes you have a problem to solve
+that's beyond the scope of just configuration. The standard way to add
+features to RT is with an extension. You can see the large number of
+freely available extensions on CPAN under the RT::Extension namespace
+to get an idea what's already out there. We also list some of the more
+useful extensions on the Best Practical website at
+L<http://www.bestpractical.com/rt/extensions.html>
+
+After looking through those, you still may not find what you need, so
+you'll want to write your own extension. Through the years there have
+been different ways to safely and effectively add things onto RT.
+This document describes the current best practice which should allow
+you to add what you need and still be able to safely upgrade RT
+in the future.
+
+=head1 Getting Started
+
+There are a few modules that will set up your initial sandbox for you
+to get you started. Install these modules from CPAN:
+
+=over
+
+=item Module::Install::RTx
+
+Sets up your extension to be installed using Module::Install.
+
+=item Dist::Zilla::MintingProfile::RTx
+
+Provides some tools for managing your distribution. Handy even if you're
+not putting your code on CPAN.
+
+=back
+
+If this is your first time using L<Dist::Zilla>, you can set up your
+CPAN details by running:
+
+ dzil setup
+
+You can read about L<Dist::Zilla> and the C<dzil> command at L<http://dzil.org>.
+
+Change to the directory that will be the parent directory for your new
+extension and run the following, replacing Demo with a descriptive name
+for your new extension:
+
+ dzil new -P RTx RT-Extension-Demo
+
+You'll see something like:
+
+ [DZ] making target dir /some-dir/RT-Extension-Demo
+ [DZ] writing files to /some-dir/RT-Extension-Demo
+ [DZ] dist minted in ./RT-Extension-Demo
+
+If you're stuck on a name, take a look at some of the existing RT extensions.
+You can also ask around IRC (#rt on irc.perl.org) to see what people think
+makes sense for what the extension will do.
+
+You'll now have a directory with the basic files for your extension.
+Included is a F<gitignore> file, which is handy if you use git for your version
+control like we do. If you don't use git, feel free to delete it, but we hope
+you're using some sort of version control for your work.
+
+=head1 Extension Directories
+
+There are several places to put code to provide your new features
+and if you follow the guidelines below, you'll make sure things
+get installed in the right places when you're ready to use it. These standards
+apply to RT 4.0 and 4.2 and any differences between the two are noted below.
+
+=head2 Module Code
+
+In your new extension directory you'll already have a
+C<lib/RT/Extension/Demo.pm> file, which is just a standard perl module.
+As you start writing code, you can use all of the standard RT libraries
+because your extension will be running in the context of RT and those
+are already pulled in. You can also create more modules under C<lib>
+as needed.
+
+=head2 Mason Code
+
+RT provides callbacks throughout its Mason templates to give you hooks to
+add features. The easiest way to modify RT is to add Mason template files
+that will use these callbacks. See L</Callbacks> for more information.
+Your Mason templates should go in an C<html> directory with the appropriate
+directory structure to make sure the callbacks are executed.
+
+If you are creating completely new pages for RT, you can put these under the
+C<html> directory also. You can create subdirectories as needed to add the
+page to existing RT paths (like Tools) or to create new directories for your
+extension.
+
+=head2 CSS and Javascript
+
+Where these files live differs between RT 4.2 and above, and RT 4.0 and
+below; if you need your extension to be compatible with both, you may
+need to provide both configurations. On RT 4.2 and above, create a
+C<static> directory at the top level under your extension, and under
+that a C<css> directory and a C<js> directory. Before RT 4.2, you should
+create C<css> and C<js> directories in C<html/NoAuth/>.
+
+To add files to RT's include paths, you can use the L<RT/AddStyleSheets> and
+L<RT/AddJavascript> methods available in the L<RT> module. You can put the
+lines near the top of your module code (in your "Demo.pm" file). If you set up
+the paths correctly, you should only need to set the file names like this:
+
+ RT->AddStyleSheets('myextension.css');
+ RT->AddJavaScript('myextension.js');
+
+=head2 Creating Objects in RT
+
+If you need to have users create a group, scrip, template, or some other
+object in their RT instance, you can automate this using an F<initialdata>
+file. If you need this, the file should go in the C<etc> directory. This will
+allow users to easily run the F<initialdata> file when installing with:
+
+ make initdb
+
+=head2 Module::Install Files
+
+As mentioned above, the RT extension tools are set up to use L<Module::Install>
+to manage the distribution. When you run
+
+ perl Makefile.PL
+
+for the first time, L<Module::Install> will create an C<inc> directory for all
+of the files it needs. Since you are the author, a C<.author> directory
+(note the . in the directory name) is created for you in the C<inc>
+directory. When L<Module::Install> detects this directory, it does things only
+the author needs, like pulling in modules to put in the C<inc> directory.
+Once you have this set up, L<Module::Install> should mostly do the right thing.
+You can find details in the module documentation.
+
+=head2 Tests
+
+=head3 Test Directory
+
+You can create tests for your new extension just as with other perl code
+you write. However, unlike typical CPAN modules where users run the tests
+as a step in the installation process, RT users installing extensions don't
+usually run tests. This is because running the tests requires your RT to
+be set up in development mode which involves installing some additional
+modules and having a test database. To prevent users from accidentally
+running the tests, which will fail without this testing setup, we put them in
+a C<xt> directory rather than the typical C<t> directory.
+
+=head3 Writing Extension Tests
+
+If you want to write and run tests yourself, you'll need a development RT
+instance set up. Since you are building an extension, you probably already have
+one. To start with testing, set the C<RTHOME> environment variable to the base
+directory of your RT instance so your extension tests run against the right
+instance. This is especially useful if you have your test RT installed in a non-standard location.
+
+Next, you need to subclass from L<RT::Test>
+which gives you access to the test RT and a test database for running
+tests. For this, you'll create a F<Test.pm> file in your C<lib> tree.
+The easiest way to set up the test module to pull in F<RT::Test> is to look at
+an example extension. L<RT::Extension::RepeatTicket>, for example, has a
+testing configuration you can borrow from.
+
+You'll notice that the file included in the extension is
+F<lib/RT/Extension/RepeatTicket/Test.pm.in>. This is because there are paths
+that are set based on your RT location, so the actual F<Test.pm> file is
+written when you run F<Makefile.PL> with appropriate paths substituted
+when F<Makefile.PL> is run. L<Module::Install> provides an interface to make
+this easy with a C<substitute> feature. The substitution code is in the
+F<Makefile.PL> file and you can borrow that as well.
+
+Once you have that set up, add this to the top of your test files:
+
+ use RT::Extension::Demo::Test tests => undef;
+
+and you'll be able to run tests in the context of a fully functioning RT
+instance. The L<RT::Test>
+documentation describes some of the helper methods available and you can
+look at other extensions and the RT source code for examples of how to
+do things like create tickets, queues, and users, how to set rights, and
+how to modify tickets to simulate various RT tasks.
+
+If you have a command-line component in your extension, the easiest way
+to test it is to set up a C<run> method using the Modulino approach.
+You can find an example of this approach in L<RT::Extension::RepeatTicket>
+in the F<bin> directory.
+
+=head2 Patches
+
+If you need to provide patches to RT for any reason, you can put them in
+a C<patches> directory. See L</"Changes to RT"> for more information.
+
+=head1 Callbacks
+
+The RT codebase, mostly the Mason templates, contains hooks called callbacks
+that make it easy to add functionality without changing the RT code itself.
+RT invokes callbacks by looking in the source directories for files that might
+have extra code.
+
+=head2 Directory Structure
+
+RT looks in the F<local/plugins> directory under the RT base directory for
+extensions registered with the C<@Plugins> configuration. RT then uses the
+following structure when looking for callbacks:
+
+ local/plugins/[ext name]/html/Callbacks/[custom name]/[rt mason path]/[callback name]
+
+The extension installation process will handle some of this for you by putting
+your html directory under F<local/plugins/[ext name]> as part of the
+installation process. You need to make sure the path under C<html> is correct
+since that is installed as-is.
+
+The C<Callbacks> directory is required. The next directory can be named
+anything and is provided to allow RT owners to keep local files organized
+in a way that makes sense to them. In the case of
+an extension, you should name the directory the same as your extension.
+So if your extension is C<RT::Extension::Demo>, you should create a
+F<RT-Extension-Demo> directory under F<Callbacks>.
+
+The rest of the path is determined by the RT Mason code and the callback you
+want to use. You can find callbacks by looking for calls to the C<callback>
+method in the RT Mason code. You can use something like this in your base
+RT directory:
+
+ # find share/html/ | xargs grep '\->callback'
+
+As an example, assume you wanted to modify the ticket update page to put
+something after the Time Worked field. You run the above and see there is
+a callback in F<share/html/Ticket/Update.html> that looks like this:
+
+ $m->callback( %ARGS, CallbackName => 'AfterWorked', Ticket => $TicketObj );
+
+You look at the F<Update.html> file and see that the callback is located
+right after the Time Worked field. To add some code that RT will
+run at that point, you would create the directory:
+
+ html/Callbacks/RT-Extension-Demo/Ticket/Update.html/
+
+Note that F<Update.html> is a file in the RT source, but it becomes a directory
+in your extension code. You then create a file with the name of the
+callback, in this case F<AfterWorked>, and that's where you put your code.
+So the full path and file would be:
+
+ html/Callbacks/RT-Extension-Demo/Ticket/Update.html/AfterWorked
+
+If you see a callback that doesn't have a C<CallbackName> parameter, name
+your file F<Default> and it will get invoked since that is the default
+callback name when one isn't provided.
+
+=head2 Callback Parameters
+
+When you look at callbacks using the method above, the other important
+thing to consider is the parameter list. In addition to the C<CallbackName>,
+the other parameters listed in the callback will be passed to you
+to use as you develop your extension.
+
+Getting these parameters is important because you'll likely need them
+in your code, getting data from the current ticket object, for example.
+These values are also often passed by reference, which allows you to modify
+them, potentially changing the behavior of the RT template when it
+continues executing after evaluating your code.
+
+Some examples are adding a C<Limit> call to modify search results on
+a L<DBIx::SearchBuilder> object, or setting a flag like C<$skip_update>
+for a callback like this:
+
+ $m->callback( CallbackName => 'BeforeUpdate', ARGSRef => \%ARGS, skip_update => \$skip_update,
+ checks_failure => $checks_failure, results => \@results, TicketObj => $TicketObj );
+
+There are many different callbacks in RT and these are just a few examples
+to give you idea what you can do in your callback code. You can also look
+at other extensions for examples of how people use callbacks to modify
+and extend RT.
+
+=head1 Adding and Modifying Menus
+
+You can modify all of RT's menus using callbacks as described in L</Callbacks>.
+The file in RT that controls menus is:
+
+ share/html/Elements/Tabs
+
+and you'll find a Privileged and SelfService callback which gives you access
+to those two sets of menus. In those callbacks, you can add to or change
+the main menu, the page menu, or the page widgets.
+
+You can look at the F<Tabs> file itself for examples of adding menu items.
+The menu object is a L<RT::Interface::Web::Menu> and you can find details on
+the available parameters in the documentation.
+
+Here are some simple examples of what you might do in a callback:
+
+ <%init>
+ # Add a brand new root menu item
+ my $bps = Menu()->child(
+ 'bps', # any unique identifier
+ title => 'Corporate',
+ path => 'http://bestpractical.com'
+ );
+
+ #Add a submenu item to this root menu item
+ $bps->child(
+ 'wiki',
+ title => 'Wiki',
+ path => 'http://wiki.bestpractical.com',
+ );
+
+ #Retrieve the 'actions' page menu item
+ if (my $actions = PageMenu->child('actions')) {
+ $actions->child(
+ 'newitem',
+ title => loc('New Action'), path => '/new/thing/here',
+ )
+ }
+ </%init>
+
+=head1 Changes to RT
+
+When writing an extension, the goal is to provide all of the new functionality
+in your extension code using standard interfaces into RT. However,
+sometimes when you're working on an extension, you'll find you really need
+a change in RT itself to make your extension work. Often this is something
+like adding a new callback or a method to a core module that would be
+helpful for everyone.
+
+Since any change to RT will only be included in the next version and
+forward, you'll need to provide something for users on current or older
+versions of RT. An easy way to do this is to provide a patch in your
+extension distribution. In general, you should only provide patches
+if you know they will eventually be merged into RT. Otherwise, you
+may have to provide versions of your patches for each release of RT.
+You can read more about getting changes accepted into RT in the
+L<hacking> document. We generally accept patches that add new callbacks.
+
+Create a C<patches> directory in your extension distribution to hold
+your patch files. Name the patch files with the latest version of RT
+that needs the patch. For example, if the patch is needed for RT 4.0.7,
+name your patch C<4.0.7-some-patch.diff>. That tells users that if they
+are using RT 4.0.7 or earlier, they need to apply the patch. If your
+extension can be used for RT 3.8, you'll likely need to provide different
+patches using the same naming convention.
+
+Also remember to update your install documentation to remind users to apply
+the patch.
+
+=head1 Preparing for CPAN
+
+When you have your extension ready and want to release it to the world, you
+can do so with a few simple steps.
+
+Assuming you have run C<perl Makefile.PL> and you created the F<inc/.author>
+directory as described above, a F<README> file will be created for you. You can
+now type:
+
+ make manifest
+
+and a F<MANIFEST> file will be created. It should contain all of the needed
+to install and run your extension. If you followed the steps above, you'll have
+also have a F<inc> directory which contains L<Module::Install> code. Note that
+this code should also be included with your extension when you release it as
+it's part of the install process.
+
+Next, check to see if everything is ready with:
+
+ make distcheck
+
+If anything is missing, it will be reported and you can go fix it.
+When the check is clean, run:
+
+ make dist
+
+and a new distribution will be created in the form of a tarred and gzipped
+file.
+
+Now you can upload to cpan with the F<cpan-upload> utility provided by
+L<CPAN::Uploader> or your favorite method of uploading to CPAN.
+
+=cut
+