[Rt-commit] rt branch, 4.2/migrator-fixes, created. rt-4.2.12-122-gcd06315
Shawn Moore
shawn at bestpractical.com
Sun May 1 16:15:37 EDT 2016
The branch, 4.2/migrator-fixes has been created
at cd06315e3d98c6ee1094afa22776d5296c9c8f96 (commit)
- Log -----------------------------------------------------------------
commit 50dea853e373a5c3d3fafe3f201d8b726fda1099
Author: Dustin Graves <dustin at bestpractical.com>
Date: Wed Feb 17 20:16:50 2016 +0000
add AddRight calls to 4.0.1 upgrade step to prevent error message due to failure to canonicalize rights
Fixes: I#31721
diff --git a/etc/upgrade/4.0.1/content b/etc/upgrade/4.0.1/content
index cc3b5f1..851c502 100644
--- a/etc/upgrade/4.0.1/content
+++ b/etc/upgrade/4.0.1/content
@@ -50,6 +50,11 @@ our @Initial = (
sub {
RT->Logger->debug('Removing all Delegate and PersonalGroup rights');
+ # this temporarily tells the system that the rights exist so it can properly canonicalize them
+ RT::System->AddRight(Admin => AdminOwnPersonalGroups => 'Add right for 4.0.1 upgrade steps');
+ RT::System->AddRight(Admin => AdminAllPersonalGroups => 'Add right for 4.0.1 upgrade steps');
+ RT::System->AddRight(Admin => DelegateRights => 'Add right for 4.0.1 upgrade steps');
+
my $acl = RT::ACL->new(RT->SystemUser);
for my $right (qw/AdminOwnPersonalGroups AdminAllPersonalGroups DelegateRights/) {
$acl->Limit( FIELD => 'RightName', VALUE => $right );
commit 3b8ae5b6697ffd26734c9db46b30002af9460193
Author: Jim Brandt <jbrandt at bestpractical.com>
Date: Wed Feb 17 23:19:49 2016 +0000
Update detection of find version in configure
Commit 4028723 added code to detect the version of find
because Debian is changing to a newer version of GNU
find with different syntax than the traditional find.
However, the change in that commit no longer worked on
Mac OS X, a BSD-type system.
Modify the find check to use the --version option supported
on GNU and use GNU syntax if found. Otherwise default to the
previous BSD syntax which was the previous setting for all
systems.
diff --git a/configure.ac b/configure.ac
index 44f5384..c671138 100755
--- a/configure.ac
+++ b/configure.ac
@@ -36,21 +36,13 @@ fi
dnl BSD find uses -perm +xxxx, GNU find has deprecated this syntax in favour of
dnl -perm /xxx.
-AC_MSG_CHECKING([whether find supports -perm /x or find -perm +x])
-if find -perm /0100 -not -perm /0100
-then
- FINDPERM="/"
-elif
- find -perm +0100 -not -perm +0100
-then
- FINDPERM="+"
-else
- FINDPERM="na"
-fi
-AC_MSG_RESULT([${FINDPERM}])
-if test "x$FINDPERM" = "xna" ; then
- AC_MSG_WARN([local find program supports neither -perm /0111 nor -perm +0111, make fixperms will not work])
-fi
+AC_MSG_CHECKING([checking version of find])
+AS_IF([find --version 2>&1 | grep 'GNU'],
+ [ FINDPERM="/"
+ AC_MSG_RESULT([configuring for GNU find]) ],
+ [ FINDPERM="+"
+ AC_MSG_RESULT([configuring for BSD find]) ])
+
AC_SUBST([FINDPERM])
dnl WEB_HANDLER
commit 1cac7d3a64b1b3513610069f7b3895e359585475
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Sat Mar 12 16:27:00 2016 +0000
Serialize ObjectClass ObjectId using indirection
Otherwise article classes get applied to the wrong queue (the
one which happens to have had the same ID as one in the database
being serialized). This method is mostly lifted from
ObjectCustomField.
Fixes: I#31804
diff --git a/lib/RT/ObjectClass.pm b/lib/RT/ObjectClass.pm
index c51d9d4..f5a5da6 100644
--- a/lib/RT/ObjectClass.pm
+++ b/lib/RT/ObjectClass.pm
@@ -229,6 +229,18 @@ sub FindDependencies {
$deps->Add( out => $obj );
}
+sub Serialize {
+ my $self = shift;
+ my %args = (@_);
+ my %store = $self->SUPER::Serialize(@_);
+
+ if ($store{ObjectId}) {
+ my $obj = $self->ObjectType->new( RT->SystemUser );
+ $obj->Load( $store{ObjectId} );
+ $store{ObjectId} = \($obj->UID);
+ }
+ return %store;
+}
RT::Base->_ImportOverlays();
commit 06c4c4393d1ce6223aa280f152c5da14bfb6a2fd
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Sat Mar 12 16:43:53 2016 +0000
Serialize ObjectScrip ObjectId using indirection
Otherwise scrip gets applied to the wrong queue (the one which
happens to have had the same ID as one in the database being
serialized). This method is mostly lifted from
ObjectCustomField.
Fixes: I#31805
diff --git a/lib/RT/ObjectScrip.pm b/lib/RT/ObjectScrip.pm
index 8399398..b270d25 100644
--- a/lib/RT/ObjectScrip.pm
+++ b/lib/RT/ObjectScrip.pm
@@ -272,6 +272,19 @@ sub FindDependencies {
}
}
+sub Serialize {
+ my $self = shift;
+ my %args = (@_);
+ my %store = $self->SUPER::Serialize(@_);
+
+ if ($store{ObjectId}) {
+ my $obj = RT::Queue->new( RT->SystemUser );
+ $obj->Load( $store{ObjectId} );
+ $store{ObjectId} = \($obj->UID);
+ }
+ return %store;
+}
+
RT::Base->_ImportOverlays();
1;
commit 152c90c600c19cf470e9202b21b1cbb82a100072
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Sat Mar 12 16:51:44 2016 +0000
Serialize ObjectTopic ObjectId using indirection
Otherwise a topic gets applied to the wrong article (the one
which happens to have had the same ID as one in the database
being serialized). This method is mostly lifted from
ObjectCustomField.
Fixes: I#31803
diff --git a/lib/RT/ObjectTopic.pm b/lib/RT/ObjectTopic.pm
index c9429fd..dfe2bfd 100644
--- a/lib/RT/ObjectTopic.pm
+++ b/lib/RT/ObjectTopic.pm
@@ -212,6 +212,19 @@ sub FindDependencies {
$deps->Add( out => $obj );
}
+sub Serialize {
+ my $self = shift;
+ my %args = (@_);
+ my %store = $self->SUPER::Serialize(@_);
+
+ if ($store{ObjectId}) {
+ my $obj = $self->ObjectType->new( RT->SystemUser );
+ $obj->Load( $store{ObjectId} );
+ $store{ObjectId} = \($obj->UID);
+ }
+ return %store;
+}
+
RT::Base->_ImportOverlays();
1;
commit 84b02228763304a20edec35cc8547aa9e9c99862
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Sat Mar 12 18:03:31 2016 +0000
Avoid breaking rights granted to users when using rt-importer
The "user rights" admin pages issue a SQL query where each
user's ACLEquivalence group name is expected to be "UserEquiv".
However, before this commit, the importer system changed each
group's name from the expected "UserEquiv" to be e.g. "User 99",
since the user ID changes during import. So because the group
name was no longer "UserEquiv", the admin UI was failing to find
the existant but malformed ACL entries.
ACLEquivalence UserEquiv groups stopped using the user's ID in
their name as of 71fcde32, which is exactly when this regression
was introduced. Previously, user rights importing worked because
both the migrator and the ACL subsytems correctly used the Type
of the group, which was "UserEquiv". (The regression was
introduced because ACLs started using Name in place of Type)
Fixes: I#31806
diff --git a/lib/RT/Group.pm b/lib/RT/Group.pm
index c412ba6..81ac325 100644
--- a/lib/RT/Group.pm
+++ b/lib/RT/Group.pm
@@ -1741,13 +1741,12 @@ sub PreInflate {
return;
};
- # Go looking for the pre-existing version of the it
+ # Go looking for the pre-existing version of it
if ($data->{Domain} eq "ACLEquivalence") {
$obj->LoadACLEquivalenceGroup( $data->{Instance} );
return $duplicated->() if $obj->Id;
- # Update the name and description for the new ID
- $data->{Name} = 'User '. $data->{Instance};
+ # Update description for the new ID
$data->{Description} = 'ACL equiv. for user '.$data->{Instance};
} elsif ($data->{Domain} eq "UserDefined") {
$data->{Name} = $importer->Qualify($data->{Name});
commit 5c2cdaccdac956404b013dcd5b287ad48c929946
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Mon Mar 21 19:37:23 2016 +0000
Serialize dashboards in menu preference using indirection
Otherwise the old dashboard IDs will be kept in the user's
preferences, causing the menu to (in most cases) be empty.
Fixes: I#31810
diff --git a/lib/RT/Attribute.pm b/lib/RT/Attribute.pm
index 9943b57..9f69179 100644
--- a/lib/RT/Attribute.pm
+++ b/lib/RT/Attribute.pm
@@ -632,6 +632,18 @@ sub FindDependencies {
$self->SUPER::FindDependencies($walker, $deps);
$deps->Add( out => $self->Object );
+
+ # dashboards in menu attribute has dependencies on each of its dashboards
+ if ($self->Name eq RT::User::_PrefName("DashboardsInMenu")) {
+ my $content = $self->Content;
+ for my $pane (values %{ $content || {} }) {
+ for my $dash_id (@$pane) {
+ my $attr = RT::Attribute->new($self->CurrentUser);
+ $attr->LoadById($dash_id);
+ $deps->Add( out => $attr );
+ }
+ }
+ }
}
sub PreInflate {
@@ -642,9 +654,40 @@ sub PreInflate {
my $on_uid = ${ $data->{Object} };
return if $importer->ShouldSkipTransaction($on_uid);
}
+
+ # decode UIDs to be raw dashboard IDs
+ if ($data->{Name} eq RT::User::_PrefName("DashboardsInMenu")) {
+ my $content = $class->_DeserializeContent($data->{Content});
+ for my $pane (values %{ $content || {} }) {
+ @$pane = map { $importer->LookupObj($$_)->Id } @$pane;
+ }
+ $data->{Content} = $class->_SerializeContent($content);
+ }
+
return $class->SUPER::PreInflate( $importer, $uid, $data );
}
+sub Serialize {
+ my $self = shift;
+ my %args = (@_);
+ my %store = $self->SUPER::Serialize(@_);
+
+ # encode raw dashboard IDs to be UIDs
+ if ($store{Name} eq RT::User::_PrefName("DashboardsInMenu")) {
+ my $content = $self->_DeserializeContent($store{Content});
+ for my $pane (values %{ $content || {} }) {
+ for (@$pane) {
+ my $attr = RT::Attribute->new($self->CurrentUser);
+ $attr->LoadById($_);
+ $_ = \($attr->UID);
+ }
+ }
+ $store{Content} = $self->_SerializeContent($content);
+ }
+
+ return %store;
+}
+
RT::Base->_ImportOverlays();
1;
commit 69ab5435b21ce782d6114ec985a57ff00ccca29f
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Mon Mar 21 23:11:30 2016 +0000
Add a way to register a postpone callback in importer
This is meant for inflating saved searches and dashboards (see followup commits)
diff --git a/lib/RT/Migrate/Importer.pm b/lib/RT/Migrate/Importer.pm
index 7897434..0e6456a 100644
--- a/lib/RT/Migrate/Importer.pm
+++ b/lib/RT/Migrate/Importer.pm
@@ -179,6 +179,9 @@ sub Resolve {
Field => $ref->{uri},
Value => $self->LookupObj($uid)->URI,
) if defined $ref->{uri};
+ if (my $method = $ref->{method}) {
+ $obj->$method($self, $ref, $class, $id);
+ }
}
delete $self->{Pending}{$uid};
}
@@ -332,7 +335,7 @@ sub Create {
# Load it back to get real values into the columns
$obj = $class->new( RT->SystemUser );
$obj->Load( $id );
- $obj->PostInflate( $self );
+ $obj->PostInflate( $self, $uid );
return $obj;
}
commit 97cf2096df4b088dbc26de4db0b964e5d16219fd
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Mon Mar 21 23:12:52 2016 +0000
Don't skip importing RT->System searches
While this may duplicate the three builtin searches (bookmarked,
unowned, my tickets), we definitely do not want to lose any user-defined
searches saved at the system level.
Furthermore, when merging two RT instances, we may want each user to
continue using their system's customization of those three builtin
searches.
diff --git a/lib/RT/Attribute.pm b/lib/RT/Attribute.pm
index 9f69179..c493441 100644
--- a/lib/RT/Attribute.pm
+++ b/lib/RT/Attribute.pm
@@ -652,7 +652,12 @@ sub PreInflate {
if ($data->{Object} and ref $data->{Object}) {
my $on_uid = ${ $data->{Object} };
- return if $importer->ShouldSkipTransaction($on_uid);
+
+ # skip attributes of objects we're not inflating
+ # exception: we don't inflate RT->System, but we want RT->System's searches
+ unless ($on_uid eq RT->System->UID && $data->{Name} =~ /Search/) {
+ return if $importer->ShouldSkipTransaction($on_uid);
+ }
}
# decode UIDs to be raw dashboard IDs
commit f464c3f2fce0a81a77f0efe54a9311a2fc240b39
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Mon Mar 21 23:23:07 2016 +0000
Serialize RT at a Glance preferences using indirection
Otherwise the old search IDs will be kept in the user's preferences,
causing the homepage to render with "search not found" type errors.
Fixes: I#31809
diff --git a/lib/RT/Attribute.pm b/lib/RT/Attribute.pm
index c493441..9cf42f6 100644
--- a/lib/RT/Attribute.pm
+++ b/lib/RT/Attribute.pm
@@ -644,6 +644,33 @@ sub FindDependencies {
}
}
}
+ # homepage settings attribute has dependencies on each of the searches in it
+ elsif ($self->Name eq RT::User::_PrefName("HomepageSettings")) {
+ my $content = $self->Content;
+ for my $pane (values %{ $content || {} }) {
+ for my $component (@$pane) {
+ # this hairy code mirrors what's in the saved search loader
+ # in /Elements/ShowSearch
+ if ($component->{type} eq 'saved') {
+ if ($component->{name} =~ /^(.*?)-(\d+)-SavedSearch-(\d+)$/) {
+ my $attr = RT::Attribute->new($self->CurrentUser);
+ $attr->LoadById($3);
+ $deps->Add( out => $attr );
+ }
+ }
+ elsif ($component->{type} eq 'system') {
+ my ($search) = RT::System->new($self->CurrentUser)->Attributes->Named( 'Search - ' . $component->{name} );
+ unless ( $search && $search->Id ) {
+ my (@custom_searches) = RT::System->new($self->CurrentUser)->Attributes->Named('SavedSearch');
+ foreach my $custom (@custom_searches) {
+ if ($custom->Description eq $component->{name}) { $search = $custom; last }
+ }
+ }
+ $deps->Add( out => $search ) if $search;
+ }
+ }
+ }
+ }
}
sub PreInflate {
@@ -660,16 +687,89 @@ sub PreInflate {
}
}
+ return $class->SUPER::PreInflate( $importer, $uid, $data );
+}
+
+# this method will be called repeatedly to fix up this attribute's contents
+# (a list of searches, dashboards) during the import process, as the
+# ordinary dependency resolution system can't quite handle the subtlety
+# involved (e.g. a user simply declares out-dependencies on all of her
+# attributes, but those attributes (e.g. dashboards, saved searches,
+# dashboards in menu preferences) have dependencies amongst themselves).
+# if this attribute (e.g. a user's dashboard) fails to load an attribute
+# (e.g. a user's saved search) then it postpones and repeats the postinflate
+# process again when that user's saved search has been imported
+# this method updates Content each time through, each time getting closer and
+# closer to the fully inflated attribute
+sub PostInflateFixup {
+ my $self = shift;
+ my $importer = shift;
+ my $spec = shift;
+
# decode UIDs to be raw dashboard IDs
- if ($data->{Name} eq RT::User::_PrefName("DashboardsInMenu")) {
- my $content = $class->_DeserializeContent($data->{Content});
+ if ($self->Name eq RT::User::_PrefName("DashboardsInMenu")) {
+ my $content = $self->Content;
+
for my $pane (values %{ $content || {} }) {
- @$pane = map { $importer->LookupObj($$_)->Id } @$pane;
+ for (@$pane) {
+ if (ref($_) eq 'SCALAR') {
+ my $attr = $importer->LookupObj($$_);
+ if ($attr) {
+ $_ = $attr->Id;
+ }
+ else {
+ $importer->Postpone(
+ for => $$_,
+ uid => $spec->{uid},
+ method => 'PostInflateFixup',
+ );
+ }
+ }
+ }
}
- $data->{Content} = $class->_SerializeContent($content);
+ $self->SetContent($content);
}
+ # decode UIDs to be saved searches
+ elsif ($self->Name eq RT::User::_PrefName("HomepageSettings")) {
+ my $content = $self->Content;
- return $class->SUPER::PreInflate( $importer, $uid, $data );
+ for my $pane (values %{ $content || {} }) {
+ for (@$pane) {
+ if (ref($_->{uid}) eq 'SCALAR') {
+ my $uid = $_->{uid};
+ my $attr = $importer->LookupObj($$uid);
+
+ if ($attr) {
+ if ($_->{type} eq 'saved') {
+ $_->{name} = join '-', $attr->ObjectType, $attr->ObjectId, 'SavedSearch', $attr->id;
+ }
+ # if type is system, name doesn't need to change
+ # if type is anything else, pass it through as is
+ delete $_->{uid};
+ }
+ else {
+ $importer->Postpone(
+ for => $$uid,
+ uid => $spec->{uid},
+ method => 'PostInflateFixup',
+ );
+ }
+ }
+ }
+ }
+ $self->SetContent($content);
+ }
+}
+
+sub PostInflate {
+ my $self = shift;
+ my ($importer, $uid) = @_;
+
+ $self->SUPER::PostInflate( $importer, $uid );
+
+ # this method is separate because it needs to be callable multple times,
+ # and we can't guarantee that SUPER::PostInflate can deal with that
+ $self->PostInflateFixup($importer, { uid => $uid });
}
sub Serialize {
@@ -689,6 +789,39 @@ sub Serialize {
}
$store{Content} = $self->_SerializeContent($content);
}
+ # encode saved searches to be UIDs
+ elsif ($store{Name} eq RT::User::_PrefName("HomepageSettings")) {
+ my $content = $self->_DeserializeContent($store{Content});
+ for my $pane (values %{ $content || {} }) {
+ for (@$pane) {
+ # this hairy code mirrors what's in the saved search loader
+ # in /Elements/ShowSearch
+ if ($_->{type} eq 'saved') {
+ if ($_->{name} =~ /^(.*?)-(\d+)-SavedSearch-(\d+)$/) {
+ my $attr = RT::Attribute->new($self->CurrentUser);
+ $attr->LoadById($3);
+ $_->{uid} = \($attr->UID);
+ }
+ # if we can't parse the name, just pass it through
+ }
+ elsif ($_->{type} eq 'system') {
+ my ($search) = RT::System->new($self->CurrentUser)->Attributes->Named( 'Search - ' . $_->{name} );
+ unless ( $search && $search->Id ) {
+ my (@custom_searches) = RT::System->new($self->CurrentUser)->Attributes->Named('SavedSearch');
+ foreach my $custom (@custom_searches) {
+ if ($custom->Description eq $_->{name}) { $search = $custom; last }
+ }
+ }
+ # if we can't load the search, just pass it through
+ if ($search) {
+ $_->{uid} = \($search->UID);
+ }
+ }
+ # pass through everything else (e.g. component)
+ }
+ }
+ $store{Content} = $self->_SerializeContent($content);
+ }
return %store;
}
commit f05b6682d00d0113225dbcc62f79b8be0c8aa7e9
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Mon Mar 21 23:42:27 2016 +0000
Serialize dashboards using indirection
Otherwise the old search and dashboard IDs will be kept in the component
list, causing the dashboard to render with "search not found" type errors.
Fixes: I#31808
diff --git a/lib/RT/Attribute.pm b/lib/RT/Attribute.pm
index 9cf42f6..74c6be9 100644
--- a/lib/RT/Attribute.pm
+++ b/lib/RT/Attribute.pm
@@ -671,6 +671,19 @@ sub FindDependencies {
}
}
}
+ # dashboards have dependencies on all the searches and dashboards they use
+ elsif ($self->Name eq 'Dashboard') {
+ my $content = $self->Content;
+ for my $pane (values %{ $content->{Panes} || {} }) {
+ for my $component (@$pane) {
+ if ($component->{portlet_type} eq 'search' || $component->{portlet_type} eq 'dashboard') {
+ my $attr = RT::Attribute->new($self->CurrentUser);
+ $attr->LoadById($component->{id});
+ $deps->Add( out => $attr );
+ }
+ }
+ }
+ }
}
sub PreInflate {
@@ -759,6 +772,33 @@ sub PostInflateFixup {
}
$self->SetContent($content);
}
+ elsif ($self->Name eq 'Dashboard') {
+ my $content = $self->Content;
+
+ for my $pane (values %{ $content->{Panes} || {} }) {
+ for (@$pane) {
+ if (ref($_->{uid}) eq 'SCALAR') {
+ my $uid = $_->{uid};
+ my $attr = $importer->LookupObj($$uid);
+
+ if ($attr) {
+ # update with the new id numbers assigned to us
+ $_->{id} = $attr->Id;
+ $_->{privacy} = join '-', $attr->ObjectType, $attr->ObjectId;
+ delete $_->{uid};
+ }
+ else {
+ $importer->Postpone(
+ for => $$uid,
+ uid => $spec->{uid},
+ method => 'PostInflateFixup',
+ );
+ }
+ }
+ }
+ }
+ $self->SetContent($content);
+ }
}
sub PostInflate {
@@ -822,6 +862,21 @@ sub Serialize {
}
$store{Content} = $self->_SerializeContent($content);
}
+ # encode saved searches and dashboards to be UIDs
+ elsif ($store{Name} eq 'Dashboard') {
+ my $content = $self->_DeserializeContent($store{Content}) || {};
+ for my $pane (values %{ $content->{Panes} || {} }) {
+ for (@$pane) {
+ if ($_->{portlet_type} eq 'search' || $_->{portlet_type} eq 'dashboard') {
+ my $attr = RT::Attribute->new($self->CurrentUser);
+ $attr->LoadById($_->{id});
+ $_->{uid} = \($attr->UID);
+ }
+ # pass through everything else (e.g. component)
+ }
+ }
+ $store{Content} = $self->_SerializeContent($content);
+ }
return %store;
}
commit 1240499ed3e548486b2a857447c8db990a09a987
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Mon Mar 21 23:43:03 2016 +0000
Serialize dashboard subscriptions using indirection
Otherwise the old dashboard ID will be kept in the subscription,
causing it to go missing.
diff --git a/lib/RT/Attribute.pm b/lib/RT/Attribute.pm
index 74c6be9..a78a6f6 100644
--- a/lib/RT/Attribute.pm
+++ b/lib/RT/Attribute.pm
@@ -684,6 +684,13 @@ sub FindDependencies {
}
}
}
+ # subscriptions have dependencies their dashboard
+ elsif ($self->Name eq 'Subscription') {
+ my $content = $self->Content;
+ my $attr = RT::Attribute->new($self->CurrentUser);
+ $attr->LoadById($content->{DashboardId});
+ $deps->Add( out => $attr );
+ }
}
sub PreInflate {
@@ -799,6 +806,23 @@ sub PostInflateFixup {
}
$self->SetContent($content);
}
+ elsif ($self->Name eq 'Subscription') {
+ my $content = $self->Content;
+ if (ref($content->{DashboardId}) eq 'SCALAR') {
+ my $attr = $importer->LookupObj(${ $content->{DashboardId} });
+ if ($attr) {
+ $content->{DashboardId} = $attr->Id;
+ }
+ else {
+ $importer->Postpone(
+ for => ${ $content->{DashboardId} },
+ uid => $spec->{uid},
+ method => 'PostInflateFixup',
+ );
+ }
+ }
+ $self->SetContent($content);
+ }
}
sub PostInflate {
@@ -877,6 +901,14 @@ sub Serialize {
}
$store{Content} = $self->_SerializeContent($content);
}
+ # encode subscriptions to have dashboard UID
+ elsif ($store{Name} eq 'Subscription') {
+ my $content = $self->_DeserializeContent($store{Content});
+ my $attr = RT::Attribute->new($self->CurrentUser);
+ $attr->LoadById($content->{DashboardId});
+ $content->{DashboardId} = \($attr->UID);
+ $store{Content} = $self->_SerializeContent($content);
+ }
return %store;
}
commit cd06315e3d98c6ee1094afa22776d5296c9c8f96
Author: Shawn M Moore <shawn at bestpractical.com>
Date: Fri Mar 25 01:29:47 2016 +0000
--exclude-organization option for rt-importer
When records are already known to be unique this is unwanted noise.
Fixes: I#31813
Fixes: I#31812
diff --git a/lib/RT/Migrate/Importer.pm b/lib/RT/Migrate/Importer.pm
index 0e6456a..5c25d9a 100644
--- a/lib/RT/Migrate/Importer.pm
+++ b/lib/RT/Migrate/Importer.pm
@@ -65,17 +65,20 @@ sub new {
sub Init {
my $self = shift;
my %args = (
- OriginalId => undef,
- Progress => undef,
- Statefile => undef,
- DumpObjects => undef,
- HandleError => undef,
+ OriginalId => undef,
+ Progress => undef,
+ Statefile => undef,
+ DumpObjects => undef,
+ HandleError => undef,
+ ExcludeOrganization => undef,
@_,
);
# Should we attempt to preserve record IDs as they are created?
$self->{OriginalId} = $args{OriginalId};
+ $self->{ExcludeOrganization} = $args{ExcludeOrganization};
+
$self->{Progress} = $args{Progress};
$self->{HandleError} = sub { 0 };
@@ -294,6 +297,7 @@ sub Qualify {
my ($string) = @_;
return $string if $self->{Clone};
return $string if not defined $self->{Organization};
+ return $string if $self->{ExcludeOrganization};
return $string if $self->{Organization} eq $RT::Organization;
return $self->{Organization}.": $string";
}
@@ -402,9 +406,13 @@ sub ReadStream {
# If it's a ticket, we might need to create a
# TicketCustomField for the previous ID
if ($class eq "RT::Ticket" and $self->{OriginalId}) {
+ my $value = $self->{ExcludeOrganization}
+ ? $origid
+ : $self->Organization . ":$origid";
+
my ($id, $msg) = $obj->AddCustomFieldValue(
Field => $self->{OriginalId},
- Value => $self->Organization . ":$origid",
+ Value => $value,
RecordTransaction => 0,
);
warn "Failed to add custom field to $uid: $msg"
diff --git a/lib/RT/Migrate/Importer/File.pm b/lib/RT/Migrate/Importer/File.pm
index cfad9ae..3d36f3d 100644
--- a/lib/RT/Migrate/Importer/File.pm
+++ b/lib/RT/Migrate/Importer/File.pm
@@ -192,7 +192,7 @@ sub SaveState {
NewQueues NewCFs
SkipTransactions Pending Invalid
UIDs
- OriginalId Clone
+ OriginalId ExcludeOrganization Clone
/;
Storable::nstore(\%data, $self->{Statefile});
diff --git a/sbin/rt-importer.in b/sbin/rt-importer.in
index 6d3cda5..1f9e6e6 100644
--- a/sbin/rt-importer.in
+++ b/sbin/rt-importer.in
@@ -95,6 +95,7 @@ GetOptions(
"resume!",
"originalid|i=s",
+ "exclude-organization",
"ask",
"ignore-errors",
@@ -142,11 +143,12 @@ elsif ($OPT{'ignore-errors'}) {
}
my $import = RT::Migrate::Importer::File->new(
- Directory => $dir,
- OriginalId => $OPT{originalid},
- DumpObjects => $OPT{dump},
- Resume => $OPT{resume},
- HandleError => $error_handler,
+ Directory => $dir,
+ OriginalId => $OPT{originalid},
+ ExcludeOrganization => $OPT{'exclude-organization'},
+ DumpObjects => $OPT{dump},
+ Resume => $OPT{resume},
+ HandleError => $error_handler,
);
if ($import->Metadata and -t STDOUT and not $OPT{quiet}) {
@@ -236,6 +238,12 @@ Places the original ticket organization and ID into a global custom
field with the given name. If no global ticket custom field with that
name is found in the current database, it will create one.
+=item B<--exclude-organization>
+
+Ordinarily certain records (groups, queues, the B<--originalid> custom field)
+include the organization name of the original RT instance. Use this option to
+suppress that behavior and use the original name directly.
+
=item B<--ask>
Prompt for action when an error occurs inserting a record into the
-----------------------------------------------------------------------
More information about the rt-commit
mailing list