1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
6 # <jesse@bestpractical.com>
8 # (Except where explicitly superseded by other copyright notices)
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 # General Public License for more details.
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 # CONTRIBUTION SUBMISSION POLICY:
30 # (The following paragraph is not intended to limit the rights granted
31 # to you to modify and distribute this software under the terms of
32 # the GNU General Public License and is only of importance to you if
33 # you choose to contribute your changes and enhancements to the
34 # community by submitting them to Best Practical Solutions, LLC.)
36 # By intentionally submitting any modifications, corrections or
37 # derivatives to this work, or any other work intended for use with
38 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
39 # you are the copyright holder for those contributions and you grant
40 # Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
41 # royalty-free, perpetual, license to use, copy, create derivative
42 # works based on those contributions, and sublicense and distribute
43 # those contributions and any derivatives thereof.
45 # END BPS TAGGED BLOCK }}}
52 use vars qw($VERSION $System $SystemUser $Nobody $Handle $Logger
64 $MasonLocalComponentRoot
69 $VERSION = '@RT_VERSION_MAJOR@.@RT_VERSION_MINOR@.@RT_VERSION_PATCH@';
70 $CORE_CONFIG_FILE = "@CONFIG_FILE_PATH@/RT_Config.pm";
71 $SITE_CONFIG_FILE = "@CONFIG_FILE_PATH@/RT_SiteConfig.pm";
75 $BasePath = '@RT_PATH@';
77 $EtcPath = '@RT_ETC_PATH@';
78 $BinPath = '@RT_BIN_PATH@';
79 $VarPath = '@RT_VAR_PATH@';
80 $LocalPath = '@RT_LOCAL_PATH@';
81 $LocalEtcPath = '@LOCAL_ETC_PATH@';
82 $LocalLexiconPath = '@LOCAL_LEXICON_PATH@';
84 # $MasonComponentRoot is where your rt instance keeps its mason html files
86 $MasonComponentRoot = '@MASON_HTML_PATH@';
88 # $MasonLocalComponentRoot is where your rt instance keeps its site-local
91 $MasonLocalComponentRoot = '@MASON_LOCAL_HTML_PATH@';
93 # $MasonDataDir Where mason keeps its datafiles
95 $MasonDataDir = '@MASON_DATA_PATH@';
97 # RT needs to put session data (for preserving state between connections
98 # via the web interface)
99 $MasonSessionDir = '@MASON_SESSION_PATH@';
109 A fully featured request tracker package
115 Load RT's config file. First, the site configuration file
116 (C<RT_SiteConfig.pm>) is loaded, in order to establish overall site
117 settings like hostname and name of RT instance. Then, the core
118 configuration file (C<RT_Config.pm>) is loaded to set fallback values
119 for all settings; it bases some values on settings from the site
122 In order for the core configuration to not override the site's
123 settings, the function C<Set> is used; it only sets values if they
124 have not been set already.
129 local *Set = sub { $_[0] = $_[1] unless defined $_[0] };
130 if ( -f "$SITE_CONFIG_FILE" ) {
131 require $SITE_CONFIG_FILE
132 || die ("Couldn't load RT config file '$SITE_CONFIG_FILE'\n$@");
134 require $CORE_CONFIG_FILE
135 || die ("Couldn't load RT config file '$CORE_CONFIG_FILE'\n$@");
141 Conenct to the database, set up logging.
147 #Get a database connection
150 #RT's system user is a genuine database user. its id lives here
151 $SystemUser = new RT::CurrentUser();
152 $SystemUser->LoadByName('RT_System');
154 #RT's "nobody user" is a genuine database user. its ID lives here.
155 $Nobody = new RT::CurrentUser();
156 $Nobody->LoadByName('Nobody');
158 $System = RT::System->new();
165 =head2 ConnectToDatabase
167 Get a database connection
171 sub ConnectToDatabase {
173 unless ($Handle && $Handle->dbh && $Handle->dbh->ping) {
174 $Handle = RT::Handle->new();
181 Create the RT::Logger object.
187 # We have to set the record separator ($, man perlvar)
188 # or Log::Dispatch starts getting
189 # really pissy, as some other module we use unsets it.
192 use Log::Dispatch 1.6;
194 unless ($RT::Logger) {
196 $RT::Logger=Log::Dispatch->new();
198 if ($RT::LogToFile) {
199 my ($filename, $logdir);
200 if ($RT::LogToFileNamed =~ m![/\\]!) {
201 # looks like an absolute path.
202 $filename = $RT::LogToFileNamed;
203 ($logdir) = $RT::LogToFileNamed =~ m!^(.*[/\\])!;
206 $filename = "$RT::LogDir/$RT::LogToFileNamed";
207 $logdir = $RT::LogDir;
210 unless ( -d $logdir && ( ( -f $filename && -w $filename ) || -w $logdir ) ) {
211 # localizing here would be hard when we don't have a current user yet
212 # die $self->loc("Log directory [_1] not found or couldn't be written.\n RT can't run.", $RT::LogDir);
213 die ("Log file $filename couldn't be written or created.\n RT can't run.");
216 package Log::Dispatch::File;
217 require Log::Dispatch::File;
220 $RT::Logger->add(Log::Dispatch::File->new
222 min_level=> $RT::LogToFile,
223 filename=> $filename,
225 callbacks => sub { my %p = @_;
226 my ($package, $filename, $line) = caller(5);
227 return "[".gmtime(time)."] [".$p{level}."]: $p{message} ($filename:$line)\n"}
233 if ($RT::LogToScreen) {
234 package Log::Dispatch::Screen;
235 require Log::Dispatch::Screen;
236 $RT::Logger->add(Log::Dispatch::Screen->new
238 min_level => $RT::LogToScreen,
239 callbacks => sub { my %p = @_;
240 my ($package, $filename, $line) = caller(5);
241 return "[".gmtime(time)."] [".$p{level}."]: $p{message} ($filename:$line)\n"
247 if ($RT::LogToSyslog) {
248 package Log::Dispatch::Syslog;
249 require Log::Dispatch::Syslog;
250 $RT::Logger->add(Log::Dispatch::Syslog->new
253 min_level => $RT::LogToSyslog,
254 callbacks => sub { my %p = @_;
255 my ($package, $filename, $line) = caller(5);
257 # syswrite() cannot take utf8; turn it off here.
258 Encode::_utf8_off($p{message});
260 if ($p{level} eq 'debug') {
262 return "$p{message}\n" }
264 return "$p{message} ($filename:$line)\n"}
274 # {{{ Signal handlers
276 ## This is the default handling of warnings and die'ings in the code
277 ## (including other used modules - maybe except for errors catched by
278 ## Mason). It will log all problems through the standard logging
279 ## mechanism (see above).
281 $SIG{__WARN__} = sub {
283 $w =~ s/(?:\r*\n)+$//;
284 # The 'wide character' warnings has to be silenced for now, at least
285 # until HTML::Mason offers a sane way to process both raw output and
287 $RT::Logger->warning($w) if index($w, 'Wide character in ') != 0;
290 #When we call die, trap it and log->crit with the value of the die.
292 $SIG{__DIE__} = sub {
293 unless ($^S || !defined $^S ) {
294 $RT::Handle->Rollback();
295 $RT::Logger->crit("$_[0]");
306 Load all modules that define base classes
312 require RT::Transactions;
314 require RT::CurrentUser;
315 require RT::Templates;
317 require RT::ScripActions;
318 require RT::ScripConditions;
321 require RT::GroupMembers;
322 require RT::CustomFields;
323 require RT::CustomFieldValues;
324 require RT::ObjectCustomFields;
325 require RT::ObjectCustomFieldValues;
341 Please report them to rt-bugs@fsck.com, if you know what's broken and have at least
342 some idea of what needs to be fixed.
344 If you're not sure what's going on, report them rt-devel@lists.bestpractical.com.
349 L<DBIx::SearchBuilder>
353 ok ($RT::Nobody->Name() eq 'Nobody', "Nobody is nobody");
354 ok ($RT::Nobody->Name() ne 'root', "Nobody isn't named root");
355 ok ($RT::SystemUser->Name() eq 'RT_System', "The system user is RT_System");
356 ok ($RT::SystemUser->Name() ne 'noname', "The system user isn't noname");
362 eval "require RT_Local";
363 die $@ if ($@ && $@ !~ qr{^Can't locate RT_Local.pm});