import of rt 3.0.9
[freeside.git] / rt / lib / RT / Template_Overlay.pm
1 # BEGIN LICENSE BLOCK
2
3 # Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
4
5 # (Except where explictly superceded by other copyright notices)
6
7 # This work is made available to you under the terms of Version 2 of
8 # the GNU General Public License. A copy of that license should have
9 # been provided with this software, but in any event can be snarfed
10 # from www.gnu.org.
11
12 # This work is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # General Public License for more details.
16
17 # Unless otherwise specified, all modifications, corrections or
18 # extensions to this work which alter its source code become the
19 # property of Best Practical Solutions, LLC when submitted for
20 # inclusion in the work.
21
22
23 # END LICENSE BLOCK
24 # Portions Copyright 2000 Tobias Brox <tobix@cpan.org> 
25
26 =head1 NAME
27
28   RT::Template - RT's template object
29
30 =head1 SYNOPSIS
31
32   use RT::Template;
33
34 =head1 DESCRIPTION
35
36
37 =head1 METHODS
38
39 =begin testing
40
41 ok(require RT::Template);
42
43 =end testing
44
45 =cut
46
47 use strict;
48 no warnings qw(redefine);
49
50 use Text::Template;
51 use MIME::Entity;
52 use MIME::Parser;
53 use File::Temp qw /tempdir/;
54
55
56 # {{{ sub _Accessible 
57
58 sub _Accessible {
59     my $self = shift;
60     my %Cols = (
61         id            => 'read',
62         Name          => 'read/write',
63         Description   => 'read/write',
64         Type          => 'read/write',    #Type is one of Action or Message
65         Content       => 'read/write',
66         Queue         => 'read/write',
67         Creator       => 'read/auto',
68         Created       => 'read/auto',
69         LastUpdatedBy => 'read/auto',
70         LastUpdated   => 'read/auto'
71     );
72     return $self->SUPER::_Accessible( @_, %Cols );
73 }
74
75 # }}}
76
77 # {{{ sub _Set
78
79 sub _Set {
80     my $self = shift;
81
82     # use super::value or we get acl blocked
83     if ( ( defined $self->SUPER::_Value('Queue') )
84         && ( $self->SUPER::_Value('Queue') == 0 ) )
85     {
86         unless ( $self->CurrentUser->HasRight( Object => $RT::System, Right => 'ModifyTemplate') ) {
87             return ( 0, $self->loc('Permission Denied') );
88         }
89     }
90     else {
91
92         unless ( $self->CurrentUserHasQueueRight('ModifyTemplate') ) {
93             return ( 0, $self->loc('Permission Denied') );
94         }
95     }
96     return ( $self->SUPER::_Set(@_) );
97
98 }
99
100 # }}}
101
102 # {{{ sub _Value 
103
104 =head2 _Value
105
106 Takes the name of a table column.
107 Returns its value as a string, if the user passes an ACL check
108
109
110 =begin testing
111
112 my $t = RT::Template->new($RT::SystemUser);
113 $t->Create(Name => "Foo", Queue => 1);
114 my $t2 = RT::Template->new($RT::Nobody);
115 $t2->Load($t->Id);
116 ok($t2->QueueObj->id, "Got the template's queue objet");
117
118 =end testing
119
120
121
122 =cut
123
124 sub _Value {
125
126     my $self  = shift;
127     my $field = shift;
128
129    
130     #If the current user doesn't have ACLs, don't let em at it.  
131     #use super::value or we get acl blocked
132     if ( ( !defined $self->__Value('Queue') )
133         || ( $self->__Value('Queue') == 0 ) )
134     {
135         unless ( $self->CurrentUser->HasRight( Object => $RT::System, Right => 'ShowTemplate') ) {
136             return (undef);
137         }
138     }
139     else {
140         unless ( $self->CurrentUserHasQueueRight('ShowTemplate') ) {
141             return (undef);
142         }
143     }
144     return ( $self->__Value($field) );
145
146 }
147
148 # }}}
149
150 # {{{ sub Load
151
152 =head2 Load <identifer>
153
154 Load a template, either by number or by name
155
156 =cut
157
158 sub Load {
159     my $self       = shift;
160     my $identifier = shift;
161
162     if ( !$identifier ) {
163         return (undef);
164     }
165
166     if ( $identifier !~ /\D/ ) {
167         $self->SUPER::LoadById($identifier);
168     }
169     else {
170         $self->LoadByCol( 'Name', $identifier );
171
172     }
173 }
174
175 # }}}
176
177 # {{{ sub LoadGlobalTemplate
178
179 =head2 LoadGlobalTemplate NAME
180
181 Load the global tempalte with the name NAME
182
183 =cut
184
185 sub LoadGlobalTemplate {
186     my $self = shift;
187     my $id   = shift;
188
189     return ( $self->LoadQueueTemplate( Queue => 0, Name => $id ) );
190 }
191
192 # }}}
193
194 # {{{ sub LoadQueueTemplate
195
196 =head2  LoadQueueTemplate (Queue => QUEUEID, Name => NAME)
197
198 Loads the Queue template named NAME for Queue QUEUE.
199
200 =cut
201
202 sub LoadQueueTemplate {
203     my $self = shift;
204     my %args = (
205         Queue => undef,
206         Name  => undef,
207         @_
208     );
209
210     return ( $self->LoadByCols( Name => $args{'Name'}, Queue => $args{'Queue'} ) );
211
212 }
213
214 # }}}
215
216 # {{{ sub Create
217
218 =head2 Create
219
220 Takes a paramhash of Content, Queue, Name and Description.
221 Name should be a unique string identifying this Template.
222 Description and Content should be the template's title and content.
223 Queue should be 0 for a global template and the queue # for a queue-specific 
224 template.
225
226 Returns the Template's id # if the create was successful. Returns undef for
227 unknown database failure.
228
229
230 =cut
231
232 sub Create {
233     my $self = shift;
234     my %args = (
235         Content     => undef,
236         Queue       => 0,
237         Description => '[no description]',
238         Type => 'Action',    #By default, template are 'Action' templates
239         Name => undef,
240         @_
241     );
242
243     if ( !$args{'Queue'}  ) {
244         unless ( $self->CurrentUser->HasRight(Right =>'ModifyTemplate', Object => $RT::System) ) {
245             return (undef);
246         }
247         $args{'Queue'} = 0;
248     }
249     else {
250         my $QueueObj = new RT::Queue( $self->CurrentUser );
251         $QueueObj->Load( $args{'Queue'} ) || return ( 0, $self->loc('Invalid queue') );
252     
253         unless ( $QueueObj->CurrentUserHasRight('ModifyTemplate') ) {
254             return (undef);
255         }
256         $args{'Queue'} = $QueueObj->Id;
257     }
258
259     my $result = $self->SUPER::Create(
260         Content => $args{'Content'},
261         Queue   =>  $args{'Queue'},
262         Description => $args{'Description'},
263         Name        => $args{'Name'}
264     );
265
266     return ($result);
267
268 }
269
270 # }}}
271
272 # {{{ sub Delete
273
274 =head2 Delete
275
276 Delete this template.
277
278 =cut
279
280 sub Delete {
281     my $self = shift;
282
283     unless ( $self->CurrentUserHasQueueRight('ModifyTemplate') ) {
284         return ( 0, $self->loc('Permission Denied') );
285     }
286
287     return ( $self->SUPER::Delete(@_) );
288 }
289
290 # }}}
291
292 # {{{ sub MIMEObj
293 sub MIMEObj {
294     my $self = shift;
295     return ( $self->{'MIMEObj'} );
296 }
297
298 # }}}
299
300 # {{{ sub Parse 
301
302 =item Parse
303
304  This routine performs Text::Template parsing on the template and then
305  imports the results into a MIME::Entity so we can really use it
306  It returns a tuple of (val, message)
307  If val is 0, the message contains an error message
308
309 =cut
310
311 sub Parse {
312     my $self = shift;
313
314     #We're passing in whatever we were passed. it's destined for _ParseContent
315     my $content = $self->_ParseContent(@_);
316
317     #Lets build our mime Entity
318
319     my $parser = MIME::Parser->new();
320
321     # Setup output directory for files. from RT::EmailParser::_SetupMIMEParser
322     if ( my $AttachmentDir =
323         eval { File::Temp::tempdir( TMPDIR => 1, CLEANUP => 1 ) } )
324     {
325
326         # Set up output directory for files:
327         $parser->output_dir("$AttachmentDir");
328     }
329     else {
330         $RT::Logger->error("Couldn't write attachments to temp dir on disk. using more memory and processor.");
331         # On some situations TMPDIR is non-writable. sad but true.
332         $parser->output_to_core(1);
333         $parser->tmp_to_core(1);
334     }
335
336     #If someone includes a message, don't extract it
337     $parser->extract_nested_messages(1);
338
339     # Set up the prefix for files with auto-generated names:
340     $parser->output_prefix("part");
341
342     # If content length is <= 50000 bytes, store each msg as in-core scalar;
343     # Else, write to a disk file (the default action):
344     $parser->output_to_core(50000);
345
346     ### Should we forgive normally-fatal errors?
347     $parser->ignore_errors(1);
348     $self->{'MIMEObj'} = eval { $parser->parse_data($content) };
349     my $error = ( $@ || $parser->last_error );
350
351     if ($error) {
352         $RT::Logger->error("$error");
353         return ( 0, $error );
354     }
355
356     # Unfold all headers
357     $self->{'MIMEObj'}->head->unfold();
358
359     return ( 1, $self->loc("Template parsed") );
360
361 }
362
363 # }}}
364
365 # {{{ sub _ParseContent
366
367 # Perform Template substitutions on the template
368
369 sub _ParseContent {
370     my $self = shift;
371     my %args = (
372         Argument       => undef,
373         TicketObj      => undef,
374         TransactionObj => undef,
375         @_
376     );
377
378     no warnings 'redefine';
379     $T::Ticket      = $args{'TicketObj'};
380     $T::Transaction = $args{'TransactionObj'};
381     $T::Argument    = $args{'Argument'};
382     $T::Requestor   = eval { $T::Ticket->Requestors->UserMembersObj->First->Name };
383     $T::rtname      = $RT::rtname;
384     *T::loc         = sub { $T::Ticket->loc(@_) };
385
386     # We need to untaint the content of the template, since we'll be working
387     # with it
388     my $content = $self->Content();
389     $content =~ s/^(.*)$/$1/;
390     my $template = Text::Template->new(
391         TYPE   => 'STRING',
392         SOURCE => $content
393     );
394
395     my $retval = $template->fill_in( PACKAGE => 'T' );
396
397     # MIME::Parser has problems dealing with high-bit utf8 data.
398     Encode::_utf8_off($retval);
399     return ($retval);
400 }
401
402 # }}}
403
404 # {{{ sub CurrentUserHasQueueRight
405
406 =head2 CurrentUserHasQueueRight
407
408 Helper function to call the template's queue's CurrentUserHasQueueRight with the passed in args.
409
410 =cut
411
412 sub CurrentUserHasQueueRight {
413     my $self = shift;
414     return ( $self->QueueObj->CurrentUserHasRight(@_) );
415 }
416
417 # }}}
418 1;