Removed LDAP-lookup loop for new external users.
[usit-rt.git] / lib / RT / Template.pm
CommitLineData
84fb5b46
MKG
1# BEGIN BPS TAGGED BLOCK {{{
2#
3# COPYRIGHT:
4#
5# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
6# <sales@bestpractical.com>
7#
8# (Except where explicitly superseded by other copyright notices)
9#
10#
11# LICENSE:
12#
13# This work is made available to you under the terms of Version 2 of
14# the GNU General Public License. A copy of that license should have
15# been provided with this software, but in any event can be snarfed
16# from www.gnu.org.
17#
18# This work is distributed in the hope that it will be useful, but
19# WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21# General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License
24# along with this program; if not, write to the Free Software
25# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26# 02110-1301 or visit their web page on the internet at
27# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28#
29#
30# CONTRIBUTION SUBMISSION POLICY:
31#
32# (The following paragraph is not intended to limit the rights granted
33# to you to modify and distribute this software under the terms of
34# the GNU General Public License and is only of importance to you if
35# you choose to contribute your changes and enhancements to the
36# community by submitting them to Best Practical Solutions, LLC.)
37#
38# By intentionally submitting any modifications, corrections or
39# derivatives to this work, or any other work intended for use with
40# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41# you are the copyright holder for those contributions and you grant
42# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
43# royalty-free, perpetual, license to use, copy, create derivative
44# works based on those contributions, and sublicense and distribute
45# those contributions and any derivatives thereof.
46#
47# END BPS TAGGED BLOCK }}}
48
49# Portions Copyright 2000 Tobias Brox <tobix@cpan.org>
50
51=head1 NAME
52
53 RT::Template - RT's template object
54
55=head1 SYNOPSIS
56
57 use RT::Template;
58
59=head1 DESCRIPTION
60
61
62=head1 METHODS
63
64
65=cut
66
67
68package RT::Template;
69
70use strict;
71use warnings;
72
73
74
75use Text::Template;
76use MIME::Entity;
77use MIME::Parser;
78use Scalar::Util 'blessed';
79
80sub _Accessible {
81 my $self = shift;
82 my %Cols = (
83 id => 'read',
84 Name => 'read/write',
85 Description => 'read/write',
86 Type => 'read/write', #Type is one of Perl or Simple
87 Content => 'read/write',
88 Queue => 'read/write',
89 Creator => 'read/auto',
90 Created => 'read/auto',
91 LastUpdatedBy => 'read/auto',
92 LastUpdated => 'read/auto'
93 );
94 return $self->SUPER::_Accessible( @_, %Cols );
95}
96
97sub _Set {
98 my $self = shift;
99 my %args = (
100 Field => undef,
101 Value => undef,
102 @_,
103 );
104
105 unless ( $self->CurrentUserHasQueueRight('ModifyTemplate') ) {
106 return ( 0, $self->loc('Permission Denied') );
107 }
108
109 if (exists $args{Value}) {
110 if ($args{Field} eq 'Queue') {
111 if ($args{Value}) {
112 # moving to another queue
113 my $queue = RT::Queue->new( $self->CurrentUser );
114 $queue->Load($args{Value});
115 unless ($queue->Id and $queue->CurrentUserHasRight('ModifyTemplate')) {
116 return ( 0, $self->loc('Permission Denied') );
117 }
118 } else {
119 # moving to global
120 unless ($self->CurrentUser->HasRight( Object => RT->System, Right => 'ModifyTemplate' )) {
121 return ( 0, $self->loc('Permission Denied') );
122 }
123 }
124 }
125 }
126
127 return $self->SUPER::_Set( @_ );
128}
129
130=head2 _Value
131
132Takes the name of a table column. Returns its value as a string,
133if the user passes an ACL check, otherwise returns undef.
134
135=cut
136
137sub _Value {
138 my $self = shift;
139
140 unless ( $self->CurrentUserCanRead() ) {
141 return undef;
142 }
143 return $self->__Value( @_ );
144
145}
146
147=head2 Load <identifier>
148
149Load a template, either by number or by name.
150
151Note that loading templates by name using this method B<is
152ambiguous>. Several queues may have template with the same name
153and as well global template with the same name may exist.
154Use L</LoadGlobalTemplate> and/or L<LoadQueueTemplate> to get
155precise result.
156
157=cut
158
159sub Load {
160 my $self = shift;
161 my $identifier = shift;
162 return undef unless $identifier;
163
164 if ( $identifier =~ /\D/ ) {
165 return $self->LoadByCol( 'Name', $identifier );
166 }
167 return $self->LoadById( $identifier );
168}
169
170=head2 LoadGlobalTemplate NAME
171
172Load the global template with the name NAME
173
174=cut
175
176sub LoadGlobalTemplate {
177 my $self = shift;
178 my $name = shift;
179
180 return ( $self->LoadQueueTemplate( Queue => 0, Name => $name ) );
181}
182
183=head2 LoadQueueTemplate (Queue => QUEUEID, Name => NAME)
184
185Loads the Queue template named NAME for Queue QUEUE.
186
187Note that this method doesn't load a global template with the same name
188if template in the queue doesn't exist. THe following code can be used:
189
190 $template->LoadQueueTemplate( Queue => $queue_id, Name => $template_name );
191 unless ( $template->id ) {
192 $template->LoadGlobalTemplate( $template_name );
193 unless ( $template->id ) {
194 # no template
195 ...
196 }
197 }
198 # ok, template either queue's or global
199 ...
200
201=cut
202
203sub LoadQueueTemplate {
204 my $self = shift;
205 my %args = (
206 Queue => undef,
207 Name => undef,
208 @_
209 );
210
211 return ( $self->LoadByCols( Name => $args{'Name'}, Queue => $args{'Queue'} ) );
212
213}
214
215=head2 Create
216
217Takes a paramhash of Content, Queue, Name and Description.
218Name should be a unique string identifying this Template.
219Description and Content should be the template's title and content.
220Queue should be 0 for a global template and the queue # for a queue-specific
221template.
222
223Returns the Template's id # if the create was successful. Returns undef for
224unknown database failure.
225
226=cut
227
228sub Create {
229 my $self = shift;
230 my %args = (
231 Content => undef,
232 Queue => 0,
233 Description => '[no description]',
234 Type => 'Perl',
235 Name => undef,
236 @_
237 );
238
239 if ( $args{Type} eq 'Perl' && !$self->CurrentUser->HasRight(Right => 'ExecuteCode', Object => $RT::System) ) {
240 return ( undef, $self->loc('Permission Denied') );
241 }
242
243 unless ( $args{'Queue'} ) {
244 unless ( $self->CurrentUser->HasRight(Right =>'ModifyTemplate', Object => $RT::System) ) {
245 return ( undef, $self->loc('Permission Denied') );
246 }
247 $args{'Queue'} = 0;
248 }
249 else {
250 my $QueueObj = RT::Queue->new( $self->CurrentUser );
251 $QueueObj->Load( $args{'Queue'} ) || return ( undef, $self->loc('Invalid queue') );
252
253 unless ( $QueueObj->CurrentUserHasRight('ModifyTemplate') ) {
254 return ( undef, $self->loc('Permission Denied') );
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 Type => $args{'Type'},
265 );
266
267 return ($result);
268
269}
270
271=head2 Delete
272
273Delete this template.
274
275=cut
276
277sub Delete {
278 my $self = shift;
279
280 unless ( $self->CurrentUserHasQueueRight('ModifyTemplate') ) {
281 return ( 0, $self->loc('Permission Denied') );
282 }
283
284 return ( $self->SUPER::Delete(@_) );
285}
286
287=head2 IsEmpty
288
289Returns true value if content of the template is empty, otherwise
290returns false.
291
292=cut
293
294sub IsEmpty {
295 my $self = shift;
296 my $content = $self->Content;
297 return 0 if defined $content && length $content;
298 return 1;
299}
300
301=head2 MIMEObj
302
303Returns L<MIME::Entity> object parsed using L</Parse> method. Returns
304undef if last call to L</Parse> failed or never be called.
305
306Note that content of the template is UTF-8, but L<MIME::Parser> is not
307good at handling it and all data of the entity should be treated as
308octets and converted to perl strings using Encode::decode_utf8 or
309something else.
310
311=cut
312
313sub MIMEObj {
314 my $self = shift;
315 return ( $self->{'MIMEObj'} );
316}
317
318=head2 Parse
319
320This routine performs L<Text::Template> parsing on the template and then
321imports the results into a L<MIME::Entity> so we can really use it. Use
322L</MIMEObj> method to get the L<MIME::Entity> object.
323
324Takes a hash containing Argument, TicketObj, and TransactionObj and other
325arguments that will be available in the template's code. TicketObj and
326TransactionObj are not mandatory, but highly recommended.
327
328It returns a tuple of (val, message). If val is false, the message contains
329an error message.
330
331=cut
332
333sub Parse {
334 my $self = shift;
335 my ($rv, $msg);
336
337
338 if ($self->Content =~ m{^Content-Type:\s+text/html\b}im) {
339 local $RT::Transaction::PreferredContentType = 'text/html';
340 ($rv, $msg) = $self->_Parse(@_);
341 }
342 else {
343 ($rv, $msg) = $self->_Parse(@_);
344 }
345
346 return ($rv, $msg) unless $rv;
347
348 my $mime_type = $self->MIMEObj->mime_type;
349 if (defined $mime_type and $mime_type eq 'text/html') {
350 $self->_DowngradeFromHTML(@_);
351 }
352
353 return ($rv, $msg);
354}
355
356sub _Parse {
357 my $self = shift;
358
359 # clear prev MIME object
360 $self->{'MIMEObj'} = undef;
361
362 #We're passing in whatever we were passed. it's destined for _ParseContent
363 my ($content, $msg) = $self->_ParseContent(@_);
364 return ( 0, $msg ) unless defined $content && length $content;
365
366 if ( $content =~ /^\S/s && $content !~ /^\S+:/ ) {
367 $RT::Logger->error(
368 "Template #". $self->id ." has leading line that doesn't"
369 ." look like header field, if you don't want to override"
370 ." any headers and don't want to see this error message"
371 ." then leave first line of the template empty"
372 );
373 $content = "\n".$content;
374 }
375
376 my $parser = MIME::Parser->new();
377 $parser->output_to_core(1);
378 $parser->tmp_to_core(1);
379 $parser->use_inner_files(1);
380
381 ### Should we forgive normally-fatal errors?
382 $parser->ignore_errors(1);
383 # MIME::Parser doesn't play well with perl strings
384 utf8::encode($content);
385 $self->{'MIMEObj'} = eval { $parser->parse_data( \$content ) };
386 if ( my $error = $@ || $parser->last_error ) {
387 $RT::Logger->error( "$error" );
388 return ( 0, $error );
389 }
390
391 # Unfold all headers
392 $self->{'MIMEObj'}->head->unfold;
393
394 return ( 1, $self->loc("Template parsed") );
395
396}
397
398# Perform Template substitutions on the template
399
400sub _ParseContent {
401 my $self = shift;
402 my %args = (
403 Argument => undef,
404 TicketObj => undef,
405 TransactionObj => undef,
406 @_
407 );
408
409 unless ( $self->CurrentUserCanRead() ) {
410 return (undef, $self->loc("Permission Denied"));
411 }
412
413 if ( $self->IsEmpty ) {
414 return ( undef, $self->loc("Template is empty") );
415 }
416
417 my $content = $self->SUPER::_Value('Content');
418 # We need to untaint the content of the template, since we'll be working
419 # with it
420 $content =~ s/^(.*)$/$1/;
421
422 $args{'Ticket'} = delete $args{'TicketObj'} if $args{'TicketObj'};
423 $args{'Transaction'} = delete $args{'TransactionObj'} if $args{'TransactionObj'};
424 $args{'Requestor'} = eval { $args{'Ticket'}->Requestors->UserMembersObj->First->Name }
425 if $args{'Ticket'};
426 $args{'rtname'} = RT->Config->Get('rtname');
427 if ( $args{'Ticket'} ) {
428 my $t = $args{'Ticket'}; # avoid memory leak
429 $args{'loc'} = sub { $t->loc(@_) };
430 } else {
431 $args{'loc'} = sub { $self->loc(@_) };
432 }
433
434 if ($self->Type eq 'Perl') {
435 return $self->_ParseContentPerl(
436 Content => $content,
437 TemplateArgs => \%args,
438 );
439 }
440 else {
441 return $self->_ParseContentSimple(
442 Content => $content,
443 TemplateArgs => \%args,
444 );
445 }
446}
447
448# uses Text::Template for Perl templates
449sub _ParseContentPerl {
450 my $self = shift;
451 my %args = (
452 Content => undef,
453 TemplateArgs => {},
454 @_,
455 );
456
457 foreach my $key ( keys %{ $args{TemplateArgs} } ) {
458 my $val = $args{TemplateArgs}{ $key };
459 next unless ref $val;
460 next if ref $val =~ /^(ARRAY|HASH|SCALAR|CODE)$/;
461 $args{TemplateArgs}{ $key } = \$val;
462 }
463
464 my $template = Text::Template->new(
465 TYPE => 'STRING',
466 SOURCE => $args{Content},
467 );
468 my $is_broken = 0;
469 my $retval = $template->fill_in(
470 HASH => $args{TemplateArgs},
471 BROKEN => sub {
472 my (%args) = @_;
473 $RT::Logger->error("Template parsing error: $args{error}")
474 unless $args{error} =~ /^Died at /; # ignore intentional die()
475 $is_broken++;
476 return undef;
477 },
478 );
479 return ( undef, $self->loc('Template parsing error') ) if $is_broken;
480
481 return ($retval);
482}
483
484sub _ParseContentSimple {
485 my $self = shift;
486 my %args = (
487 Content => undef,
488 TemplateArgs => {},
489 @_,
490 );
491
492 $self->_MassageSimpleTemplateArgs(%args);
493
494 my $template = Text::Template->new(
495 TYPE => 'STRING',
496 SOURCE => $args{Content},
497 );
498 my ($ok) = $template->compile;
499 return ( undef, $self->loc('Template parsing error: [_1]', $Text::Template::ERROR) ) if !$ok;
500
501 # copied from Text::Template::fill_in and refactored to be simple variable
502 # interpolation
503 my $fi_r = '';
504 foreach my $fi_item (@{$template->{SOURCE}}) {
505 my ($fi_type, $fi_text, $fi_lineno) = @$fi_item;
506 if ($fi_type eq 'TEXT') {
507 $fi_r .= $fi_text;
508 } elsif ($fi_type eq 'PROG') {
509 my $fi_res;
510 my $original_fi_text = $fi_text;
511
512 # strip surrounding whitespace for simpler regexes
513 $fi_text =~ s/^\s+//;
514 $fi_text =~ s/\s+$//;
515
516 # if the codeblock is a simple $Variable lookup, use the value from
517 # the TemplateArgs hash...
518 if (my ($var) = $fi_text =~ /^\$(\w+)$/) {
519 if (exists $args{TemplateArgs}{$var}) {
520 $fi_res = $args{TemplateArgs}{$var};
521 }
522 }
523
524 # if there was no substitution then just reinsert the codeblock
525 if (!defined $fi_res) {
526 $fi_res = "{$original_fi_text}";
527 }
528
529 # If the value of the filled-in text really was undef,
530 # change it to an explicit empty string to avoid undefined
531 # value warnings later.
532 $fi_res = '' unless defined $fi_res;
533
534 $fi_r .= $fi_res;
535 }
536 }
537
538 return $fi_r;
539}
540
541sub _MassageSimpleTemplateArgs {
542 my $self = shift;
543 my %args = (
544 TemplateArgs => {},
545 @_,
546 );
547
548 my $template_args = $args{TemplateArgs};
549
550 if (my $ticket = $template_args->{Ticket}) {
551 for my $column (qw/Id Subject Type InitialPriority FinalPriority Priority TimeEstimated TimeWorked Status TimeLeft Told Starts Started Due Resolved RequestorAddresses AdminCcAddresses CcAddresses/) {
552 $template_args->{"Ticket".$column} = $ticket->$column;
553 }
554
555 $template_args->{"TicketQueueId"} = $ticket->Queue;
556 $template_args->{"TicketQueueName"} = $ticket->QueueObj->Name;
557
558 $template_args->{"TicketOwnerId"} = $ticket->Owner;
559 $template_args->{"TicketOwnerName"} = $ticket->OwnerObj->Name;
560 $template_args->{"TicketOwnerEmailAddress"} = $ticket->OwnerObj->EmailAddress;
561
562 my $cfs = $ticket->CustomFields;
563 while (my $cf = $cfs->Next) {
564 $template_args->{"TicketCF" . $cf->Name} = $ticket->CustomFieldValuesAsString($cf->Name);
565 }
566 }
567
568 if (my $txn = $template_args->{Transaction}) {
569 for my $column (qw/Id TimeTaken Type Field OldValue NewValue Data Content Subject Description BriefDescription/) {
570 $template_args->{"Transaction".$column} = $txn->$column;
571 }
572
573 my $cfs = $txn->CustomFields;
574 while (my $cf = $cfs->Next) {
575 $template_args->{"TransactionCF" . $cf->Name} = $txn->CustomFieldValuesAsString($cf->Name);
576 }
577 }
578}
579
580sub _DowngradeFromHTML {
581 my $self = shift;
582 my $orig_entity = $self->MIMEObj;
583
584 my $new_entity = $orig_entity->dup; # this will fail badly if we go away from InCore parsing
585 $new_entity->head->mime_attr( "Content-Type" => 'text/plain' );
586 $new_entity->head->mime_attr( "Content-Type.charset" => 'utf-8' );
587
588 $orig_entity->head->mime_attr( "Content-Type" => 'text/html' );
589 $orig_entity->head->mime_attr( "Content-Type.charset" => 'utf-8' );
590 $orig_entity->make_multipart('alternative', Force => 1);
591
592 require HTML::FormatText;
593 require HTML::TreeBuilder;
594 require Encode;
595 # need to decode_utf8, see the doc of MIMEObj method
596 my $tree = HTML::TreeBuilder->new_from_content(
597 Encode::decode_utf8($new_entity->bodyhandle->as_string)
598 );
599 $new_entity->bodyhandle(MIME::Body::InCore->new(
600 \(scalar HTML::FormatText->new(
601 leftmargin => 0,
602 rightmargin => 78,
603 )->format( $tree ))
604 ));
605 $tree->delete;
606
607 $orig_entity->add_part($new_entity, 0); # plain comes before html
608 $self->{MIMEObj} = $orig_entity;
609
610 return;
611}
612
613=head2 CurrentUserHasQueueRight
614
615Helper function to call the template's queue's CurrentUserHasQueueRight with the passed in args.
616
617=cut
618
619sub CurrentUserHasQueueRight {
620 my $self = shift;
621 return ( $self->QueueObj->CurrentUserHasRight(@_) );
622}
623
624=head2 SetType
625
626If setting Type to Perl, require the ExecuteCode right.
627
628=cut
629
630sub SetType {
631 my $self = shift;
632 my $NewType = shift;
633
634 if ($NewType eq 'Perl' && !$self->CurrentUser->HasRight(Right => 'ExecuteCode', Object => $RT::System)) {
635 return ( undef, $self->loc('Permission Denied') );
636 }
637
638 return $self->_Set( Field => 'Type', Value => $NewType );
639}
640
641=head2 SetContent
642
643If changing content and the type is Perl, require the ExecuteCode right.
644
645=cut
646
647sub SetContent {
648 my $self = shift;
649 my $NewContent = shift;
650
651 if ($self->Type eq 'Perl' && !$self->CurrentUser->HasRight(Right => 'ExecuteCode', Object => $RT::System)) {
652 return ( undef, $self->loc('Permission Denied') );
653 }
654
655 return $self->_Set( Field => 'Content', Value => $NewContent );
656}
657
658sub _UpdateAttributes {
659 my $self = shift;
660 my %args = (
661 NewValues => {},
662 @_,
663 );
664
665 my $type = $args{NewValues}{Type} || $self->Type;
666
667 # forbid updating content when the (possibly new) value of Type is Perl
668 if ($type eq 'Perl' && exists $args{NewValues}{Content}) {
669 if (!$self->CurrentUser->HasRight(Right => 'ExecuteCode', Object => $RT::System)) {
670 return $self->loc('Permission Denied');
671 }
672 }
673
674 return $self->SUPER::_UpdateAttributes(%args);
675}
676
677=head2 CompileCheck
678
679If the template's Type is Perl, then compile check all the codeblocks to see if
680they are syntactically valid. We eval them in a codeblock to avoid actually
681executing the code.
682
683Returns an (ok, message) pair.
684
685=cut
686
687sub CompileCheck {
688 my $self = shift;
689
690 return (1, $self->loc("Template does not include Perl code"))
691 unless $self->Type eq 'Perl';
692
693 my $content = $self->Content;
694 $content = '' if !defined($content);
695
696 my $template = Text::Template->new(
697 TYPE => 'STRING',
698 SOURCE => $content,
699 );
700 my ($ok) = $template->compile;
701 return ( undef, $self->loc('Template parsing error: [_1]', $Text::Template::ERROR) ) if !$ok;
702
703 # copied from Text::Template::fill_in and refactored to be compile checks
704 foreach my $fi_item (@{$template->{SOURCE}}) {
705 my ($fi_type, $fi_text, $fi_lineno) = @$fi_item;
706 next unless $fi_type eq 'PROG';
707
708 do {
709 no strict 'vars';
710 eval "sub { $fi_text }";
711 };
712 next if !$@;
713
714 my $error = $@;
715
716 # provide a (hopefully) useful line number for the error, but clean up
717 # all the other extraneous garbage
718 $error =~ s/\(eval \d+\) line (\d+).*/"template line " . ($1+$fi_lineno-1)/es;
719
720 return (0, $self->loc("Couldn't compile template codeblock '[_1]': [_2]", $fi_text, $error));
721 }
722
723 return (1, $self->loc("Template compiles"));
724}
725
726=head2 CurrentUserCanRead
727
728=cut
729
730sub CurrentUserCanRead {
731 my $self =shift;
732
733 return 1 if $self->CurrentUserHasQueueRight('ShowTemplate');
734
735 return $self->CurrentUser->HasRight( Right =>'ShowGlobalTemplates', Object => $RT::System )
736 if !$self->QueueObj->Id;
737
738 return;
739}
740
7411;
742
743use RT::Queue;
744use base 'RT::Record';
745
746sub Table {'Templates'}
747
748
749
750
751
752
753=head2 id
754
755Returns the current value of id.
756(In the database, id is stored as int(11).)
757
758
759=cut
760
761
762=head2 Queue
763
764Returns the current value of Queue.
765(In the database, Queue is stored as int(11).)
766
767
768
769=head2 SetQueue VALUE
770
771
772Set Queue to VALUE.
773Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
774(In the database, Queue will be stored as a int(11).)
775
776
777=cut
778
779
780=head2 QueueObj
781
782Returns the Queue Object which has the id returned by Queue
783
784
785=cut
786
787sub QueueObj {
788 my $self = shift;
789 my $Queue = RT::Queue->new($self->CurrentUser);
790 $Queue->Load($self->__Value('Queue'));
791 return($Queue);
792}
793
794=head2 Name
795
796Returns the current value of Name.
797(In the database, Name is stored as varchar(200).)
798
799
800
801=head2 SetName VALUE
802
803
804Set Name to VALUE.
805Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
806(In the database, Name will be stored as a varchar(200).)
807
808
809=cut
810
811
812=head2 Description
813
814Returns the current value of Description.
815(In the database, Description is stored as varchar(255).)
816
817
818
819=head2 SetDescription VALUE
820
821
822Set Description to VALUE.
823Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
824(In the database, Description will be stored as a varchar(255).)
825
826
827=cut
828
829
830=head2 Type
831
832Returns the current value of Type.
833(In the database, Type is stored as varchar(16).)
834
835
836
837=head2 SetType VALUE
838
839
840Set Type to VALUE.
841Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
842(In the database, Type will be stored as a varchar(16).)
843
844
845=cut
846
847
848=head2 Language
849
850Returns the current value of Language.
851(In the database, Language is stored as varchar(16).)
852
853
854
855=head2 SetLanguage VALUE
856
857
858Set Language to VALUE.
859Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
860(In the database, Language will be stored as a varchar(16).)
861
862
863=cut
864
865
866=head2 TranslationOf
867
868Returns the current value of TranslationOf.
869(In the database, TranslationOf is stored as int(11).)
870
871
872
873=head2 SetTranslationOf VALUE
874
875
876Set TranslationOf to VALUE.
877Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
878(In the database, TranslationOf will be stored as a int(11).)
879
880
881=cut
882
883
884=head2 Content
885
886Returns the current value of Content.
887(In the database, Content is stored as text.)
888
889
890
891=head2 SetContent VALUE
892
893
894Set Content to VALUE.
895Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
896(In the database, Content will be stored as a text.)
897
898
899=cut
900
901
902=head2 LastUpdated
903
904Returns the current value of LastUpdated.
905(In the database, LastUpdated is stored as datetime.)
906
907
908=cut
909
910
911=head2 LastUpdatedBy
912
913Returns the current value of LastUpdatedBy.
914(In the database, LastUpdatedBy is stored as int(11).)
915
916
917=cut
918
919
920=head2 Creator
921
922Returns the current value of Creator.
923(In the database, Creator is stored as int(11).)
924
925
926=cut
927
928
929=head2 Created
930
931Returns the current value of Created.
932(In the database, Created is stored as datetime.)
933
934
935=cut
936
937
938
939sub _CoreAccessible {
940 {
941
942 id =>
943 {read => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => ''},
944 Queue =>
945 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
946 Name =>
947 {read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => ''},
948 Description =>
949 {read => 1, write => 1, sql_type => 12, length => 255, is_blob => 0, is_numeric => 0, type => 'varchar(255)', default => ''},
950 Type =>
951 {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''},
952 Language =>
953 {read => 1, write => 1, sql_type => 12, length => 16, is_blob => 0, is_numeric => 0, type => 'varchar(16)', default => ''},
954 TranslationOf =>
955 {read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
956 Content =>
957 {read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'text', default => ''},
958 LastUpdated =>
959 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
960 LastUpdatedBy =>
961 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
962 Creator =>
963 {read => 1, auto => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
964 Created =>
965 {read => 1, auto => 1, sql_type => 11, length => 0, is_blob => 0, is_numeric => 0, type => 'datetime', default => ''},
966
967 }
968};
969
970RT::Base->_ImportOverlays();
971
9721;