+++ /dev/null
-#!/usr/bin/perl -w
-# BEGIN BPS TAGGED BLOCK {{{
-#
-# COPYRIGHT:
-#
-# This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
-# <sales@bestpractical.com>
-#
-# (Except where explicitly superseded by other copyright notices)
-#
-#
-# LICENSE:
-#
-# This work is made available to you under the terms of Version 2 of
-# the GNU General Public License. A copy of that license should have
-# been provided with this software, but in any event can be snarfed
-# from www.gnu.org.
-#
-# This work is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301 or visit their web page on the internet at
-# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
-#
-#
-# CONTRIBUTION SUBMISSION POLICY:
-#
-# (The following paragraph is not intended to limit the rights granted
-# to you to modify and distribute this software under the terms of
-# the GNU General Public License and is only of importance to you if
-# you choose to contribute your changes and enhancements to the
-# community by submitting them to Best Practical Solutions, LLC.)
-#
-# By intentionally submitting any modifications, corrections or
-# derivatives to this work, or any other work intended for use with
-# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-# you are the copyright holder for those contributions and you grant
-# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
-# royalty-free, perpetual, license to use, copy, create derivative
-# works based on those contributions, and sublicense and distribute
-# those contributions and any derivatives thereof.
-#
-# 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
-binmode( STDOUT, ":utf8" );
-
-# fix lib paths, some may be relative
-BEGIN {
- require File::Spec;
- my @libs = ( "/opt/rt3/lib", "/opt/rt3/local/lib" );
- my $bin_path;
-
- for my $lib (@libs) {
- unless ( File::Spec->file_name_is_absolute($lib) ) {
- unless ($bin_path) {
- if ( File::Spec->file_name_is_absolute(__FILE__) ) {
- $bin_path = ( File::Spec->splitpath(__FILE__) )[1];
- } else {
- require FindBin;
- no warnings "once";
- $bin_path = $FindBin::Bin;
- }
- }
- $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib );
- }
- unshift @INC, $lib;
- }
-
-}
-
-use Getopt::Long;
-my %opt;
-GetOptions( \%opt, "help|h",
- "limit-to-privileged|l",
- "skip-disabled|s",
- "all|a",
-);
-
-if ( $opt{help} ) {
- require Pod::Usage;
- Pod::Usage::pod2usage( { verbose => 2 } );
- exit;
-}
-
-require RT;
-require XML::Simple;
-
-RT::LoadConfig();
-RT::Init();
-
-my %RV;
-my %Ignore = (
- All => [
- qw(
- id Created Creator LastUpdated LastUpdatedBy
- )
- ],
- Templates => [
- qw(
- TranslationOf
- )
- ],
-);
-
-my $SystemUserId = RT->SystemUser->Id;
-my @classes = qw(
- Users Groups Queues ScripActions ScripConditions
- Templates Scrips ACL CustomFields
- );
-foreach my $class (@classes) {
- require "RT/$class.pm";
- my $objects = "RT::$class"->new( RT->SystemUser );
- $objects->{find_disabled_rows} = 1 unless $opt{'skip-disabled'};
- $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(
- { FIELD => 'LookupType' },
- { FIELD => 'SortOrder' },
- { FIELD => 'Id' },
- );
- } else {
- $objects->OrderBy( FIELD => 'Id' );
- }
-
- unless ($opt{all}) {
- next if $class eq 'ACL'; # XXX - would go into infinite loop - XXX
- $objects->Limit(
- FIELD => 'LastUpdatedBy',
- OPERATOR => '!=',
- VALUE => $SystemUserId
- ) unless $class eq 'Groups';
- $objects->Limit(
- FIELD => 'Id',
- OPERATOR => '!=',
- VALUE => $SystemUserId
- ) if $class eq 'Users';
- }
-
- my %fields;
-OBJECT:
- while ( my $obj = $objects->Next ) {
- next
- if $obj->can('LastUpdatedBy')
- and $obj->LastUpdatedBy == $SystemUserId;
-
- if ( !%fields ) {
- %fields = map { $_ => 1 } keys %{ $obj->_ClassAccessible };
- delete @fields{ @{ $Ignore{$class} ||= [] },
- @{ $Ignore{All} ||= [] }, };
- }
-
- my $rv;
-
- 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."
- }
- }
-
- # 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;
- }
- }
- }
-
- if ( eval { require RT::Attributes; 1 } ) {
- 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);
- }
- }
-
- push @{ $RV{$class} }, $rv;
- }
-}
-
-print(<< ".");
-no strict; use XML::Simple; *_ = XMLin(do { local \$/; readline(DATA) }, ForceArray => [qw(
- @classes Values
-)], NoAttr => 1, SuppressEmpty => ''); *\$_ = (\$_{\$_} || []) for keys \%_; 1; # vim: ft=xml
-__DATA__
-.
-
-print XML::Simple::XMLout(
- { map { ( $_ => ( $RV{$_} || [] ) ) } @classes },
- RootName => 'InitialData',
- NoAttr => 1,
- SuppressEmpty => '',
- XMLDecl => '<?xml version="1.0" encoding="UTF-8"?>',
-);
-
-__END__
-
-=head1 NAME
-
-rt-dump-metadata - dump configuration metadata from an RT database
-
-=head1 SYNOPSIS
-
- rt-dump-metdata [--all]
-
-=head1 DESCRIPTION
-
-C<rt-dump-metadata> is a tool that dumps configuration metadata from the
-Request Tracker database into XML format, suitable for feeding into
-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.
-
-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.
-
-=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
-
-=cut
-