+sub SetQueue {
+ my $self = shift;
+ return ( undef, $self->loc('Changing queue is not implemented') );
+}
+
+=head2 SetName
+
+Change name of the template.
+
+=cut
+
+sub SetName {
+ my $self = shift;
+ my $value = shift;
+
+ return ( undef, $self->loc('Name is required') )
+ unless $value;
+
+ return $self->_Set( Field => 'Name', Value => $value )
+ if lc($self->Name) eq lc($value);
+
+ my $tmp = $self->new( RT->SystemUser );
+ $tmp->LoadByCols( Name => $value, Queue => $self->Queue );
+ return ( undef, $self->loc('A Template with that name already exists') )
+ if $tmp->id;
+
+ return $self->_Set( Field => 'Name', Value => $value );
+}
+
+=head2 SetType
+
+If setting Type to Perl, require the ExecuteCode right.
+
+=cut
+
+sub SetType {
+ my $self = shift;
+ my $NewType = shift;
+
+ if ($NewType eq 'Perl' && !$self->CurrentUser->HasRight(Right => 'ExecuteCode', Object => $RT::System)) {
+ return ( undef, $self->loc('Permission Denied') );
+ }
+
+ return $self->_Set( Field => 'Type', Value => $NewType );
+}
+
+=head2 SetContent
+
+If changing content and the type is Perl, require the ExecuteCode right.
+
+=cut
+
+sub SetContent {
+ my $self = shift;
+ my $NewContent = shift;
+
+ if ($self->Type eq 'Perl' && !$self->CurrentUser->HasRight(Right => 'ExecuteCode', Object => $RT::System)) {
+ return ( undef, $self->loc('Permission Denied') );
+ }
+
+ return $self->_Set( Field => 'Content', Value => $NewContent );
+}
+
+sub _UpdateAttributes {
+ my $self = shift;
+ my %args = (
+ NewValues => {},
+ @_,
+ );
+
+ my $type = $args{NewValues}{Type} || $self->Type;
+
+ # forbid updating content when the (possibly new) value of Type is Perl
+ if ($type eq 'Perl' && exists $args{NewValues}{Content}) {
+ if (!$self->CurrentUser->HasRight(Right => 'ExecuteCode', Object => $RT::System)) {
+ return $self->loc('Permission Denied');
+ }
+ }
+
+ return $self->SUPER::_UpdateAttributes(%args);
+}
+
+=head2 CompileCheck
+
+If the template's Type is Perl, then compile check all the codeblocks to see if
+they are syntactically valid. We eval them in a codeblock to avoid actually
+executing the code.
+
+Returns an (ok, message) pair.
+
+=cut
+
+sub CompileCheck {
+ my $self = shift;
+
+ return (1, $self->loc("Template does not include Perl code"))
+ unless $self->Type eq 'Perl';
+
+ my $content = $self->Content;
+ $content = '' if !defined($content);
+
+ my $template = Text::Template->new(
+ TYPE => 'STRING',
+ SOURCE => $content,
+ );
+ my ($ok) = $template->compile;
+ return ( undef, $self->loc('Template parsing error: [_1]', $Text::Template::ERROR) ) if !$ok;
+
+ # copied from Text::Template::fill_in and refactored to be compile checks
+ foreach my $fi_item (@{$template->{SOURCE}}) {
+ my ($fi_type, $fi_text, $fi_lineno) = @$fi_item;
+ next unless $fi_type eq 'PROG';
+
+ do {
+ no strict 'vars';
+ eval "sub { $fi_text }";
+ };
+ next if !$@;
+
+ my $error = $@;
+
+ # provide a (hopefully) useful line number for the error, but clean up
+ # all the other extraneous garbage
+ $error =~ s/\(eval \d+\) line (\d+).*/"template line " . ($1+$fi_lineno-1)/es;
+
+ return (0, $self->loc("Couldn't compile template codeblock '[_1]': [_2]", $fi_text, $error));
+ }
+
+ return (1, $self->loc("Template compiles"));
+}
+
+=head2 CurrentUserCanRead
+
+=cut
+
+sub CurrentUserCanRead {
+ my $self =shift;
+
+ if ($self->__Value('Queue')) {
+ my $queue = RT::Queue->new( RT->SystemUser );
+ $queue->Load( $self->__Value('Queue'));
+ return 1 if $self->CurrentUser->HasRight( Right => 'ShowTemplate', Object => $queue );
+ } else {
+ return 1 if $self->CurrentUser->HasRight( Right => 'ShowGlobalTemplates', Object => $RT::System );
+ return 1 if $self->CurrentUser->HasRight( Right => 'ShowTemplate', Object => $RT::System );
+ }
+
+ return;
+}
+
+1;
+
+sub Table {'Templates'}