Putting 4.2.0 on top of 4.0.17
[usit-rt.git] / sbin / rt-dump-metadata
CommitLineData
84fb5b46
MKG
1#!/usr/bin/perl -w
2# BEGIN BPS TAGGED BLOCK {{{
3#
4# COPYRIGHT:
5#
403d7b0b 6# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
84fb5b46
MKG
7# <sales@bestpractical.com>
8#
9# (Except where explicitly superseded by other copyright notices)
10#
11#
12# LICENSE:
13#
14# This work is made available to you under the terms of Version 2 of
15# the GNU General Public License. A copy of that license should have
16# been provided with this software, but in any event can be snarfed
17# from www.gnu.org.
18#
19# This work is distributed in the hope that it will be useful, but
20# WITHOUT ANY WARRANTY; without even the implied warranty of
21# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22# General Public License for more details.
23#
24# You should have received a copy of the GNU General Public License
25# along with this program; if not, write to the Free Software
26# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27# 02110-1301 or visit their web page on the internet at
28# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
29#
30#
31# CONTRIBUTION SUBMISSION POLICY:
32#
33# (The following paragraph is not intended to limit the rights granted
34# to you to modify and distribute this software under the terms of
35# the GNU General Public License and is only of importance to you if
36# you choose to contribute your changes and enhancements to the
37# community by submitting them to Best Practical Solutions, LLC.)
38#
39# By intentionally submitting any modifications, corrections or
40# derivatives to this work, or any other work intended for use with
41# Request Tracker, to Best Practical Solutions, LLC, you confirm that
42# you are the copyright holder for those contributions and you grant
43# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
44# royalty-free, perpetual, license to use, copy, create derivative
45# works based on those contributions, and sublicense and distribute
46# those contributions and any derivatives thereof.
47#
48# END BPS TAGGED BLOCK }}}
49use strict;
403d7b0b 50use warnings;
84fb5b46
MKG
51
52# As we specify that XML is UTF-8 and we output it to STDOUT, we must be sure
53# it is UTF-8 so further XMLin will not break
54binmode( STDOUT, ":utf8" );
55
56# fix lib paths, some may be relative
af59614d 57BEGIN { # BEGIN RT CMD BOILERPLATE
84fb5b46 58 require File::Spec;
af59614d
MKG
59 require Cwd;
60 my @libs = ("lib", "local/lib");
84fb5b46
MKG
61 my $bin_path;
62
63 for my $lib (@libs) {
64 unless ( File::Spec->file_name_is_absolute($lib) ) {
af59614d 65 $bin_path ||= ( File::Spec->splitpath(Cwd::abs_path(__FILE__)) )[1];
84fb5b46
MKG
66 $lib = File::Spec->catfile( $bin_path, File::Spec->updir, $lib );
67 }
68 unshift @INC, $lib;
69 }
70
71}
72
73use Getopt::Long;
74my %opt;
75GetOptions( \%opt, "help|h" );
76
77if ( $opt{help} ) {
78 require Pod::Usage;
79 Pod::Usage::pod2usage( { verbose => 2 } );
80 exit;
81}
82
83require RT;
84require XML::Simple;
85
86RT::LoadConfig();
87RT::Init();
88
89my $LocalOnly = @ARGV ? shift(@ARGV) : 1;
90
91my %RV;
92my %Ignore = (
93 All => [
94 qw(
95 id Created Creator LastUpdated LastUpdatedBy
96 )
97 ],
84fb5b46
MKG
98);
99
100my $SystemUserId = RT->SystemUser->Id;
101my @classes = qw(
102 Users Groups Queues ScripActions ScripConditions
103 Templates Scrips ACL CustomFields
104 );
105foreach my $class (@classes) {
106 require "RT/$class.pm";
107 my $objects = "RT::$class"->new( RT->SystemUser );
108 $objects->{find_disabled_rows} = 1;
109 $objects->UnLimit;
110
111 if ( $class eq 'CustomFields' ) {
112 $objects->OrderByCols(
113 { FIELD => 'LookupType' },
114 { FIELD => 'SortOrder' },
115 { FIELD => 'Id' },
116 );
117 } else {
118 $objects->OrderBy( FIELD => 'Id' );
119 }
120
121 if ($LocalOnly) {
122 next if $class eq 'ACL'; # XXX - would go into infinite loop - XXX
123 $objects->Limit(
124 FIELD => 'LastUpdatedBy',
125 OPERATOR => '!=',
126 VALUE => $SystemUserId
127 ) unless $class eq 'Groups';
128 $objects->Limit(
129 FIELD => 'Id',
130 OPERATOR => '!=',
131 VALUE => $SystemUserId
132 ) if $class eq 'Users';
133 $objects->Limit(
134 FIELD => 'Domain',
135 OPERATOR => '=',
af59614d
MKG
136 VALUE => 'UserDefined',
137 CASESENSITIVE => 0,
84fb5b46
MKG
138 ) if $class eq 'Groups';
139 }
140
141 my %fields;
142 while ( my $obj = $objects->Next ) {
143 next
144 if $obj->can('LastUpdatedBy')
145 and $obj->LastUpdatedBy == $SystemUserId;
146
147 if ( !%fields ) {
148 %fields = map { $_ => 1 } keys %{ $obj->_ClassAccessible };
149 delete @fields{ @{ $Ignore{$class} ||= [] },
150 @{ $Ignore{All} ||= [] }, };
151 }
152
153 my $rv;
154
155 # next if $obj-> # skip default names
156 foreach my $field ( sort keys %fields ) {
157 my $value = $obj->__Value($field);
158 $rv->{$field} = $value if ( defined($value) && length($value) );
159 }
160 delete $rv->{Disabled} unless $rv->{Disabled};
161
162 foreach my $record ( map { /ACL/ ? 'ACE' : substr( $_, 0, -1 ) }
163 @classes )
164 {
165 foreach my $key ( map "$record$_", ( '', 'Id' ) ) {
166 next unless exists $rv->{$key};
167 my $id = $rv->{$key} or next;
168 my $obj = "RT::$record"->new( RT->SystemUser );
169 $obj->LoadByCols( Id => $id ) or next;
170 $rv->{$key} = $obj->__Value('Name') || 0;
171 }
172 }
173
174 if ( $class eq 'Users' and defined $obj->Privileged ) {
175 $rv->{Privileged} = int( $obj->Privileged );
176 } elsif ( $class eq 'CustomFields' ) {
177 my $values = $obj->Values;
178 while ( my $value = $values->Next ) {
179 push @{ $rv->{Values} }, {
180 map { ( $_ => $value->__Value($_) ) }
181 qw(
182 Name Description SortOrder
183 ),
184 };
185 }
186 }
187
188 if ( eval { require RT::Attributes; 1 } ) {
189 my $attributes = $obj->Attributes;
190 while ( my $attribute = $attributes->Next ) {
191 my $content = $attribute->Content;
192 $rv->{Attributes}{ $attribute->Name } = $content
193 if length($content);
194 }
195 }
196
197 push @{ $RV{$class} }, $rv;
198 }
199}
200
201print(<< ".");
202no strict; use XML::Simple; *_ = XMLin(do { local \$/; readline(DATA) }, ForceArray => [qw(
203 @classes Values
204)], NoAttr => 1, SuppressEmpty => ''); *\$_ = (\$_{\$_} || []) for keys \%_; 1; # vim: ft=xml
205__DATA__
206.
207
208print XML::Simple::XMLout(
209 { map { ( $_ => ( $RV{$_} || [] ) ) } @classes },
210 RootName => 'InitialData',
211 NoAttr => 1,
212 SuppressEmpty => '',
213 XMLDecl => '<?xml version="1.0" encoding="UTF-8"?>',
214);
215
216__END__
217
218=head1 NAME
219
220rt-dump-metadata - dump configuration metadata from an RT database
221
222=head1 SYNOPSIS
223
224 rt-dump-metdata [ 0 ]
225
226=head1 DESCRIPTION
227
228C<rt-dump-metadata> is a tool that dumps configuration metadata from the
229Request Tracker database into XML format, suitable for feeding into
230C<rt-setup-database>. To dump and load a full RT database, you should generally
231use the native database tools instead, as well as performing any necessary
232steps from UPGRADING.
233
234When run without arguments, the metadata dump will only include 'local'
235configuration changes, i.e. those done manually in the web interface.
236
237When run with the argument '0', the dump will include all configuration
238metadata.
239
240This is NOT a tool for backing up an RT database.
241