import of rt 3.0.4
[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     return ( $self->LoadByCols( Name => $args{'Name'}, Queue => {'Queue'} ) );
210
211 }
212
213 # }}}
214
215 # {{{ sub Create
216
217 =head2 Create
218
219 Takes a paramhash of Content, Queue, Name and Description.
220 Name should be a unique string identifying this Template.
221 Description and Content should be the template's title and content.
222 Queue should be 0 for a global template and the queue # for a queue-specific 
223 template.
224
225 Returns the Template's id # if the create was successful. Returns undef for
226 unknown database failure.
227
228
229 =cut
230
231 sub Create {
232     my $self = shift;
233     my %args = (
234         Content     => undef,
235         Queue       => 0,
236         Description => '[no description]',
237         Type => 'Action',    #By default, template are 'Action' templates
238         Name => undef,
239         @_
240     );
241
242     if ( !$args{'Queue'}  ) {
243         unless ( $self->CurrentUser->HasRight(Right =>'ModifyTemplate', Object => $RT::System) ) {
244             return (undef);
245         }
246         $args{'Queue'} = 0;
247     }
248     else {
249         my $QueueObj = new RT::Queue( $self->CurrentUser );
250         $QueueObj->Load( $args{'Queue'} ) || return ( 0, $self->loc('Invalid queue') );
251     
252         unless ( $QueueObj->CurrentUserHasRight('ModifyTemplate') ) {
253             return (undef);
254         }
255         $args{'Queue'} = $QueueObj->Id;
256     }
257
258     my $result = $self->SUPER::Create(
259         Content => $args{'Content'},
260         Queue   =>  $args{'Queue'},
261         Description => $args{'Description'},
262         Name        => $args{'Name'}
263     );
264
265     return ($result);
266
267 }
268
269 # }}}
270
271 # {{{ sub Delete
272
273 =head2 Delete
274
275 Delete this template.
276
277 =cut
278
279 sub Delete {
280     my $self = shift;
281
282     unless ( $self->CurrentUserHasQueueRight('ModifyTemplate') ) {
283         return ( 0, $self->loc('Permission Denied') );
284     }
285
286     return ( $self->SUPER::Delete(@_) );
287 }
288
289 # }}}
290
291 # {{{ sub MIMEObj
292 sub MIMEObj {
293     my $self = shift;
294     return ( $self->{'MIMEObj'} );
295 }
296
297 # }}}
298
299 # {{{ sub Parse 
300
301 =item Parse
302
303  This routine performs Text::Template parsing on the template and then
304  imports the results into a MIME::Entity so we can really use it
305  It returns a tuple of (val, message)
306  If val is 0, the message contains an error message
307
308 =cut
309
310 sub Parse {
311     my $self = shift;
312
313     #We're passing in whatever we were passed. it's destined for _ParseContent
314     my $content = $self->_ParseContent(@_);
315
316     #Lets build our mime Entity
317
318     my $parser = MIME::Parser->new();
319
320     # Setup output directory for files. from RT::EmailParser::_SetupMIMEParser
321     if (my $AttachmentDir = eval { File::Temp::tempdir( TMPDIR => 1, CLEANUP => 1 ) }) {
322         # Set up output directory for files:
323         $parser->output_dir("$AttachmentDir");
324     }
325     else {
326         # On some situations TMPDIR is non-writable. sad but true.
327         $parser->output_to_core(1);
328         $parser->tmp_to_core(1);
329     }
330     #If someone includes a message, don't extract it
331     $parser->extract_nested_messages(1);
332     # Set up the prefix for files with auto-generated names:
333     $parser->output_prefix("part");
334     # If content length is <= 50000 bytes, store each msg as in-core scalar;
335     # Else, write to a disk file (the default action):
336     $parser->output_to_core(50000);
337
338
339     ### Should we forgive normally-fatal errors?
340     $parser->ignore_errors(1);
341     $self->{'MIMEObj'} = eval { $parser->parse_data($content) };
342     my $error = ( $@ || $parser->last_error );
343
344     if ($error) {
345         $RT::Logger->error("$error");
346         return ( 0, $error );
347     }
348
349     # Unfold all headers
350     $self->{'MIMEObj'}->head->unfold();
351
352     return ( 1, $self->loc("Template parsed") );
353    
354
355 }
356
357 # }}}
358
359 # {{{ sub _ParseContent
360
361 # Perform Template substitutions on the template
362
363 sub _ParseContent {
364     my $self = shift;
365     my %args = (
366         Argument       => undef,
367         TicketObj      => undef,
368         TransactionObj => undef,
369         @_
370     );
371
372
373     $T::Ticket      = $args{'TicketObj'};
374     $T::Transaction = $args{'TransactionObj'};
375     $T::Argument    = $args{'Argument'};
376     $T::Requestor   = eval { $T::Ticket->Requestors->UserMembersObj->First->Name };
377     $T::rtname      = $RT::rtname;
378
379     # We need to untaint the content of the template, since we'll be working
380     # with it
381     my $content = $self->Content();
382     $content =~ s/^(.*)$/$1/;
383     my $template = Text::Template->new(
384         TYPE   => 'STRING',
385         SOURCE => $content
386     );
387
388     my $retval = $template->fill_in( PACKAGE => 'T' );
389
390     # MIME::Parser has problems dealing with high-bit utf8 data.
391     Encode::_utf8_off($retval);
392     return ($retval);
393 }
394
395 # }}}
396
397 # {{{ sub CurrentUserHasQueueRight
398
399 =head2 CurrentUserHasQueueRight
400
401 Helper function to call the template's queue's CurrentUserHasQueueRight with the passed in args.
402
403 =cut
404
405 sub CurrentUserHasQueueRight {
406     my $self = shift;
407     return ( $self->QueueObj->CurrentUserHasRight(@_) );
408 }
409
410 # }}}
411 1;