[Rt-commit] rt branch 5.0/dump-initialdata-copy-queues created. rt-5.0.3-64-g827995ee9d
BPS Git Server
git at git.bestpractical.com
Thu Jul 28 20:51:43 UTC 2022
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "rt".
The branch, 5.0/dump-initialdata-copy-queues has been created
at 827995ee9dd168339059a525d9dd4c1bc33644b9 (commit)
- Log -----------------------------------------------------------------
commit 827995ee9dd168339059a525d9dd4c1bc33644b9
Author: sunnavy <sunnavy at bestpractical.com>
Date: Fri Jul 29 04:19:49 2022 +0800
Test copying queue config via rt-dump-initialdata
It covers queue itself, ACL, watchers, scrips, templates, custom fields,
custom roles and also article classes.
diff --git a/t/api/initialdata_copy_queue.t b/t/api/initialdata_copy_queue.t
new file mode 100644
index 0000000000..694a4c82c5
--- /dev/null
+++ b/t/api/initialdata_copy_queue.t
@@ -0,0 +1,261 @@
+use warnings;
+use strict;
+
+use RT::Test tests => undef;
+RT->Config->Set( 'InitialdataFormatHandlers' => [ 'perl', 'RT::Initialdata::JSON' ] );
+
+my $general = RT::Test->load_or_create_queue( Name => 'General' );
+my $queue = RT::Test->load_or_create_queue( Name => 'Test' );
+
+my $user = RT::Test->load_or_create_user( Name => 'alice' );
+my $group = RT::Test->load_or_create_group('Duty');
+my $engineer = RT::CustomRole->new( RT->SystemUser );
+ok(
+ $engineer->Create(
+ Name => 'Engineer',
+ MaxValues => 0,
+ )
+);
+ok( $engineer->AddToObject( $_->id ) ) for $general, $queue;
+my $class = RT::Class->new( RT->SystemUser );
+ok( $class->Create( Name => 'FAQ' ) );
+ok( $class->AddToObject($_) ) for $general, $queue;
+
+ok( $queue->AddWatcher(Type => 'AdminCc', PrincipalId => $user->Id ) );
+ok( $queue->AddWatcher(Type => 'Cc', PrincipalId => $group->Id ) );
+
+my $scrip = RT::Scrip->new( RT->SystemUser );
+ok(
+ $scrip->Create(
+ Description => 'On Comment Notify Owner',
+ ScripCondition => 'On Comment',
+ ScripAction => 'Notify Owner',
+ Template => 'Blank',
+ )
+);
+
+ok( $scrip->AddToObject( $_->id ) ) for $general, $queue;
+
+my $template = RT::Template->new( RT->SystemUser );
+ok( $template->Create( Name => 'Foo', Description => 'Foo Description', Queue => $queue->Id, Content => q{Foo} ) );
+
+my $custom_field = RT::Test->load_or_create_custom_field(
+ Name => 'Action',
+ Type => 'FreeformSingle',
+ Queue => $queue->Id,
+);
+ok( $custom_field->SetDefaultValues( Object => $queue, Values => 'review, merge' ) );
+
+
+RT::Test->add_rights(
+ { Principal => 'Everyone', Right => 'SeeQueue', Object => RT->System },
+ { Principal => 'Requestor', Right => 'ShowTicket', Object => $general },
+ { Principal => $group, Right => 'TakeTicket', Object => RT->System },
+ { Principal => $user, Right => 'StealTicket', Object => $general },
+ { Principal => $engineer->GroupType, Right => 'CreateTicket', Object => RT->System },
+
+ { Principal => 'Privileged', Right => 'ReplyToTicket', Object => $queue },
+ { Principal => 'AdminCc', Right => 'CommentOnTicket', Object => $queue },
+ { Principal => $user, Right => 'SeeCustomField', Object => $queue },
+ { Principal => $group, Right => 'ModifyTicket', Object => $queue },
+ { Principal => $engineer->GroupType, Right => 'OwnTicket', Object => $queue },
+);
+
+my $parent_dir = RT->Config->Get('LogDir');
+my $global_dir = File::Spec->catdir( $parent_dir, 'global' );
+my $queue_dir = File::Spec->catdir( $parent_dir, 'queue' );
+
+diag "Export queue Test";
+
+ok(
+ RT::Test->run_singleton_command(
+ 'sbin/rt-dump-initialdata', '--quiet', '--dir', $global_dir, '--sync', '--no-queues',
+ ),
+ 'Dump global initialdata'
+);
+
+ok(
+ RT::Test->run_singleton_command(
+ 'sbin/rt-dump-initialdata', '--quiet', '--dir', $queue_dir, '--sync', '--limit-queues', 'Test', '--base',
+ File::Spec->catfile( $global_dir, 'initialdata.json' ),
+ ),
+ 'Dump Test queue changes'
+);
+
+my $changes;
+{
+ open my $fh, "<" . File::Spec->catfile( $queue_dir, 'changes.json' ) or die "Can't load changes.json";
+ local $/;
+ $changes = <$fh>;
+}
+
+my $expected_changes = JSON::decode_json(<<'EOF');
+{
+ "ACL" : [
+ {
+ "GroupDomain" : "SystemInternal",
+ "GroupType" : "Privileged",
+ "ObjectId" : "Test",
+ "ObjectType" : "RT::Queue",
+ "RightName" : "ReplyToTicket"
+ },
+ {
+ "GroupDomain" : "RT::Queue-Role",
+ "GroupType" : "AdminCc",
+ "ObjectId" : "Test",
+ "ObjectType" : "RT::Queue",
+ "RightName" : "CommentOnTicket"
+ },
+ {
+ "ObjectId" : "Test",
+ "ObjectType" : "RT::Queue",
+ "RightName" : "SeeCustomField",
+ "UserId" : "alice"
+ },
+ {
+ "GroupDomain" : "UserDefined",
+ "GroupId" : "Duty",
+ "ObjectId" : "Test",
+ "ObjectType" : "RT::Queue",
+ "RightName" : "ModifyTicket"
+ },
+ {
+ "GroupDomain" : "RT::Queue-Role",
+ "GroupType" : "RT::CustomRole-Engineer",
+ "ObjectId" : "Test",
+ "ObjectType" : "RT::Queue",
+ "RightName" : "OwnTicket"
+ }
+ ],
+ "Attributes" : [
+ {
+ "Content" : {
+ "Action" : "review, merge"
+ },
+ "ContentType" : "storable",
+ "Name" : "CustomFieldDefaultValues",
+ "Object" : "Test",
+ "ObjectType" : "RT::Queue"
+ }
+ ],
+ "Classes" : [
+ {
+ "ApplyTo" : [
+ "Test"
+ ],
+ "_Original" : {
+ "ApplyTo" : [],
+ "Description" : "",
+ "Name" : "FAQ",
+ "SortOrder" : 0
+ },
+ "_Updated" : 1
+ }
+ ],
+ "CustomFields" : [
+ {
+ "ApplyTo" : [
+ "Test"
+ ],
+ "_Original" : {
+ "ApplyTo" : [],
+ "Description" : "",
+ "EntryHint" : "Enter one value",
+ "LookupType" : "RT::Queue-RT::Ticket",
+ "MaxValues" : 1,
+ "Name" : "Action",
+ "SortOrder" : 0,
+ "Type" : "Freeform"
+ },
+ "_Updated" : 1
+ }
+ ],
+ "CustomRoles" : [
+ {
+ "ApplyTo" : [
+ "Test"
+ ],
+ "_Original" : {
+ "Description" : "",
+ "EntryHint" : "",
+ "MaxValues" : 0,
+ "Name" : "Engineer"
+ },
+ "_Updated" : 1
+ }
+ ],
+ "Members" : [
+ {
+ "Class" : "RT::User",
+ "Group" : "AdminCc",
+ "GroupDomain" : "RT::Queue-Role",
+ "GroupInstance" : "Test",
+ "Name" : "alice"
+ },
+ {
+ "Class" : "RT::Group",
+ "Group" : "Cc",
+ "GroupDomain" : "RT::Queue-Role",
+ "GroupInstance" : "Test",
+ "Name" : "Duty"
+ }
+ ],
+ "Queues" : [
+ {
+ "CommentAddress" : "",
+ "CorrespondAddress" : "",
+ "Description" : "",
+ "Lifecycle" : "default",
+ "Name" : "Test",
+ "SLADisabled" : 1,
+ "SortOrder" : 0
+ }
+ ],
+ "Templates" : [
+ {
+ "Content" : "Foo",
+ "Description" : "Foo Description",
+ "Name" : "Foo",
+ "Queue" : "Test",
+ "Type" : "Perl"
+ }
+ ]
+}
+EOF
+
+is_deeply( JSON::decode_json($changes), $expected_changes, 'Generated changes look good' );
+
+diag "Import queue Test with a new name";
+$changes =~ s/"Test"/"Test2"/g;
+
+open my $fh, '>', File::Spec->catdir( $parent_dir, 'queue_changes.json' );
+print $fh $changes;
+close $fh;
+
+ok(
+ RT->DatabaseHandle->InsertData(
+ File::Spec->catdir( $parent_dir, 'queue_changes.json' ),
+ undef, disconnect_after => 0
+ )
+);
+
+$queue_dir = File::Spec->catdir( $parent_dir, 'queue2' );
+
+ok(
+ RT::Test->run_singleton_command(
+ 'sbin/rt-dump-initialdata', '--quiet', '--dir', $queue_dir, '--sync', '--limit-queues', 'Test2', '--base',
+ File::Spec->catfile( $global_dir, 'initialdata.json' ),
+ ),
+ 'Dump Test2 queue changes'
+);
+
+my $new_changes;
+{
+ open my $fh, "<" . File::Spec->catfile( $queue_dir, 'changes.json' ) or die "Can't load changes.json";
+ local $/;
+ $new_changes = <$fh>;
+}
+
+is_deeply( JSON::decode_json($new_changes), JSON::decode_json($changes), 'Generated changes look good' );
+
+done_testing;
commit 67ac0157a775171067a533d0cfae58f2ae3d2cd0
Author: sunnavy <sunnavy at bestpractical.com>
Date: Thu Jul 28 22:35:40 2022 +0800
Support to dump and import CustomFieldDefaultValues attributes with cf name
The content in db is like:
{ 2 => 'value1', 3 => 'value2' }
This commit tweaks it to:
{ foo => 'value1', bar => 'value2' }
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index e7f27404a1..549eb6ea75 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -3172,6 +3172,23 @@ sub _CanonilizeAttributeContent {
}
}
}
+ elsif ( $item->{Name} eq 'CustomFieldDefaultValues' ) {
+ my %value;
+ for my $name ( keys %{ $item->{Content} || {} } ) {
+ my $custom_field = RT::CustomField->new( RT->SystemUser );
+ $custom_field->LoadByName(
+ Name => $name,
+ IncludeGlobal => 1,
+ ObjectType => $item->{ObjectType},
+ ObjectId => $item->{ObjectId},
+ );
+
+ if ( $custom_field->Id ) {
+ $value{ $custom_field->Id } = $item->{Content}{$name};
+ }
+ }
+ $item->{Content} = \%value;
+ }
}
sub _CanonilizeObjectCustomFieldValue {
diff --git a/lib/RT/Migrate/Serializer/JSON.pm b/lib/RT/Migrate/Serializer/JSON.pm
index dabd595003..3f03a70f2f 100644
--- a/lib/RT/Migrate/Serializer/JSON.pm
+++ b/lib/RT/Migrate/Serializer/JSON.pm
@@ -541,6 +541,17 @@ sub CanonicalizeAttributes {
}
}
}
+ elsif ( $record->{Name} eq 'CustomFieldDefaultValues' ) {
+ my %value;
+ for my $id ( keys %{ $record->{Content} || {} } ) {
+ my $custom_field = RT::CustomField->new( RT->SystemUser );
+ $custom_field->Load($id);
+ if ( $custom_field->Id ) {
+ $value{ $custom_field->Name } = $record->{Content}{$id};
+ }
+ }
+ $record->{Content} = \%value;
+ }
}
}
elsif ( $record->{Name} =~ /DefaultDashboard$/ ) {
commit 4cdd421158b8076d4f7870d6b1ec106b2092894a
Author: sunnavy <sunnavy at bestpractical.com>
Date: Thu Jul 28 22:04:07 2022 +0800
Support to dump and import custom role ACL with custom role name
This is for custom role groups like "RT::CustomRole-1", this commit
tweaks it to something like "RT::CustomRole-Enginner".
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index 15b16a7735..e7f27404a1 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -1554,10 +1554,31 @@ sub InsertData {
$princ->LoadUserDefinedGroup( $item->{'GroupId'} );
} elsif ( $item->{'GroupDomain'} eq 'SystemInternal' ) {
$princ->LoadSystemInternalGroup( $item->{'GroupType'} );
- } elsif ( $item->{'GroupDomain'} eq 'RT::System-Role' ) {
- $princ->LoadRoleGroup( Object => RT->System, Name => $item->{'GroupType'} );
} elsif ( $item->{'GroupDomain'} =~ /-Role$/ ) {
- $princ->LoadRoleGroup( Object => $object, Name => $item->{'GroupType'} );
+ my $obj;
+ if ( $item->{'GroupDomain'} eq 'RT::System-Role' ) {
+ $obj = RT->System;
+ }
+ else {
+ $obj = $object;
+ }
+
+ if ( $item->{GroupType} =~ /^RT::CustomRole-(.+)$/ ) {
+ my $id = $1;
+
+ # $id could be Name
+ if ( $id =~ /\D/ ) {
+ my $custom_role = RT::CustomRole->new( RT->SystemUser );
+ $custom_role->Load($id);
+ if ( $custom_role->Id ) {
+ $item->{GroupType} = $custom_role->GroupType;
+ }
+ else {
+ RT->Logger->error("Unable to load custom role $id");
+ }
+ }
+ }
+ $princ->LoadRoleGroup( Object => $obj, Name => $item->{'GroupType'} );
} else {
$princ->Load( $item->{'GroupId'} );
}
@@ -2950,12 +2971,13 @@ sub _LoadObject {
if ( $values->{_Original}{'GroupDomain'} eq 'SystemInternal' ) {
$group->LoadSystemInternalGroup( $values->{_Original}{GroupType} );
}
- elsif ( $values->{_Original}{'GroupDomain'} eq 'RT::System-Role' ) {
- $group->LoadRoleGroup( Object => RT->System, Name => $values->{_Original}{GroupType} );
- }
elsif ( $values->{_Original}{'GroupDomain'} =~ /-Role$/ ) {
my $object;
- if ( $values->{_Original}{ObjectType} and $values->{_Original}{ObjectId} ) {
+
+ if ( $values->{_Original}{'GroupDomain'} eq 'RT::System-Role' ) {
+ $object = RT->System;
+ }
+ elsif ( $values->{_Original}{ObjectType} and $values->{_Original}{ObjectId} ) {
$object = $values->{_Original}{ObjectType}->new( RT->SystemUser );
my ( $ok, $msg ) = $object->Load( $values->{_Original}{ObjectId} );
unless ($ok) {
@@ -2969,6 +2991,20 @@ sub _LoadObject {
else {
$object = RT->System;
}
+ if ( $values->{_Original}{GroupType} =~ /^RT::CustomRole-(.+)$/ ) {
+ my $id = $1;
+ # $id could be Name
+ if ( $id =~ /\D/ ) {
+ my $custom_role = RT::CustomRole->new(RT->SystemUser);
+ $custom_role->Load($id);
+ if ( $custom_role->Id ) {
+ $values->{_Original}{GroupType} = $custom_role->GroupType;
+ }
+ else {
+ RT->Logger->error("Unable to load custom role $id");
+ }
+ }
+ }
$group->LoadRoleGroup( Object => $object, Name => $values->{_Original}{GroupType} );
}
diff --git a/lib/RT/Migrate/Serializer/JSON.pm b/lib/RT/Migrate/Serializer/JSON.pm
index 78c008c665..dabd595003 100644
--- a/lib/RT/Migrate/Serializer/JSON.pm
+++ b/lib/RT/Migrate/Serializer/JSON.pm
@@ -318,7 +318,12 @@ sub CanonicalizeACLs {
$ace->{GroupId} = $group->Name;
}
if ($domain eq 'SystemInternal' || $domain =~ /-Role$/) {
- $ace->{GroupType} = $group->Name;
+ if ( $group->Name =~ /^RT::CustomRole-\d+$/ ) {
+ $ace->{GroupType} = 'RT::CustomRole-' . $group->_CustomRoleObj->Name;
+ }
+ else {
+ $ace->{GroupType} = $group->Name;
+ }
}
}
}
commit 2d92af4fe50c1096d3031eaceea71b6edab74737
Author: sunnavy <sunnavy at bestpractical.com>
Date: Sat Jul 23 02:59:51 2022 +0800
Add --limit-queues and --no-queues support for rt-dump-initialdata
--limit-queues is simply a clone from rt-serializer, --no-queues is to
export configs without any queue specific ones.
diff --git a/sbin/rt-dump-initialdata.in b/sbin/rt-dump-initialdata.in
index 98a30648b2..e443d7c76d 100644
--- a/sbin/rt-dump-initialdata.in
+++ b/sbin/rt-dump-initialdata.in
@@ -105,6 +105,8 @@ GetOptions(
"scrips!",
"acls!",
"assets!",
+ 'queues!',
+ "limit-queues=s@",
"sync",
@@ -136,6 +138,26 @@ $args{Sync} = 1 if $OPT{sync} || $OPT{base};
$args{GC} = defined $OPT{gc} ? $OPT{gc} : 5000;
$args{Page} = defined $OPT{page} ? $OPT{page} : 100;
+if ( defined $OPT{'queues'} ) {
+ $args{Queues} = [] unless $OPT{'queues'};
+}
+elsif ( $OPT{'limit-queues'} ) {
+ my @queue_ids;
+
+ for my $name ( split ',', join ',', @{ $OPT{'limit-queues'} } ) {
+ $name =~ s/^\s+//;
+ $name =~ s/\s+$//;
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load($name);
+ if ( !$queue->Id ) {
+ die "Unable to load queue '$name'";
+ }
+ push @queue_ids, $queue->Id;
+ }
+
+ $args{Queues} = \@queue_ids;
+}
+
my $walker;
my $gnuplot = `which gnuplot`;
@@ -467,6 +489,15 @@ skips them.
By default, all ACLs are dumped; passing C<--no-acls> skips them.
+=item B<--no-queues>
+
+By default, all queues are dumped; passing C<--no-queues> skips them.
+
+=item B<--limit-queues>
+
+Takes a list of queue IDs or names separated by commas. When provided, only
+that set of queues will be dumped.
+
=item B<--sync>
By default, record ids are ordinarily excluded. Pass C<--sync> to
commit 8fa64ea1e1b974daa36b2bae6542f9fdec35ec1f
Author: sunnavy <sunnavy at bestpractical.com>
Date: Thu Jul 28 02:28:31 2022 +0800
Handle ObjectClass updates for article classes in initialdata
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index 177b9e5ce1..15b16a7735 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -2660,7 +2660,7 @@ sub _UpdateObject {
next;
}
}
- if ( $class eq 'RT::CustomRole' ) {
+ elsif ( $class eq 'RT::CustomRole' ) {
if ( $field eq 'ApplyTo' ) {
my %current;
my %new;
@@ -2711,6 +2711,61 @@ sub _UpdateObject {
next;
}
}
+ elsif ( $class eq 'RT::Class' ) {
+ if ( $field eq 'ApplyTo' ) {
+ my %current;
+ my %new;
+
+ # Calculate changes based on $original if possible
+ if ( defined $original->{ApplyTo} ) {
+ for my $item ( @{ $original->{ApplyTo} } ) {
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load($item);
+ if ( $queue->Id ) {
+ $current{ $queue->Id } = 1;
+ }
+ }
+ }
+ else {
+ my $ocs = RT::ObjectClasses->new( RT->SystemUser );
+ $ocs->LimitToClass( $object->id );
+
+ while ( my $oc = $ocs->Next ) {
+ $current{ $oc->ObjectId } = 1;
+ }
+ }
+
+
+ for my $item ( @{ $value || [] } ) {
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load($item);
+ if ( $queue->Id ) {
+ $new{ $queue->Id } = 1;
+ }
+ }
+
+ for my $id ( keys %current ) {
+ next if $new{$id};
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load($id);
+ my ( $ret, $msg ) = $object->RemoveFromObject( $queue );
+ if ( !$ret ) {
+ RT->Logger->error( "Couldn't remove Class #" . $object->Id . " from Queue #$id: $msg" );
+ }
+ }
+
+ for my $id ( keys %new ) {
+ next if $current{$id};
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load($id);
+ my ( $ret, $msg ) = $object->AddToObject($queue);
+ if ( !$ret ) {
+ RT->Logger->error( "Couldn't add Class #" . $object->Id . " to Queue #$id: $msg" );
+ }
+ }
+ next;
+ }
+ }
elsif ( $class eq 'RT::Scrip' ) {
if ( $field eq 'Queue' ) {
my %current;
commit 1ce0d06608eedf28e0e406fb72328fb95be88e48
Author: sunnavy <sunnavy at bestpractical.com>
Date: Thu Jul 28 02:17:10 2022 +0800
Handle ObjectCustomRole updates for custom roles in initialdata
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index 954ceb010c..177b9e5ce1 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -2660,6 +2660,57 @@ sub _UpdateObject {
next;
}
}
+ if ( $class eq 'RT::CustomRole' ) {
+ if ( $field eq 'ApplyTo' ) {
+ my %current;
+ my %new;
+
+ # Calculate changes based on $original if possible
+ if ( defined $original->{ApplyTo} ) {
+ for my $item ( @{ $original->{ApplyTo} } ) {
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load($item);
+ if ( $queue->Id ) {
+ $current{ $queue->Id } = 1;
+ }
+ }
+ }
+ else {
+ my $ocrs = RT::ObjectCustomRoles->new( RT->SystemUser );
+ $ocrs->LimitToCustomRole( $object->id );
+
+ while ( my $ocr = $ocrs->Next ) {
+ $current{ $ocr->ObjectId } = 1;
+ }
+ }
+
+
+ for my $item ( @{ $value || [] } ) {
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load($item);
+ if ( $queue->Id ) {
+ $new{ $queue->Id } = 1;
+ }
+ }
+
+ for my $id ( keys %current ) {
+ next if $new{$id};
+ my ($ret, $msg) = $object->RemoveFromObject($id);
+ if ( !$ret ) {
+ RT->Logger->error( "Couldn't remove CustomRole #" . $object->Id . " from Queue #$id: $msg" );
+ }
+ }
+
+ for my $id ( keys %new ) {
+ next if $current{$id};
+ my ($ret, $msg) = $object->AddToObject($id);
+ if ( !$ret ) {
+ RT->Logger->error( "Couldn't add CustomRole #" . $object->id . " to Queue #$id: $msg" );
+ }
+ }
+ next;
+ }
+ }
elsif ( $class eq 'RT::Scrip' ) {
if ( $field eq 'Queue' ) {
my %current;
commit 9fe1355ba955b645ebb5aaab3ee04900a369db9a
Author: sunnavy <sunnavy at bestpractical.com>
Date: Wed Sep 22 03:07:57 2021 +0800
Handle ObjectScrip updates for scrips in initialdata
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index 2a7977c46b..954ceb010c 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -2517,8 +2517,12 @@ sub _UpdateObject {
}
}
- for my $field ( sort { $a eq 'ApplyTo' || $b eq 'ApplyTo' ? 1 : 0 } keys %$values ) {
+ my %order = (
+ 'Queue' => 1,
+ 'ApplyTo' => 1,
+ );
+ for my $field ( sort { ( $order{$a} || 0 ) <=> ( $order{b} || 0 ) } keys %$values ) {
if ( $class eq 'RT::Attribute' ) {
if ( $field eq 'Content' ) {
$self->_CanonilizeAttributeContent( $values );
@@ -2656,6 +2660,98 @@ sub _UpdateObject {
next;
}
}
+ elsif ( $class eq 'RT::Scrip' ) {
+ if ( $field eq 'Queue' ) {
+ my %current;
+ my %new;
+
+ # Calculate changes based on $original if possible
+ if ( defined $original->{Queue} ) {
+ for my $item ( @{$original->{Queue}} ) {
+ # Globally applied
+ if ( $item->{ObjectId} eq 0 ) {
+ $current{ $item->{Stage} }{0} = $item->{SortOrder};
+ }
+ else {
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load( $item->{ObjectId} );
+ if ( $queue->id ) {
+ $current{ $item->{Stage} }{ $queue->id } = $item->{SortOrder};
+ }
+ }
+ }
+ }
+ else {
+ my $object_scrips = RT::ObjectScrips->new(RT->SystemUser);
+ $object_scrips->LimitToScrip($object->id);
+
+ while ( my $object_scrip = $object_scrips->Next ) {
+ $current{$object_scrip->Stage}{$object_scrip->ObjectId} = $object_scrip->SortOrder;
+ }
+ }
+
+ for my $item ( @{ $value || [] } ) {
+ if ( $item->{ObjectId} eq 0 ) {
+ $new{ $item->{Stage} }{0} = $item->{SortOrder};
+ }
+ else {
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load( $item->{ObjectId} );
+ if ( $queue->id ) {
+ $new{ $item->{Stage} }{ $queue->id } = $item->{SortOrder};
+ }
+ }
+ }
+
+ for my $stage ( sort keys %current ) {
+ for my $id ( sort { $current{$stage}{$a} <=> $current{$stage}{$b} } keys %{ $current{$stage} } ) {
+ my $object_scrip = RT::ObjectScrip->new( RT->SystemUser );
+ $object_scrip->LoadByCols( Scrip => $object->id, ObjectId => $id, Stage => $stage );
+ if ( $object_scrip->id ) {
+ if ( defined $new{$stage}{$id} ) {
+ if ( $new{$stage}{$id} != $current{$stage}{$id} ) {
+ my ( $ret, $msg ) = $object_scrip->SetSortOrder( $new{$stage}{$id} );
+ if ( !$ret ) {
+ RT->Logger->error( "Couldn't update SortOrder of ObjectScrip #"
+ . $object_scrip->id
+ . ": $msg" );
+ }
+ }
+ }
+ else {
+ my ( $ret, $msg ) = $object_scrip->Delete;
+ if ( !$ret ) {
+ RT->Logger->error( "Couldn't delete ObjectScrip #" . $object_scrip->id . ": $msg" );
+ }
+ }
+ }
+ }
+ }
+
+ for my $stage ( sort keys %new ) {
+ for my $id ( sort { $new{$stage}{$a} <=> $new{$stage}{$b} } keys %{ $new{$stage} } ) {
+ next if defined $current{$stage}{$id};
+
+ my $object_scrip = RT::ObjectScrip->new( RT->SystemUser );
+ $object_scrip->LoadByCols( Scrip => $object->id, ObjectId => $id, Stage => $stage );
+ if ( !$object_scrip->id ) {
+ my ( $ret, $msg ) = $object_scrip->Create(
+ Scrip => $object->id,
+ ObjectId => $id,
+ Stage => $stage,
+ SortOrder => $new{$stage}{SortOrder},
+ );
+ if ( !$ret ) {
+ RT->Logger->error( "Couldn't create ObjectScrip for Scrip #"
+ . $object->id
+ . " and Queue #$id: $msg" );
+ }
+ }
+ }
+ }
+ next;
+ }
+ }
next unless $object->can( $field ) || $object->_Accessible( $field, 'read' );
my $old_value = $object->can( $field ) ? $object->$field : $object->_Value( $field );
commit e963da9bb05797a70d53cb12da50a5fc186645eb
Author: sunnavy <sunnavy at bestpractical.com>
Date: Thu Jul 28 01:32:29 2022 +0800
Calculate ObjectCustomField changes based on source RT if possible
Previously we always calculated changes based on target RT, which could
involve unexpected changes. E.g. if a custom field is applied to a new
Queue in source RT and we want to sync this change to target RT,
previously if target RT had some extra queues applied(i.e. ones not
applied in source RT), these queues would be revoked after sync.
This is initially to sync changes of specific queues, just like the
example above.
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index 4be4295d89..2a7977c46b 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -2532,18 +2532,36 @@ sub _UpdateObject {
my %current;
my %new;
- my $ocfs = RT::ObjectCustomFields->new(RT->SystemUser);
- $ocfs->LimitToCustomField($object->id);
-
- while ( my $ocf = $ocfs->Next ) {
- if ( $ocf->ObjectId == 0 ) {
- $current{0} = 1;
- }
- else {
- my $added = $object->RecordClassFromLookupType->new( RT->SystemUser );
- $current{$ocf->ObjectId} = 1;
+ # Calculate changes based on $original if possible
+ if ( defined $original->{ApplyTo} ) {
+ for my $item ( @{$original->{ApplyTo}} ) {
+ # Globally applied
+ if ( $item eq 0 ) {
+ $current{0} = 1;
+ }
+ else {
+ my $added = $object->RecordClassFromLookupType->new( RT->SystemUser );
+ $added->Load($item);
+ if ( $added->id ) {
+ $current{ $added->id } = 1;
+ }
+ }
}
}
+ else {
+ my $ocfs = RT::ObjectCustomFields->new(RT->SystemUser);
+ $ocfs->LimitToCustomField($object->id);
+
+ while ( my $ocf = $ocfs->Next ) {
+ if ( $ocf->ObjectId == 0 ) {
+ $current{0} = 1;
+ }
+ else {
+ $current{$ocf->ObjectId} = 1;
+ }
+ }
+ }
+
for my $item ( @{ $value || [] } ) {
if ( $item eq 0 ) {
commit 74f0e2387a71112ac83681e84c872d08e5f2c89b
Author: sunnavy <sunnavy at bestpractical.com>
Date: Fri Oct 1 17:52:58 2021 +0800
Do not keep track of ObjectScrips ids when calculating changes
This is like how we deleted ids of CustomFieldValues and
ObjectCustomFieldValues, which are allowed to be different.
diff --git a/sbin/rt-dump-initialdata.in b/sbin/rt-dump-initialdata.in
index 8e5064ed9b..98a30648b2 100644
--- a/sbin/rt-dump-initialdata.in
+++ b/sbin/rt-dump-initialdata.in
@@ -285,6 +285,10 @@ sub find_differences {
if ( $record->{Topics} ) {
delete $_->{id} for @{$record->{Topics}};
}
+
+ if ( $type eq 'Scrips' && $record->{Queue} ) {
+ delete $_->{id} for @{$record->{Queue}};
+ }
}
my @changes;
commit 629ca7518ed7cc7f1b42522dd0495237388f5a0e
Author: sunnavy <sunnavy at bestpractical.com>
Date: Tue Sep 21 21:55:32 2021 +0800
ACL in initialdata is applied globally by default
When ObjectType/ObjectId are absent in ACL records, it means global.
This is to get rid of errors from RT::ACE::_ParseObjectArg:
Method called with wrong args
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index b51058233b..4be4295d89 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -2769,6 +2769,8 @@ sub _LoadObject {
$object->LoadByValues(
PrincipalId => $principal_id,
PrincipalType => $principal_type,
+ ObjectType => 'RT::System',
+ ObjectId => RT->System->Id,
map { $_ => $values->{_Original}{$_} } grep { $values->{_Original}{$_} } qw/ObjectType ObjectId RightName/,
);
}
commit 9fd1a70caf14fc3f6ddc4e955fdcc47a56210301
Author: sunnavy <sunnavy at bestpractical.com>
Date: Tue Sep 21 21:47:18 2021 +0800
Handle system internal and role groups for ACL updates in initialdata
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index 709c4df143..b51058233b 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -2724,6 +2724,43 @@ sub _LoadObject {
return;
}
}
+ elsif ( $values->{_Original}{GroupType} ) {
+
+ my $group = RT::Group->new(RT->SystemUser);
+ if ( $values->{_Original}{'GroupDomain'} eq 'SystemInternal' ) {
+ $group->LoadSystemInternalGroup( $values->{_Original}{GroupType} );
+ }
+ elsif ( $values->{_Original}{'GroupDomain'} eq 'RT::System-Role' ) {
+ $group->LoadRoleGroup( Object => RT->System, Name => $values->{_Original}{GroupType} );
+ }
+ elsif ( $values->{_Original}{'GroupDomain'} =~ /-Role$/ ) {
+ my $object;
+ if ( $values->{_Original}{ObjectType} and $values->{_Original}{ObjectId} ) {
+ $object = $values->{_Original}{ObjectType}->new( RT->SystemUser );
+ my ( $ok, $msg ) = $object->Load( $values->{_Original}{ObjectId} );
+ unless ($ok) {
+ RT->Logger->error( "Unable to load "
+ . $values->{_Original}{ObjectType} . " "
+ . $values->{_Original}{ObjectId}
+ . ": $msg" );
+ return;
+ }
+ }
+ else {
+ $object = RT->System;
+ }
+ $group->LoadRoleGroup( Object => $object, Name => $values->{_Original}{GroupType} );
+ }
+
+ if ( $group->id ) {
+ $principal_id = $group->PrincipalId;
+ $principal_type = 'Group';
+ }
+ else {
+ RT->Logger->error("Couldn't load group $values->{_Original}{GroupType}");
+ return;
+ }
+ }
else {
RT->Logger->error( "Invalid principal type in $class" );
return;
commit c4ce6b83a55dae8a6cd9f7436c754de2891a27ab
Author: sunnavy <sunnavy at bestpractical.com>
Date: Tue Sep 21 21:44:26 2021 +0800
Fix typo, this block is to check GroupId
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index f557832669..709c4df143 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -2720,7 +2720,7 @@ sub _LoadObject {
$principal_type = 'Group';
}
else {
- RT->Logger->error( "Couldn't load group $values->{_Original}{UserId}" );
+ RT->Logger->error( "Couldn't load group $values->{_Original}{GroupId}" );
return;
}
}
-----------------------------------------------------------------------
hooks/post-receive
--
rt
More information about the rt-commit
mailing list