import rt 3.8.7
[freeside.git] / rt / t / ticket / linking.t
1
2 use strict;
3 use warnings;
4
5 use RT::Test tests => '101';
6 use_ok('RT');
7 use_ok('RT::Ticket');
8 use_ok('RT::ScripConditions');
9 use_ok('RT::ScripActions');
10 use_ok('RT::Template');
11 use_ok('RT::Scrips');
12 use_ok('RT::Scrip');
13
14
15 use File::Temp qw/tempfile/;
16 my ($fh, $filename) = tempfile( UNLINK => 1, SUFFIX => '.rt');
17 my $link_scrips_orig = RT->Config->Get( 'LinkTransactionsRun1Scrip' );
18 RT->Config->Set( 'LinkTransactionsRun1Scrip', 1 );
19
20 my $link_acl_checks_orig = RT->Config->Get( 'StrictLinkACL' );
21 RT->Config->Set( 'StrictLinkACL', 1);
22
23 my $condition = RT::ScripCondition->new( $RT::SystemUser );
24 $condition->Load('User Defined');
25 ok($condition->id);
26 my $action = RT::ScripAction->new( $RT::SystemUser );
27 $action->Load('User Defined');
28 ok($action->id);
29 my $template = RT::Template->new( $RT::SystemUser );
30 $template->Load('Blank');
31 ok($template->id);
32
33 my $q1 = RT::Queue->new($RT::SystemUser);
34 my ($id,$msg) = $q1->Create(Name => "LinkTest1.$$");
35 ok ($id,$msg);
36 my $q2 = RT::Queue->new($RT::SystemUser);
37 ($id,$msg) = $q2->Create(Name => "LinkTest2.$$");
38 ok ($id,$msg);
39
40 my $commit_code = <<END;
41 open my \$file, "<$filename" or die "couldn't open $filename";
42 my \$data = <\$file>;
43 chomp \$data;
44 \$data += 0;
45 close \$file;
46 \$RT::Logger->debug("Data is \$data");
47
48 open \$file, ">$filename" or die "couldn't open $filename";
49 if (\$self->TransactionObj->Type eq 'AddLink') {
50     \$RT::Logger->debug("AddLink");
51     print \$file \$data+1, "\n";
52 }
53 elsif (\$self->TransactionObj->Type eq 'DeleteLink') {
54     \$RT::Logger->debug("DeleteLink");
55     print \$file \$data-1, "\n";
56 }
57 else {
58     \$RT::Logger->error("THIS SHOULDN'T HAPPEN");
59     print \$file "666\n";
60 }
61 close \$file;
62 1;
63 END
64
65 my $Scrips = RT::Scrips->new( $RT::SystemUser );
66 $Scrips->UnLimit;
67 while ( my $Scrip = $Scrips->Next ) {
68     $Scrip->Delete if $Scrip->Description and $Scrip->Description =~ /Add or Delete Link \d+/;
69 }
70
71
72 my $scrip = RT::Scrip->new($RT::SystemUser);
73 ($id,$msg) = $scrip->Create( Description => "Add or Delete Link $$",
74                           ScripCondition => $condition->id,
75                           ScripAction    => $action->id,
76                           Template       => $template->id,
77                           Stage          => 'TransactionCreate',
78                           Queue          => 0,
79                   CustomIsApplicableCode => '$self->TransactionObj->Type =~ /(Add|Delete)Link/;',
80                        CustomPrepareCode => '1;',
81                        CustomCommitCode  => $commit_code,
82                            );
83 ok($id, "Scrip created");
84
85 my $u1 = RT::User->new($RT::SystemUser);
86 ($id,$msg) = $u1->Create(Name => "LinkTestUser.$$");
87 ok ($id,$msg);
88
89 # grant ShowTicket right to allow count transactions
90 ($id,$msg) = $u1->PrincipalObj->GrantRight ( Object => $q1, Right => 'ShowTicket');
91 ok ($id,$msg);
92 ($id,$msg) = $u1->PrincipalObj->GrantRight ( Object => $q2, Right => 'ShowTicket');
93 ok ($id,$msg);
94 ($id,$msg) = $u1->PrincipalObj->GrantRight ( Object => $q1, Right => 'CreateTicket');
95 ok ($id,$msg);
96
97 my $creator = RT::CurrentUser->new($u1->id);
98
99 diag('Create tickets without rights to link') if $ENV{'TEST_VERBOSE'};
100 {
101     # on q2 we have no rights, yet
102     my $parent = RT::Ticket->new( $RT::SystemUser );
103     my ($id,$tid,$msg) = $parent->Create( Subject => 'Link test 1', Queue => $q2->id );
104     ok($id,$msg);
105     my $child = RT::Ticket->new( $creator );
106     ($id,$tid,$msg) = $child->Create( Subject => 'Link test 1', Queue => $q1->id, MemberOf => $parent->id );
107     ok($id,$msg);
108     $child->CurrentUser( $RT::SystemUser );
109     is($child->_Links('Base')->Count, 0, 'link was not created, no permissions');
110     is($child->_Links('Target')->Count, 0, 'link was not create, no permissions');
111 }
112
113 diag('Create tickets with rights checks on one end of a link') if $ENV{'TEST_VERBOSE'};
114 {
115     # on q2 we have no rights, but use checking one only on thing
116     RT->Config->Set( StrictLinkACL => 0 );
117     my $parent = RT::Ticket->new( $RT::SystemUser );
118     my ($id,$tid,$msg) = $parent->Create( Subject => 'Link test 1', Queue => $q2->id );
119     ok($id,$msg);
120     my $child = RT::Ticket->new( $creator );
121     ($id,$tid,$msg) = $child->Create( Subject => 'Link test 1', Queue => $q1->id, MemberOf => $parent->id );
122     ok($id,$msg);
123     $child->CurrentUser( $RT::SystemUser );
124     is($child->_Links('Base')->Count, 1, 'link was created');
125     is($child->_Links('Target')->Count, 0, 'link was created only one');
126     # no scrip run on second ticket accroding to config option
127     is(link_count($filename), undef, "scrips ok");
128     RT->Config->Set( StrictLinkACL => 1 );
129 }
130
131 ($id,$msg) = $u1->PrincipalObj->GrantRight ( Object => $q1, Right => 'ModifyTicket');
132 ok ($id,$msg);
133
134 diag('try to add link without rights') if $ENV{'TEST_VERBOSE'};
135 {
136     # on q2 we have no rights, yet
137     my $parent = RT::Ticket->new( $RT::SystemUser );
138     my ($id,$tid,$msg) = $parent->Create( Subject => 'Link test 1', Queue => $q2->id );
139     ok($id,$msg);
140     my $child = RT::Ticket->new( $creator );
141     ($id,$tid,$msg) = $child->Create( Subject => 'Link test 1', Queue => $q1->id );
142     ok($id,$msg);
143     ($id, $msg) = $child->AddLink(Type => 'MemberOf', Target => $parent->id);
144     ok(!$id, $msg);
145     is(link_count($filename), undef, "scrips ok");
146     $child->CurrentUser( $RT::SystemUser );
147     is($child->_Links('Base')->Count, 0, 'link was not created, no permissions');
148     is($child->_Links('Target')->Count, 0, 'link was not create, no permissions');
149 }
150
151 diag('add link with rights only on base') if $ENV{'TEST_VERBOSE'};
152 {
153     # on q2 we have no rights, but use checking one only on thing
154     RT->Config->Set( StrictLinkACL => 0 );
155     my $parent = RT::Ticket->new( $RT::SystemUser );
156     my ($id,$tid,$msg) = $parent->Create( Subject => 'Link test 1', Queue => $q2->id );
157     ok($id,$msg);
158     my $child = RT::Ticket->new( $creator );
159     ($id,$tid,$msg) = $child->Create( Subject => 'Link test 1', Queue => $q1->id );
160     ok($id,$msg);
161     ($id, $msg) = $child->AddLink(Type => 'MemberOf', Target => $parent->id);
162     ok($id, $msg);
163     is(link_count($filename), 1, "scrips ok");
164     $child->CurrentUser( $RT::SystemUser );
165     is($child->_Links('Base')->Count, 1, 'link was created');
166     is($child->_Links('Target')->Count, 0, 'link was created only one');
167     $child->CurrentUser( $creator );
168
169     # turn off feature and try to delete link, we should fail
170     RT->Config->Set( StrictLinkACL => 1 );
171     ($id, $msg) = $child->AddLink(Type => 'MemberOf', Target => $parent->id);
172     ok(!$id, $msg);
173     is(link_count($filename), 1, "scrips ok");
174     $child->CurrentUser( $RT::SystemUser );
175     $child->_Links('Base')->_DoCount;
176     is($child->_Links('Base')->Count, 1, 'link was not deleted');
177     $child->CurrentUser( $creator );
178
179     # try to delete link, we should success as feature is active
180     RT->Config->Set( StrictLinkACL => 0 );
181     ($id, $msg) = $child->DeleteLink(Type => 'MemberOf', Target => $parent->id);
182     ok($id, $msg);
183     is(link_count($filename), 0, "scrips ok");
184     $child->CurrentUser( $RT::SystemUser );
185     $child->_Links('Base')->_DoCount;
186     is($child->_Links('Base')->Count, 0, 'link was deleted');
187     RT->Config->Set( StrictLinkACL => 1 );
188 }
189
190 my $tid;
191 my $ticket = RT::Ticket->new( $creator);
192 ok($ticket->isa('RT::Ticket'));
193 ($id,$tid, $msg) = $ticket->Create(Subject => 'Link test 1', Queue => $q1->id);
194 ok ($id,$msg);
195
196 diag('try link to itself') if $ENV{'TEST_VERBOSE'};
197 {
198     my ($id, $msg) = $ticket->AddLink(Type => 'RefersTo', Target => $ticket->id);
199     ok(!$id, $msg);
200     is(link_count($filename), 0, "scrips ok");
201 }
202
203 my $ticket2 = RT::Ticket->new($RT::SystemUser);
204 ($id, $tid, $msg) = $ticket2->Create(Subject => 'Link test 2', Queue => $q2->id);
205 ok ($id, $msg);
206 ($id,$msg) =$ticket->AddLink(Type => 'RefersTo', Target => $ticket2->id);
207 ok(!$id,$msg);
208 is(link_count($filename), 0, "scrips ok");
209
210 ($id,$msg) = $u1->PrincipalObj->GrantRight ( Object => $q2, Right => 'CreateTicket');
211 ok ($id,$msg);
212 ($id,$msg) = $u1->PrincipalObj->GrantRight ( Object => $q2, Right => 'ModifyTicket');
213 ok ($id,$msg);
214 ($id,$msg) = $ticket->AddLink(Type => 'RefersTo', Target => $ticket2->id);
215 ok($id,$msg);
216 is(link_count($filename), 1, "scrips ok");
217 ($id,$msg) = $ticket->AddLink(Type => 'RefersTo', Target => -1);
218 ok(!$id,$msg);
219 ($id,$msg) = $ticket->AddLink(Type => 'RefersTo', Target => $ticket2->id);
220 ok($id,$msg);
221 is(link_count($filename), 1, "scrips ok");
222
223 my $transactions = $ticket2->Transactions;
224 $transactions->Limit( FIELD => 'Type', VALUE => 'AddLink' );
225 is( $transactions->Count, 1, "Transaction found in other ticket" );
226 is( $transactions->First->Field , 'ReferredToBy');
227 is( $transactions->First->NewValue , $ticket->URI );
228
229 ($id,$msg) = $ticket->DeleteLink(Type => 'RefersTo', Target => $ticket2->id);
230 ok($id,$msg);
231 is(link_count($filename), 0, "scrips ok");
232 $transactions = $ticket2->Transactions;
233 $transactions->Limit( FIELD => 'Type', VALUE => 'DeleteLink' );
234 is( $transactions->Count, 1, "Transaction found in other ticket" );
235 is( $transactions->First->Field , 'ReferredToBy');
236 is( $transactions->First->OldValue , $ticket->URI );
237
238 RT->Config->Set( LinkTransactionsRun1Scrip => 0 );
239
240 ($id,$msg) =$ticket->AddLink(Type => 'RefersTo', Target => $ticket2->id);
241 ok($id,$msg);
242 is(link_count($filename), 2, "scrips ok");
243 ($id,$msg) =$ticket->DeleteLink(Type => 'RefersTo', Target => $ticket2->id);
244 ok($id,$msg);
245 is(link_count($filename), 0, "scrips ok");
246
247 # tests for silent behaviour
248 ($id,$msg) = $ticket->AddLink(Type => 'RefersTo', Target => $ticket2->id, Silent => 1);
249 ok($id,$msg);
250 is(link_count($filename), 0, "scrips ok");
251 {
252     my $transactions = $ticket->Transactions;
253     $transactions->Limit( FIELD => 'Type', VALUE => 'AddLink' );
254     is( $transactions->Count, 2, "Still two txns on the base" );
255
256     $transactions = $ticket2->Transactions;
257     $transactions->Limit( FIELD => 'Type', VALUE => 'AddLink' );
258     is( $transactions->Count, 2, "Still two txns on the target" );
259
260 }
261 ($id,$msg) =$ticket->DeleteLink(Type => 'RefersTo', Target => $ticket2->id, Silent => 1);
262 ok($id,$msg);
263 is(link_count($filename), 0, "scrips ok");
264
265 ($id,$msg) = $ticket->AddLink(Type => 'RefersTo', Target => $ticket2->id, SilentBase => 1);
266 ok($id,$msg);
267 is(link_count($filename), 1, "scrips ok");
268 {
269     my $transactions = $ticket->Transactions;
270     $transactions->Limit( FIELD => 'Type', VALUE => 'AddLink' );
271     is( $transactions->Count, 2, "still five txn on the base" );
272
273     $transactions = $ticket2->Transactions;
274     $transactions->Limit( FIELD => 'Type', VALUE => 'AddLink' );
275     is( $transactions->Count, 3, "+1 txn on the target" );
276
277 }
278 ($id,$msg) =$ticket->DeleteLink(Type => 'RefersTo', Target => $ticket2->id, SilentBase => 1);
279 ok($id,$msg);
280 is(link_count($filename), 0, "scrips ok");
281
282 ($id,$msg) = $ticket->AddLink(Type => 'RefersTo', Target => $ticket2->id, SilentTarget => 1);
283 ok($id,$msg);
284 is(link_count($filename), 1, "scrips ok");
285 {
286     my $transactions = $ticket->Transactions;
287     $transactions->Limit( FIELD => 'Type', VALUE => 'AddLink' );
288     is( $transactions->Count, 3, "+1 txn on the base" );
289
290     $transactions = $ticket2->Transactions;
291     $transactions->Limit( FIELD => 'Type', VALUE => 'AddLink' );
292     is( $transactions->Count, 3, "three txns on the target" );
293 }
294 ($id,$msg) =$ticket->DeleteLink(Type => 'RefersTo', Target => $ticket2->id, SilentTarget => 1);
295 ok($id,$msg);
296 is(link_count($filename), 0, "scrips ok");
297
298
299 # restore
300 RT->Config->Set( LinkTransactionsRun1Scrip => $link_scrips_orig );
301 RT->Config->Set( StrictLinkACL => $link_acl_checks_orig );
302
303 {
304     my $Scrips = RT::Scrips->new( $RT::SystemUser );
305     $Scrips->Limit( FIELD => 'Description', OPERATOR => 'STARTSWITH', VALUE => 'Add or Delete Link ');
306     while ( my $s = $Scrips->Next ) { $s->Delete };
307 }
308
309
310 my $link = RT::Link->new( $RT::SystemUser );
311 ($id,$msg) = $link->Create( Base => $ticket->URI, Target => $ticket2->URI, Type => 'MyLinkType' );
312 ok($id, $msg);
313 ok($link->LocalBase   == $ticket->id,  "LocalBase   set correctly");
314 ok($link->LocalTarget == $ticket2->id, "LocalTarget set correctly");
315
316 {
317     no warnings 'once';
318     *RT::NotTicket::Id = sub { return $$ };
319     *RT::NotTicket::id = \&RT::NotTicket::Id;
320 }
321
322 {
323     package RT::URI::not_ticket;
324     use RT::URI::base;
325     use vars qw(@ISA);
326     @ISA = qw/RT::URI::base/;
327     sub IsLocal { 1; }
328     sub Object { return bless {}, 'RT::NotTicket'; }
329 }
330
331 my $orig_getresolver = \&RT::URI::_GetResolver;
332 {
333     no warnings 'redefine';
334     *RT::URI::_GetResolver = sub {
335         my $self = shift;
336         my $scheme = shift;
337
338         $scheme =~ s/(\.|-)/_/g;
339         my $resolver;
340         my $module = "RT::URI::$scheme";
341         $resolver = $module->new($self->CurrentUser);
342
343        if ($resolver) {
344            $self->{'resolver'} = $resolver;
345         } else {
346             $self->{'resolver'} = RT::URI::base->new($self->CurrentUser);
347         }
348     };
349 }
350
351 ($id,$msg) = $link->Create( Base => "not_ticket::$RT::Organization/notticket/$$", Target => $ticket2->URI, Type => 'MyLinkType' );
352 ok($id, $msg);
353 ok($link->LocalBase   == 0,            "LocalBase set correctly");
354 ok($link->LocalTarget == $ticket2->id, "LocalTarget set correctly");
355
356 ($id,$msg) = $link->Create( Target => "not_ticket::$RT::Organization/notticket/$$", Base => $ticket->URI, Type => 'MyLinkType' );
357 ok($id, $msg);
358 ok($link->LocalTarget == 0,           "LocalTarget set correctly");
359 ok($link->LocalBase   == $ticket->id, "LocalBase set correctly");
360
361 ($id,$msg) = $link->Create(
362                        Target => "not_ticket::$RT::Organization/notticket/1$$",
363                        Base   => "not_ticket::$RT::Organization/notticket/$$",
364                        Type => 'MyLinkType' );
365
366 ok($id, $msg);
367 ok($link->LocalTarget == 0, "LocalTarget set correctly");
368 ok($link->LocalBase   == 0, "LocalBase set correctly");
369
370 # restore _GetResolver
371 {
372     no warnings 'redefine';
373     *RT::URI::_GetResolver = $orig_getresolver;
374 }
375
376 sub link_count {
377     my $file = shift;
378     open my $fh, "<$file" or die "couldn't open $file";
379     my $data = <$fh>;
380     close $fh;
381
382     return undef unless $data;
383     chomp $data;
384     return $data + 0;
385 }