# ==================================================================== # Gossamer Threads Module Library - http://gossamer-threads.com/ # # GT::Template::Editor # Author: Alex Krohn # $Id: Editor.pm,v 2.16 2004/05/19 20:04:49 jagerman Exp $ # # Copyright (c) 2004 Gossamer Threads Inc. All Rights Reserved. # ==================================================================== # # Description: # A module for editing templates via an HTML browser. # package GT::Template::Editor; # =============================================================== use strict; use GT::Base; use vars qw(@ISA $VERSION $DEBUG $ATTRIBS $ERRORS); @ISA = qw/GT::Base/; $VERSION = sprintf "%d.%03d", q$Revision: 2.16 $ =~ /(\d+)\.(\d+)/; $DEBUG = 0; $ATTRIBS = { cgi => undef, root => undef, backup => undef, default_dir => '', default_file => '', date_format => '', class => undef, skip_dir => undef, skip_file => undef, select_dir => 'tpl_dir', demo => undef }; $ERRORS = { CANTOVERWRITE => "Unable to overwrite file: %s (Permission Denied). Please set permissions properly and save again.", CANTCREATE => "Unable to create new files in directory %s. Please set permissions properly and save again.", CANTMOVE => "Unable to move file: %s to %s. Reason: %s", CANTMOVE => "Unable to copy file: %s to %s. Reason: %s", FILECOPY => "File::Copy is required in order to make backups.", }; sub process { # ------------------------------------------------------------------ # Loads the template editor. # my $self = shift; my $sel_tpl_dir = $self->{select_dir}; my $selected_dir = $self->{cgi}->param($sel_tpl_dir) || $self->{default_dir} || 'default'; my $selected_file = $self->{cgi}->param('tpl_file') || ''; my $tpl_text = ''; my $error_msg = ''; my $success_msg = ''; my ($local, $restore) = (0, 0); # Create the local directory if it doesn't exist. my $tpl_dir = $self->{root} . '/' . $selected_dir; my $local_dir = $tpl_dir . "/local"; if (! -d $local_dir) { mkdir($local_dir, 0777) or return $self->error('MKDIR', 'FATAL', $local_dir, "$!"); chmod(0777, $local_dir); } my $dir = $local_dir; my $save = $self->{cgi}->param('tpl_name') || $self->{cgi}->param('tpl_file'); # Perform a save if requested. if ($self->{cgi}->param('saveas') and $save and !$self->{demo}) { $tpl_text = $self->{cgi}->param('tpl_text'); if (-e "$dir/$save" and ! -w _) { $error_msg = sprintf($ERRORS->{CANTOVERWRITE}, $save); } elsif (! -e _ and ! -w $dir) { $error_msg = sprintf($ERRORS->{CANTCREATE}, $dir); } else { if ($self->{backup} and -e "$dir/$save") { $self->copy("$dir/$save", "$dir/$save.bak"); } local *FILE; open (FILE, "> $dir/$save") or return $self->error(CANTOPEN => FATAL => "$dir/$save", "$!"); $tpl_text =~ s/\r\n/\n/g; print FILE $tpl_text; close FILE; chmod 0666, "$dir/$save"; $success_msg = "File has been successfully saved."; $local = 1; $restore = 1 if -e "$self->{root}/$selected_dir/$save"; $selected_file = $save; $tpl_text = ''; } } # Delete a local template (thereby restoring the system template) elsif (my $restore = $self->{cgi}->param("restore") and !$self->{demo}) { if ($self->{backup}) { if ($self->move("$dir/$restore", "$dir/$restore.bak")) { $success_msg = "System template '$restore' restored"; } else { $error_msg = "Unable to restore system template '$restore': Cannot move '$dir/$restore': $!"; } } else { if (unlink "$dir/$restore") { $success_msg = "System template '$restore' restored"; } else { $error_msg = "Unable to remove $dir/$restore: $!"; } } } # Delete a local template (This is like restore, but happens when there is no system template) elsif (my $delete = $self->{cgi}->param("delete") and !$self->{demo}) { if ($self->{backup}) { if ($self->move("$dir/$delete", "$dir/$delete.bak")) { $success_msg = "Template '$delete' deleted"; } else { $error_msg = "Unable to delete template '$delete': Cannot move '$dir/$delete': $!"; } } else { if (unlink "$dir/$delete") { $success_msg = "Template '$delete' deleted"; } else { $error_msg = "Unable to remove $dir/$delete: $!"; } } } # Load any selected template file. if ($selected_file and ! $tpl_text) { if (-f "$dir/$selected_file") { local (*FILE, $/); open FILE, "$dir/$selected_file" or die "Unable to open file $dir/$selected_file: $!"; $tpl_text = ; close FILE; $local = 1; $restore = 1 if -e "$self->{root}/$selected_dir/$selected_file"; } elsif (-f "$self->{root}/$selected_dir/$selected_file") { local (*FILE, $/); open FILE, "$self->{root}/$selected_dir/$selected_file" or die "Unable to open file $self->{root}/$selected_dir/$selected_file: $!"; $tpl_text = ; close FILE; } else { $selected_file = ''; } } # Load a README if it exists. my $readme; if (-e "$dir/README") { local (*FILE, $/); open FILE, "$dir/README" or die "unable to open readme: $dir/README ($!)"; $readme = ; close FILE; } # Set the textarea width and height. my $editor_rows = $self->{cgi}->param('cookie-editor_rows') || $self->{cgi}->cookie('editor_rows') || 15; my $editor_cols = $self->{cgi}->param('cookie-editor_cols') || $self->{cgi}->cookie('editor_cols') || 55; my $file_select = $self->template_file_select; my $dir_select = $self->template_dir_select; $tpl_text = $self->{cgi}->html_escape($tpl_text); my $stats = $selected_file ? $self->template_file_stats($selected_file) : {}; if ($self->{demo} and ($self->{cgi}->param('saveas') or $self->{cgi}->param("delete") or $self->{cgi}->param("restore"))) { $error_msg = 'This feature has been disabled in the demo!'; } return { tpl_name => $selected_file, tpl_file => $selected_file, local => $local, restore => $restore, tpl_text => \$tpl_text, error_message => $error_msg, success_message => $success_msg, tpl_dir => $selected_dir, readme => $readme, editor_rows => $editor_rows, editor_cols => $editor_cols, dir_select => $dir_select, file_select => $file_select, %$stats }; } sub _skip_files { my ($skip, $file) = @_; return 1 if $skip->{$file} or substr($file, 0, 1) eq '.' # skip dotfiles or substr($file, -4) eq '.bak'; # skip .bak files foreach my $f (keys %$skip) { my $match = quotemeta $f; $match =~ s/\\\*/.*/g; $match =~ s/\\\?/./g; return 1 if $file =~ /^$match$/; } return; } sub template_file_select { # ------------------------------------------------------------------ # Returns a select list of templates in a given dir. # my $self = shift; my $path = $self->{root}; my %files; my $sel_tpl_dir = $self->{select_dir}; my $selected_dir = $self->{cgi}->param($sel_tpl_dir) || $self->{default_dir} || 'default'; my $selected_file = $self->{cgi}->param('tpl_file') || $self->{default_file} || 'default'; my %skip; if ($self->{skip_file}) { for (@{$self->{skip_file}}) { $skip{$_}++; } } else { $skip{README} = $skip{'language.txt'} = $skip{'globals.txt'} = 1; } my $system_dir = $path . "/" . $selected_dir; my $local_dir = $path . "/" . $selected_dir . '/local'; foreach my $dir ($system_dir, $local_dir) { opendir (TPL, $dir) or next; while (defined(my $file = readdir TPL)) { next unless -f "$dir/$file" and -r _; next if _skip_files(\%skip, $file); $files{$file} = 1; } closedir TPL; } my $f_select_list = '{class}; $d_select_list .= ">\n"; foreach (sort @dirs) { $d_select_list .= qq'