1 # BEGIN BPS TAGGED BLOCK {{{
5 # This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
6 # <sales@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., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
30 # CONTRIBUTION SUBMISSION POLICY:
32 # (The following paragraph is not intended to limit the rights granted
33 # to you to modify and distribute this software under the terms of
34 # the GNU General Public License and is only of importance to you if
35 # you choose to contribute your changes and enhancements to the
36 # community by submitting them to Best Practical Solutions, LLC.)
38 # By intentionally submitting any modifications, corrections or
39 # derivatives to this work, or any other work intended for use with
40 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 # you are the copyright holder for those contributions and you grant
42 # Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43 # royalty-free, perpetual, license to use, copy, create derivative
44 # works based on those contributions, and sublicense and distribute
45 # those contributions and any derivatives thereof.
47 # END BPS TAGGED BLOCK }}}
51 RT::Handle - RT's database handle
56 BEGIN { RT::LoadConfig() };
61 C<RT::Handle> is RT specific wrapper over one of L<DBIx::SearchBuilder::Handle>
62 classes. As RT works with different types of DBs we subclass repsective handler
63 from L<DBIx::SerachBuilder>. Type of the DB is defined by C<DatabasseType> RT's
64 config option. You B<must> load this module only when the configs have been
77 =head2 FinalizeDatabaseType
79 Sets RT::Handle's superclass to the correct subclass of
80 L<DBIx::SearchBuilder::Handle>, using the C<DatabaseType> configuration.
84 sub FinalizeDatabaseType {
86 use base "DBIx::SearchBuilder::Handle::". RT->Config->Get('DatabaseType');
90 die "Unable to load DBIx::SearchBuilder database handle for '". RT->Config->Get('DatabaseType') ."'.\n".
91 "Perhaps you've picked an invalid database type or spelled it incorrectly.\n".
98 Connects to RT's database using credentials and options from the RT config.
106 my $db_type = RT->Config->Get('DatabaseType');
107 if ( $db_type eq 'Oracle' ) {
108 $ENV{'NLS_LANG'} = "AMERICAN_AMERICA.AL32UTF8";
109 $ENV{'NLS_NCHAR'} = "AL32UTF8";
112 $self->SUPER::Connect(
113 User => RT->Config->Get('DatabaseUser'),
114 Password => RT->Config->Get('DatabasePassword'),
117 if ( $db_type eq 'mysql' ) {
118 my $version = $self->DatabaseVersion;
119 ($version) = $version =~ /^(\d+\.\d+)/;
120 $self->dbh->do("SET NAMES 'utf8'") if $version >= 4.1;
124 if ( $db_type eq 'Pg' ) {
125 my $version = $self->DatabaseVersion;
126 ($version) = $version =~ /^(\d+\.\d+)/;
127 $self->dbh->do("SET bytea_output = 'escape'") if $version >= 9.0;
132 $self->dbh->{'LongReadLen'} = RT->Config->Get('MaxAttachmentSize');
137 Build the DSN for the RT database. Doesn't take any parameters, draws all that
146 # Unless the database port is a positive integer, we really don't want to pass it.
147 my $db_port = RT->Config->Get('DatabasePort');
148 $db_port = undef unless (defined $db_port && $db_port =~ /^(\d+)$/);
149 my $db_host = RT->Config->Get('DatabaseHost');
150 $db_host = undef unless $db_host;
151 my $db_name = RT->Config->Get('DatabaseName');
152 my $db_type = RT->Config->Get('DatabaseType');
153 $db_name = File::Spec->catfile($RT::VarPath, $db_name)
154 if $db_type eq 'SQLite' && !File::Spec->file_name_is_absolute($db_name);
158 Database => $db_name,
161 RequireSSL => RT->Config->Get('DatabaseRequireSSL'),
162 DisconnectHandleOnDestroy => 1,
164 if ( $db_type eq 'Oracle' && $db_host ) {
165 $args{'SID'} = delete $args{'Database'};
167 $self->SUPER::BuildDSN( %args );
172 Returns the DSN for this handle. In order to get correct value you must
173 build DSN first, see L</BuildDSN>.
175 This is method can be called as class method, in this case creates
176 temporary handle object, L</BuildDSN builds DSN> and returns it.
182 return $self->SUPER::DSN if ref $self;
184 my $handle = $self->new;
191 Returns a DSN suitable for database creates and drops
192 and user creates and drops.
194 Gets RT's DSN first (see L<DSN>) and then change it according
195 to requirements of a database system RT's using.
202 my $db_name = RT->Config->Get('DatabaseName');
203 my $db_type = RT->Config->Get('DatabaseType');
205 my $dsn = $self->DSN;
206 if ( $db_type eq 'mysql' ) {
207 # with mysql, you want to connect sans database to funge things
208 $dsn =~ s/dbname=\Q$db_name//;
210 elsif ( $db_type eq 'Pg' ) {
211 # with postgres, you want to connect to template1 database
212 $dsn =~ s/dbname=\Q$db_name/dbname=template1/;
214 elsif ( $db_type eq 'Informix' ) {
215 # with Informix, you want to connect sans database:
216 $dsn =~ s/Informix:\Q$db_name/Informix:/;
221 =head2 Database compatibility and integrity checks
230 my $dsn = $self->DSN;
231 my $user = RT->Config->Get('DatabaseUser');
232 my $pass = RT->Config->Get('DatabasePassword');
234 my $dbh = DBI->connect(
236 { RaiseError => 0, PrintError => 0 },
239 return (0, 'no connection', "Failed to connect to $dsn as user '$user': ". $DBI::errstr);
242 unless ($RT::Handle and $RT::Handle->dbh) {
243 RT::ConnectToDatabase();
246 require RT::CurrentUser;
247 my $test_user = new RT::CurrentUser;
248 $test_user->Load('RT_System');
249 unless ( $test_user->id ) {
250 return (0, 'no system user', "Couldn't find RT_System user in the DB '$dsn'");
253 $test_user = new RT::CurrentUser;
254 $test_user->Load('Nobody');
255 unless ( $test_user->id ) {
256 return (0, 'no nobody user', "Couldn't find Nobody user in the DB '$dsn'");
262 sub CheckCompatibility {
265 my $state = shift || 'post';
267 my $db_type = RT->Config->Get('DatabaseType');
268 if ( $db_type eq "mysql" ) {
269 # Check which version we're running
270 my $version = ($dbh->selectrow_array("show variables like 'version'"))[1];
271 return (0, "couldn't get version of the mysql server")
274 ($version) = $version =~ /^(\d+\.\d+)/;
275 return (0, "RT is unsupported on MySQL versions before 4.0.x, it's $version")
278 # MySQL must have InnoDB support
279 my $innodb = ($dbh->selectrow_array("show variables like 'have_innodb'"))[1];
280 if ( lc $innodb eq "no" ) {
281 return (0, "RT requires that MySQL be compiled with InnoDB table support.\n".
282 "See http://dev.mysql.com/doc/mysql/en/InnoDB.html");
283 } elsif ( lc $innodb eq "disabled" ) {
284 return (0, "RT requires that MySQL InnoDB table support be enabled.\n".
285 "Remove the 'skip-innodb' line from your my.cnf file, restart MySQL, and try again.\n");
288 if ( $state eq 'post' ) {
289 my $create_table = $dbh->selectrow_arrayref("SHOW CREATE TABLE Tickets")->[1];
290 unless ( $create_table =~ /(?:ENGINE|TYPE)\s*=\s*InnoDB/i ) {
291 return (0, "RT requires that all its tables be of InnoDB type. Upgrade RT tables.");
294 if ( $version >= 4.1 && $state eq 'post' ) {
295 my $create_table = $dbh->selectrow_arrayref("SHOW CREATE TABLE Attachments")->[1];
296 unless ( $create_table =~ /\bContent\b[^,]*BLOB/i ) {
297 return (0, "RT since version 3.8 has new schema for MySQL versions after 4.1.0\n"
298 ."Follow instructions in the UPGRADING.mysql file.");
305 =head2 Database maintanance
307 =head3 CreateDatabase $DBH
309 Creates a new database. This method can be used as class method.
311 Takes DBI handle. Many database systems require special handle to
312 allow you to create a new database, so you have to use L<SystemDSN>
313 method during connection.
315 Fetches type and name of the DB from the config.
321 my $dbh = shift or return (0, "No DBI handle provided");
322 my $db_type = RT->Config->Get('DatabaseType');
323 my $db_name = RT->Config->Get('DatabaseName');
326 if ( $db_type eq 'SQLite' ) {
327 return (1, 'Skipped as SQLite doesn\'t need any action');
329 elsif ( $db_type eq 'Oracle' ) {
330 my $db_user = RT->Config->Get('DatabaseUser');
331 my $db_pass = RT->Config->Get('DatabasePassword');
333 "CREATE USER $db_user IDENTIFIED BY $db_pass"
334 ." default tablespace USERS"
335 ." temporary tablespace TEMP"
336 ." quota unlimited on USERS"
339 return $status, "Couldn't create user $db_user identified by $db_pass."
340 ."\nError: ". $dbh->errstr;
342 $status = $dbh->do( "GRANT connect, resource TO $db_user" );
344 return $status, "Couldn't grant connect and resource to $db_user."
345 ."\nError: ". $dbh->errstr;
347 return (1, "Created user $db_user. All RT's objects should be in his schema.");
349 elsif ( $db_type eq 'Pg' ) {
350 # XXX: as we get external DBH we don't know if RaiseError or PrintError
351 # are enabled, so we have to setup it here and restore them back
352 $status = $dbh->do("CREATE DATABASE $db_name WITH ENCODING='UNICODE' TEMPLATE template0")
353 || $dbh->do("CREATE DATABASE $db_name TEMPLATE template0");
355 elsif ( $db_type eq 'Informix' ) {
356 local $ENV{'DB_LOCALE'} = 'en_us.utf8';
357 $status = $dbh->do("CREATE DATABASE $db_name WITH BUFFERED LOG");
360 $status = $dbh->do("CREATE DATABASE $db_name");
362 return ($status, $DBI::errstr);
365 =head3 DropDatabase $DBH [Force => 0]
367 Drops RT's database. This method can be used as class method.
369 Takes DBI handle as first argument. Many database systems require
370 special handle to allow you to create a new database, so you have
371 to use L<SystemDSN> method during connection.
373 Fetches type and name of the DB from the config.
379 my $dbh = shift or return (0, "No DBI handle provided");
381 my $db_type = RT->Config->Get('DatabaseType');
382 my $db_name = RT->Config->Get('DatabaseName');
384 if ( $db_type eq 'Oracle' || $db_type eq 'Informix' ) {
385 my $db_user = RT->Config->Get('DatabaseUser');
386 my $status = $dbh->do( "DROP USER $db_user CASCADE" );
388 return 0, "Couldn't drop user $db_user."
389 ."\nError: ". $dbh->errstr;
391 return (1, "Successfully dropped user '$db_user' with his schema.");
393 elsif ( $db_type eq 'SQLite' ) {
395 $path = "$RT::VarPath/$path" unless substr($path, 0, 1) eq '/';
396 unlink $path or return (0, "Couldn't remove '$path': $!");
399 $dbh->do("DROP DATABASE ". $db_name)
400 or return (0, $DBI::errstr);
412 my $base_path = shift || $RT::EtcPath;
414 my $db_type = RT->Config->Get('DatabaseType');
415 return (1) if $db_type eq 'SQLite';
417 $dbh = $self->dbh if !$dbh && ref $self;
418 return (0, "No DBI handle provided") unless $dbh;
420 return (0, "'$base_path' doesn't exist") unless -e $base_path;
423 if ( -d $base_path ) {
424 $path = File::Spec->catfile( $base_path, "acl.$db_type");
425 $path = $self->GetVersionFile($dbh, $path);
427 $path = File::Spec->catfile( $base_path, "acl")
428 unless $path && -e $path;
429 return (0, "Couldn't find ACLs for $db_type")
436 do $path || return (0, "Couldn't load ACLs: " . $@);
438 foreach my $statement (@acl) {
439 my $sth = $dbh->prepare($statement)
440 or return (0, "Couldn't prepare SQL query:\n $statement\n\nERROR: ". $dbh->errstr);
441 unless ( $sth->execute ) {
442 return (0, "Couldn't run SQL query:\n $statement\n\nERROR: ". $sth->errstr);
455 my $base_path = (shift || $RT::EtcPath);
457 $dbh = $self->dbh if !$dbh && ref $self;
458 return (0, "No DBI handle provided") unless $dbh;
460 my $db_type = RT->Config->Get('DatabaseType');
463 if ( -d $base_path ) {
464 $file = $base_path . "/schema." . $db_type;
469 $file = $self->GetVersionFile( $dbh, $file );
471 return (0, "Couldn't find schema file(s) '$file*'");
473 unless ( -f $file && -r $file ) {
474 return (0, "File '$file' doesn't exist or couldn't be read");
479 open( my $fh_schema, '<', $file ) or die $!;
482 open( my $fh_schema_local, "<", $self->GetVersionFile( $dbh, $RT::LocalEtcPath . "/schema." . $db_type ))
486 foreach my $line ( <$fh_schema>, ($_ = ';;'), $has_local? <$fh_schema_local>: () ) {
490 if ( $line =~ /;(\s*)$/ ) {
491 $statement =~ s/;(\s*)$//g;
492 push @schema, $statement;
496 close $fh_schema; close $fh_schema_local;
498 if ( $db_type eq 'Oracle' ) {
499 my $db_user = RT->Config->Get('DatabaseUser');
500 my $status = $dbh->do( "ALTER SESSION SET CURRENT_SCHEMA=$db_user" );
502 return $status, "Couldn't set current schema to $db_user."
503 ."\nError: ". $dbh->errstr;
507 local $SIG{__WARN__} = sub {};
509 $dbh->begin_work or return (0, "Couldn't begin transaction: ". $dbh->errstr);
510 foreach my $statement (@schema) {
511 if ( $statement =~ /^\s*;$/ ) {
515 my $sth = $dbh->prepare($statement)
516 or return (0, "Couldn't prepare SQL query:\n$statement\n\nERROR: ". $dbh->errstr);
517 unless ( $sth->execute or $is_local ) {
518 return (0, "Couldn't run SQL query:\n$statement\n\nERROR: ". $sth->errstr);
521 $dbh->commit or return (0, "Couldn't commit transaction: ". $dbh->errstr);
525 =head1 GetVersionFile
527 Takes base name of the file as argument, scans for <base name>-<version> named
528 files and returns file name with closest version to the version of the RT DB.
535 my $base_name = shift;
537 my $db_version = ref $self
538 ? $self->DatabaseVersion
540 my $tmp = RT::Handle->new;
542 $tmp->DatabaseVersion;
546 my @files = File::Glob::bsd_glob("$base_name*");
547 return '' unless @files;
549 my %version = map { $_ =~ /\.\w+-([-\w\.]+)$/; ($1||0) => $_ } @files;
551 foreach ( reverse sort cmp_version keys %version ) {
552 if ( cmp_version( $db_version, $_ ) >= 0 ) {
558 return defined $version? $version{ $version } : undef;
561 sub cmp_version($$) {
564 my @a = split /[^0-9]+/, $a;
565 my @b = split /[^0-9]+/, $b;
566 for ( my $i = 0; $i < @a; $i++ ) {
567 return 1 unless defined $b[$i];
568 return $a[$i] <=> $b[$i] if $a[$i] <=> $b[$i];
570 return 0 if @a == @b;
575 =head2 InsertInitialData
577 Inserts system objects into RT's DB, like system user or 'nobody',
578 internal groups and other records required. However, this method
579 doesn't insert any real users like 'root' and you have to use
580 InsertData or another way to do that.
582 Takes no arguments. Returns status and message tuple.
584 It's safe to call this method even if those objects already exist.
588 sub InsertInitialData {
593 # create RT_System user and grant him rights
595 require RT::CurrentUser;
597 my $test_user = RT::User->new( new RT::CurrentUser );
598 $test_user->Load('RT_System');
599 if ( $test_user->id ) {
600 push @warns, "Found system user in the DB.";
603 my $user = RT::User->new( new RT::CurrentUser );
604 my ( $val, $msg ) = $user->_BootstrapCreate(
606 RealName => 'The RT System itself',
607 Comments => 'Do not delete or modify this user. '
608 . 'It is integral to RT\'s internal database structures',
610 LastUpdatedBy => '1',
612 return ($val, $msg) unless $val;
614 DBIx::SearchBuilder::Record::Cachable->FlushCache;
617 # init RT::SystemUser and RT::System objects
618 RT::InitSystemObjects();
619 unless ( $RT::SystemUser->id ) {
620 return (0, "Couldn't load system user");
623 # grant SuperUser right to system user
625 my $test_ace = RT::ACE->new( $RT::SystemUser );
626 $test_ace->LoadByCols(
627 PrincipalId => ACLEquivGroupId( $RT::SystemUser->Id ),
628 PrincipalType => 'Group',
629 RightName => 'SuperUser',
630 ObjectType => 'RT::System',
633 if ( $test_ace->id ) {
634 push @warns, "System user has global SuperUser right.";
636 my $ace = RT::ACE->new( $RT::SystemUser );
637 my ( $val, $msg ) = $ace->_BootstrapCreate(
638 PrincipalId => ACLEquivGroupId( $RT::SystemUser->Id ),
639 PrincipalType => 'Group',
640 RightName => 'SuperUser',
641 ObjectType => 'RT::System',
644 return ($val, $msg) unless $val;
646 DBIx::SearchBuilder::Record::Cachable->FlushCache;
650 # $self->loc('Everyone'); # For the string extractor to get a string to localize
651 # $self->loc('Privileged'); # For the string extractor to get a string to localize
652 # $self->loc('Unprivileged'); # For the string extractor to get a string to localize
653 foreach my $name (qw(Everyone Privileged Unprivileged)) {
654 my $group = RT::Group->new( $RT::SystemUser );
655 $group->LoadSystemInternalGroup( $name );
657 push @warns, "System group '$name' already exists.";
661 $group = RT::Group->new( $RT::SystemUser );
662 my ( $val, $msg ) = $group->_Create(
664 Domain => 'SystemInternal',
665 Description => 'Pseudogroup for internal use', # loc
669 return ($val, $msg) unless $val;
674 my $user = RT::User->new( $RT::SystemUser );
675 $user->Load('Nobody');
677 push @warns, "Found 'Nobody' user in the DB.";
680 my ( $val, $msg ) = $user->Create(
682 RealName => 'Nobody in particular',
683 Comments => 'Do not delete or modify this user. It is integral '
684 .'to RT\'s internal data structures',
687 return ($val, $msg) unless $val;
690 if ( $user->HasRight( Right => 'OwnTicket', Object => $RT::System ) ) {
691 push @warns, "User 'Nobody' has global OwnTicket right.";
693 my ( $val, $msg ) = $user->PrincipalObj->GrantRight(
694 Right => 'OwnTicket',
695 Object => $RT::System,
697 return ($val, $msg) unless $val;
701 # rerun to get init Nobody as well
702 RT::InitSystemObjects();
705 foreach my $name (qw(Owner Requestor Cc AdminCc)) {
706 my $group = RT::Group->new( $RT::SystemUser );
707 $group->LoadSystemRoleGroup( $name );
709 push @warns, "System role '$name' already exists.";
713 $group = RT::Group->new( $RT::SystemUser );
714 my ( $val, $msg ) = $group->_Create(
716 Domain => 'RT::System-Role',
717 Description => 'SystemRolegroup for internal use', # loc
721 return ($val, $msg) unless $val;
724 push @warns, "You appear to have a functional RT database."
727 return (1, join "\n", @warns);
732 Load some sort of data into the database, takes path to a file.
738 my $datafile = shift;
740 # Slurp in stuff to insert from the datafile. Possible things to go in here:-
741 our (@Groups, @Users, @ACL, @Queues, @ScripActions, @ScripConditions,
742 @Templates, @CustomFields, @Scrips, @Attributes, @Initial, @Final);
743 local (@Groups, @Users, @ACL, @Queues, @ScripActions, @ScripConditions,
744 @Templates, @CustomFields, @Scrips, @Attributes, @Initial, @Final);
747 $RT::Logger->debug("Going to load '$datafile' data file");
748 eval { require $datafile }
749 or return (0, "Couldn't load data from '$datafile' for import:\n\nERROR:". $@);
752 $RT::Logger->debug("Running initial actions...");
753 foreach ( @Initial ) {
755 eval { $_->(); 1 } or return (0, "One of initial functions failed: $@");
757 $RT::Logger->debug("Done.");
760 $RT::Logger->debug("Creating groups...");
761 foreach my $item (@Groups) {
762 my $new_entry = RT::Group->new( $RT::SystemUser );
763 my $member_of = delete $item->{'MemberOf'};
764 my ( $return, $msg ) = $new_entry->_Create(%$item);
766 $RT::Logger->error( $msg );
769 $RT::Logger->debug($return .".");
772 $member_of = [ $member_of ] unless ref $member_of eq 'ARRAY';
773 foreach( @$member_of ) {
774 my $parent = RT::Group->new($RT::SystemUser);
775 if ( ref $_ eq 'HASH' ) {
776 $parent->LoadByCols( %$_ );
779 $parent->LoadUserDefinedGroup( $_ );
783 "(Error: wrong format of MemberOf field."
784 ." Should be name of user defined group or"
785 ." hash reference with 'column => value' pairs."
786 ." Use array reference to add to multiple groups)"
790 unless ( $parent->Id ) {
791 $RT::Logger->error("(Error: couldn't load group to add member)");
794 my ( $return, $msg ) = $parent->AddMember( $new_entry->Id );
796 $RT::Logger->error( $msg );
798 $RT::Logger->debug( $return ."." );
803 $RT::Logger->debug("done.");
806 $RT::Logger->debug("Creating users...");
807 foreach my $item (@Users) {
808 my $new_entry = new RT::User( $RT::SystemUser );
809 my ( $return, $msg ) = $new_entry->Create(%$item);
811 $RT::Logger->error( $msg );
813 $RT::Logger->debug( $return ."." );
816 $RT::Logger->debug("done.");
819 $RT::Logger->debug("Creating queues...");
820 for my $item (@Queues) {
821 my $new_entry = new RT::Queue($RT::SystemUser);
822 my ( $return, $msg ) = $new_entry->Create(%$item);
824 $RT::Logger->error( $msg );
826 $RT::Logger->debug( $return ."." );
829 $RT::Logger->debug("done.");
831 if ( @CustomFields ) {
832 $RT::Logger->debug("Creating custom fields...");
833 for my $item ( @CustomFields ) {
834 my $new_entry = new RT::CustomField( $RT::SystemUser );
835 my $values = delete $item->{'Values'};
838 # if ref then it's list of queues, so we do things ourself
839 if ( exists $item->{'Queue'} && ref $item->{'Queue'} ) {
840 $item->{'LookupType'} ||= 'RT::Queue-RT::Ticket';
841 @queues = @{ delete $item->{'Queue'} };
844 my ( $return, $msg ) = $new_entry->Create(%$item);
846 $RT::Logger->error( $msg );
850 if ( $item->{'BasedOn'} ) {
851 my $basedon = RT::CustomField->new($RT::SystemUser);
852 my ($ok, $msg ) = $basedon->LoadByCols( Name => $item->{'BasedOn'},
853 LookupType => $new_entry->LookupType );
855 ($ok, $msg) = $new_entry->SetBasedOn( $basedon );
857 $RT::Logger->debug("Added BasedOn $item->{BasedOn}: $msg");
859 $RT::Logger->error("Failed to add basedOn $item->{BasedOn}: $msg");
862 $RT::Logger->error("Unable to load $item->{BasedOn} as a $item->{LookupType} CF. Skipping BasedOn");
866 foreach my $value ( @{$values} ) {
867 my ( $return, $msg ) = $new_entry->AddValue(%$value);
868 $RT::Logger->error( $msg ) unless $return;
872 if ( !@queues && !exists $item->{'Queue'} && $item->{LookupType} ) {
873 my $ocf = RT::ObjectCustomField->new($RT::SystemUser);
874 $ocf->Create( CustomField => $new_entry->Id );
877 for my $q (@queues) {
878 my $q_obj = RT::Queue->new($RT::SystemUser);
880 unless ( $q_obj->Id ) {
881 $RT::Logger->error("Could not find queue ". $q );
884 my $OCF = RT::ObjectCustomField->new($RT::SystemUser);
885 ( $return, $msg ) = $OCF->Create(
886 CustomField => $new_entry->Id,
887 ObjectId => $q_obj->Id,
889 $RT::Logger->error( $msg ) unless $return and $OCF->Id;
893 $RT::Logger->debug("done.");
896 $RT::Logger->debug("Creating ACL...");
897 for my $item (@ACL) {
899 my ($princ, $object);
901 # Global rights or Queue rights?
902 if ( $item->{'CF'} ) {
903 $object = RT::CustomField->new( $RT::SystemUser );
904 my @columns = ( Name => $item->{'CF'} );
905 push @columns, Queue => $item->{'Queue'} if $item->{'Queue'} and not ref $item->{'Queue'};
906 $object->LoadByName( @columns );
907 } elsif ( $item->{'Queue'} ) {
908 $object = RT::Queue->new($RT::SystemUser);
909 $object->Load( $item->{'Queue'} );
911 $object = $RT::System;
914 $RT::Logger->error("Couldn't load object") and next unless $object and $object->Id;
916 # Group rights or user rights?
917 if ( $item->{'GroupDomain'} ) {
918 $princ = RT::Group->new($RT::SystemUser);
919 if ( $item->{'GroupDomain'} eq 'UserDefined' ) {
920 $princ->LoadUserDefinedGroup( $item->{'GroupId'} );
921 } elsif ( $item->{'GroupDomain'} eq 'SystemInternal' ) {
922 $princ->LoadSystemInternalGroup( $item->{'GroupType'} );
923 } elsif ( $item->{'GroupDomain'} eq 'RT::System-Role' ) {
924 $princ->LoadSystemRoleGroup( $item->{'GroupType'} );
925 } elsif ( $item->{'GroupDomain'} eq 'RT::Queue-Role' &&
928 $princ->LoadQueueRoleGroup( Type => $item->{'GroupType'},
929 Queue => $object->id);
931 $princ->Load( $item->{'GroupId'} );
934 $princ = RT::User->new($RT::SystemUser);
935 $princ->Load( $item->{'UserId'} );
939 my ( $return, $msg ) = $princ->PrincipalObj->GrantRight(
940 Right => $item->{'Right'},
944 $RT::Logger->error( $msg );
947 $RT::Logger->debug( $return ."." );
950 $RT::Logger->debug("done.");
953 if ( @ScripActions ) {
954 $RT::Logger->debug("Creating ScripActions...");
956 for my $item (@ScripActions) {
957 my $new_entry = RT::ScripAction->new($RT::SystemUser);
958 my ( $return, $msg ) = $new_entry->Create(%$item);
960 $RT::Logger->error( $msg );
963 $RT::Logger->debug( $return ."." );
967 $RT::Logger->debug("done.");
970 if ( @ScripConditions ) {
971 $RT::Logger->debug("Creating ScripConditions...");
973 for my $item (@ScripConditions) {
974 my $new_entry = RT::ScripCondition->new($RT::SystemUser);
975 my ( $return, $msg ) = $new_entry->Create(%$item);
977 $RT::Logger->error( $msg );
980 $RT::Logger->debug( $return ."." );
984 $RT::Logger->debug("done.");
988 $RT::Logger->debug("Creating templates...");
990 for my $item (@Templates) {
991 my $new_entry = new RT::Template($RT::SystemUser);
992 my ( $return, $msg ) = $new_entry->Create(%$item);
994 $RT::Logger->error( $msg );
997 $RT::Logger->debug( $return ."." );
1000 $RT::Logger->debug("done.");
1003 $RT::Logger->debug("Creating scrips...");
1005 for my $item (@Scrips) {
1006 my $new_entry = new RT::Scrip($RT::SystemUser);
1008 my @queues = ref $item->{'Queue'} eq 'ARRAY'? @{ $item->{'Queue'} }: $item->{'Queue'} || 0;
1009 push @queues, 0 unless @queues; # add global queue at least
1011 foreach my $q ( @queues ) {
1012 my ( $return, $msg ) = $new_entry->Create( %$item, Queue => $q );
1013 unless ( $return ) {
1014 $RT::Logger->error( $msg );
1017 $RT::Logger->debug( $return ."." );
1021 $RT::Logger->debug("done.");
1023 if ( @Attributes ) {
1024 $RT::Logger->debug("Creating predefined searches...");
1025 my $sys = RT::System->new($RT::SystemUser);
1027 for my $item (@Attributes) {
1028 my $obj = delete $item->{Object}; # XXX: make this something loadable
1030 my ( $return, $msg ) = $obj->AddAttribute (%$item);
1031 unless ( $return ) {
1032 $RT::Logger->error( $msg );
1035 $RT::Logger->debug( $return ."." );
1038 $RT::Logger->debug("done.");
1041 $RT::Logger->debug("Running final actions...");
1045 $RT::Logger->error( "Failed to run one of final actions: $@" )
1048 $RT::Logger->debug("done.");
1051 my $db_type = RT->Config->Get('DatabaseType');
1052 $RT::Handle->Disconnect() unless $db_type eq 'SQLite';
1054 $RT::Logger->debug("Done setting up database content.");
1056 # TODO is it ok to return 1 here? If so, the previous codes in this sub
1057 # should return (0, $msg) if error happens instead of just warning.
1058 # anyway, we need to return something here to tell if everything is ok
1059 return( 1, 'Done inserting data' );
1062 =head2 ACLEquivGroupId
1064 Given a userid, return that user's acl equivalence group
1068 sub ACLEquivGroupId {
1071 my $cu = $RT::SystemUser;
1073 require RT::CurrentUser;
1074 $cu = new RT::CurrentUser;
1075 $cu->LoadByName('RT_System');
1076 warn "Couldn't load RT_System user" unless $cu->id;
1079 my $equiv_group = RT::Group->new( $cu );
1080 $equiv_group->LoadACLEquivalenceGroup( $id );
1081 return $equiv_group->Id;
1084 __PACKAGE__->FinalizeDatabaseType;
1086 RT::Base->_ImportOverlays();