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