rt 4.0.21 (RT#13852)
[freeside.git] / rt / sbin / rt-dump-metadata.in
index f58371f..5e0e5c3 100644 (file)
@@ -3,7 +3,7 @@
 #
 # COPYRIGHT:
 #
 #
 # COPYRIGHT:
 #
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
@@ -47,6 +47,7 @@
 #
 # END BPS TAGGED BLOCK }}}
 use strict;
 #
 # END BPS TAGGED BLOCK }}}
 use strict;
+use warnings;
 
 # As we specify that XML is UTF-8 and we output it to STDOUT, we must be sure
 # it is UTF-8 so further XMLin will not break
 
 # As we specify that XML is UTF-8 and we output it to STDOUT, we must be sure
 # it is UTF-8 so further XMLin will not break
@@ -78,7 +79,11 @@ BEGIN {
 
 use Getopt::Long;
 my %opt;
 
 use Getopt::Long;
 my %opt;
-GetOptions( \%opt, "help|h" );
+GetOptions( \%opt, "help|h",
+    "limit-to-privileged|l",
+    "skip-disabled|s",
+    "all|a",
+);
 
 if ( $opt{help} ) {
     require Pod::Usage;
 
 if ( $opt{help} ) {
     require Pod::Usage;
@@ -92,8 +97,6 @@ require XML::Simple;
 RT::LoadConfig();
 RT::Init();
 
 RT::LoadConfig();
 RT::Init();
 
-my $LocalOnly = @ARGV ? shift(@ARGV) : 1;
-
 my %RV;
 my %Ignore = (
     All => [
 my %RV;
 my %Ignore = (
     All => [
@@ -116,8 +119,15 @@ my @classes      = qw(
 foreach my $class (@classes) {
     require "RT/$class.pm";
     my $objects = "RT::$class"->new( RT->SystemUser );
 foreach my $class (@classes) {
     require "RT/$class.pm";
     my $objects = "RT::$class"->new( RT->SystemUser );
-    $objects->{find_disabled_rows} = 1;
+    $objects->{find_disabled_rows} = 1 unless $opt{'skip-disabled'};
     $objects->UnLimit;
     $objects->UnLimit;
+    $objects->LimitToPrivileged if $class eq 'Users'
+        && $opt{'limit-to-privileged'};
+    $objects->Limit(
+        FIELD    => 'Domain',
+        OPERATOR => '=',
+        VALUE    => 'UserDefined'
+    ) if $class eq 'Groups';
 
     if ( $class eq 'CustomFields' ) {
         $objects->OrderByCols(
 
     if ( $class eq 'CustomFields' ) {
         $objects->OrderByCols(
@@ -129,7 +139,7 @@ foreach my $class (@classes) {
         $objects->OrderBy( FIELD => 'Id' );
     }
 
         $objects->OrderBy( FIELD => 'Id' );
     }
 
-    if ($LocalOnly) {
+    unless ($opt{all}) {
         next if $class eq 'ACL';    # XXX - would go into infinite loop - XXX
         $objects->Limit(
             FIELD    => 'LastUpdatedBy',
         next if $class eq 'ACL';    # XXX - would go into infinite loop - XXX
         $objects->Limit(
             FIELD    => 'LastUpdatedBy',
@@ -141,14 +151,10 @@ foreach my $class (@classes) {
             OPERATOR => '!=',
             VALUE    => $SystemUserId
         ) if $class eq 'Users';
             OPERATOR => '!=',
             VALUE    => $SystemUserId
         ) if $class eq 'Users';
-        $objects->Limit(
-            FIELD    => 'Domain',
-            OPERATOR => '=',
-            VALUE    => 'UserDefined'
-        ) if $class eq 'Groups';
     }
 
     my %fields;
     }
 
     my %fields;
+OBJECT:
     while ( my $obj = $objects->Next ) {
         next
             if $obj->can('LastUpdatedBy')
     while ( my $obj = $objects->Next ) {
         next
             if $obj->can('LastUpdatedBy')
@@ -162,36 +168,116 @@ foreach my $class (@classes) {
 
         my $rv;
 
 
         my $rv;
 
-        # next if $obj-> # skip default names
-        foreach my $field ( sort keys %fields ) {
-            my $value = $obj->__Value($field);
-            $rv->{$field} = $value if ( defined($value) && length($value) );
-        }
-        delete $rv->{Disabled} unless $rv->{Disabled};
-
-        foreach my $record ( map { /ACL/ ? 'ACE' : substr( $_, 0, -1 ) }
-            @classes )
-        {
-            foreach my $key ( map "$record$_", ( '', 'Id' ) ) {
-                next unless exists $rv->{$key};
-                my $id = $rv->{$key} or next;
-                my $obj = "RT::$record"->new( RT->SystemUser );
-                $obj->LoadByCols( Id => $id ) or next;
-                $rv->{$key} = $obj->__Value('Name') || 0;
+        if ( $class ne 'ACL' ) {
+            # next if $obj-> # skip default names
+            foreach my $field ( sort keys %fields ) {
+                my $value = $obj->__Value($field);
+                $rv->{$field} = $value if ( defined($value) && length($value) );
+            }
+            delete $rv->{Disabled} unless $rv->{Disabled};
+
+            foreach my $record ( map { /ACL/ ? 'ACE' : substr( $_, 0, -1 ) }
+                @classes )
+            {
+                foreach my $key ( map "$record$_", ( '', 'Id' ) ) {
+                    next unless exists $rv->{$key};
+                    my $id = $rv->{$key} or next;
+                    my $obj = "RT::$record"->new( RT->SystemUser );
+                    $obj->LoadByCols( Id => $id ) or next;
+                    $rv->{$key} = $obj->__Value('Name') || 0;
+                }
+            }
+
+            if ( $class eq 'Users' and defined $obj->Privileged ) {
+                $rv->{Privileged} = int( $obj->Privileged );
+            } elsif ( $class eq 'CustomFields' ) {
+                my $values = $obj->Values;
+                while ( my $value = $values->Next ) {
+                    push @{ $rv->{Values} }, {
+                        map { ( $_ => $value->__Value($_) ) }
+                            qw(
+                            Name Description SortOrder
+                            ),
+                    };
+                }
+                if ( $obj->LookupType eq 'RT::Queue-RT::Ticket' ) {
+                    # XXX-TODO: unused CF's turn into global CF when importing
+                    # as the sub InsertData in RT::Handle creates a global CF
+                    # when no queue is specified.
+                    $rv->{Queue} = [];
+                    my $applies = $obj->AppliedTo;
+                    while ( my $queue = $applies->Next ) {
+                        push @{ $rv->{Queue} }, $queue->Name;
+                    }
+                }
             }
         }
             }
         }
+        else {
+            # 1) pick the right
+            $rv->{Right} = $obj->RightName;
+
+            # 2) Pick a level: Granted on Queue, CF, CF+Queue, or Globally?
+            for ( $obj->ObjectType ) {
+                if ( /^RT::Queue$/ ) {
+                    next OBJECT if $opt{'skip-disabled'} && $obj->Object->Disabled;
+                    $rv->{Queue} = $obj->Object->Name;
+                }
+                elsif ( /^RT::CustomField$/ ) {
+                    next OBJECT if $opt{'skip-disabled'} && $obj->Object->Disabled;
+                    $rv->{CF} = $obj->Object->Name;
+                }
+                elsif ( /^RT::Group$/ ) {
+                    # No support for RT::Group ACLs in RT::Handle yet.
+                    next OBJECT;
+                }
+                elsif ( /^RT::System$/ ) {
+                    # skip setting anything on $rv;
+                    # "Specifying none of the above will get you a global right."
+                }
+            }
 
 
-        if ( $class eq 'Users' and defined $obj->Privileged ) {
-            $rv->{Privileged} = int( $obj->Privileged );
-        } elsif ( $class eq 'CustomFields' ) {
-            my $values = $obj->Values;
-            while ( my $value = $values->Next ) {
-                push @{ $rv->{Values} }, {
-                    map { ( $_ => $value->__Value($_) ) }
-                        qw(
-                        Name Description SortOrder
-                        ),
-                };
+            # 3) Pick a Principal; User or Group or Role
+            if ( $obj->PrincipalType eq 'Group' ) {
+                next OBJECT if $opt{'skip-disabled'} && $obj->PrincipalObj->Disabled;
+                my $group = $obj->PrincipalObj->Object;
+                for ( $group->Domain ) {
+                    # An internal user group
+                    if ( /^SystemInternal$/ ) {
+                        $rv->{GroupDomain} = $group->Domain;
+                        $rv->{GroupType} = $group->Type;
+                    }
+                    # An individual user
+                    elsif ( /^ACLEquivalence$/ ) {
+                        my $member = $group->MembersObj->Next->MemberObj;
+                        next OBJECT if $opt{'skip-disabled'} && $member->Disabled;
+                        $rv->{UserId} = $member->Object->Name;
+                    }
+                    # A group you created
+                    elsif ( /^UserDefined$/ ) {
+                        $rv->{GroupDomain} = 'UserDefined';
+                        $rv->{GroupId} = $group->Name;
+                    }
+                }
+            } else {
+                $rv->{GroupType} = $obj->PrincipalType;
+                # A system-level role
+                if ( $obj->ObjectType eq 'RT::System' ) {
+                    $rv->{GroupDomain} = 'RT::System-Role';
+                }
+                # A queue-level role
+                elsif ( $obj->ObjectType eq 'RT::Queue' ) {
+                    $rv->{GroupDomain} = 'RT::Queue-Role';
+                }
+            }
+            if ( $obj->LookupType eq 'RT::Queue-RT::Ticket' ) {
+                # XXX-TODO: unused CF's turn into global CF when importing
+                # as the sub InsertData in RT::Handle creates a global CF
+                # when no queue is specified.
+                $rv->{Queue} = [];
+                my $applies = $obj->AppliedTo;
+                while ( my $queue = $applies->Next ) {
+                    push @{ $rv->{Queue} }, $queue->Name;
+                }
             }
         }
 
             }
         }
 
@@ -199,6 +285,9 @@ foreach my $class (@classes) {
             my $attributes = $obj->Attributes;
             while ( my $attribute = $attributes->Next ) {
                 my $content = $attribute->Content;
             my $attributes = $obj->Attributes;
             while ( my $attribute = $attributes->Next ) {
                 my $content = $attribute->Content;
+                if ( $class eq 'Users' and $attribute->Name eq 'Bookmarks' ) {
+                    next;
+                }
                 $rv->{Attributes}{ $attribute->Name } = $content
                     if length($content);
             }
                 $rv->{Attributes}{ $attribute->Name } = $content
                     if length($content);
             }
@@ -231,7 +320,7 @@ rt-dump-metadata - dump configuration metadata from an RT database
 
 =head1 SYNOPSIS
 
 
 =head1 SYNOPSIS
 
-    rt-dump-metdata [ 0 ]
+    rt-dump-metdata [--all]
 
 =head1 DESCRIPTION
 
 
 =head1 DESCRIPTION
 
@@ -241,11 +330,28 @@ C<rt-setup-database>. To dump and load a full RT database, you should generally
 use the native database tools instead, as well as performing any necessary
 steps from UPGRADING.
 
 use the native database tools instead, as well as performing any necessary
 steps from UPGRADING.
 
-When run without arguments, the metadata dump will only include 'local'
+This is NOT a tool for backing up an RT database.  See also
+L<docs/initialdata> for more straightforward means of importing data.
+
+=head1 OPTIONS
+
+=over
+
+=item C<--all> or C<-a>
+
+When run with C<--all>, the dump will include all configuration
+metadata; otherwise, the metadata dump will only include 'local'
 configuration changes, i.e. those done manually in the web interface.
 
 configuration changes, i.e. those done manually in the web interface.
 
-When run with the argument '0', the dump will include all configuration
-metadata.
+=item C<--limit-to-privileged> or C<-l>
+
+Causes the dumper to only dump privileged users.
+
+=item C<--skip-disabled> or C<-s>
+
+Ignores disabled rows in the database.
+
+=back
 
 
-This is NOT a tool for backing up an RT database.
+=cut