CatalystX-CMS
view release on metacpan or search on metacpan
lib/CatalystX/CMS.pm view on Meta::CPAN
}
}
else {
# cmspage exists, we just want a local copy to edit
#carp dump $cmspage;
$orig->{delegate} = $cmspage->{delegate};
$cmspage->{delegate} = $cmspage->delegate_class->new(
path => Path::Class::file(
$c->config->{cms}->{root}->{rw}->[0],
$orig->{type},
$orig->{flavour},
$cmspage->file . $cmspage->ext
)
);
$cmspage->{delegate}->dir->mkpath;
}
# make the copy
$c->log->debug("orig: $orig") if $c->debug;
$c->log->debug("copy: $cmspage") if $c->debug;
my $fh = $cmspage->delegate->openw;
my $buf = $orig->slurp;
print $fh $buf;
$fh->close;
$cmspage->delegate->_parse_page($buf);
}
}
=head2 edit( I<c>, I<controller>, I<cmspage> )
Available as a B<cms_mode> method.
Verifies lock on I<cmspage>, extending it if necessary, and
displays the cms editor template.
=cut
sub edit {
my ( $self, $c, $controller, $cmspage ) = @_;
# can't edit a file we haven't yet created
# unless it is one of our own CMS/tt/cms/wrappers/* files
$self->_copy_if_required( $c, $controller, $cmspage );
unless ( -s $cmspage ) {
croak( $cmspage->file . " does not exist" );
}
# lock the file immediately so no one else can edit it.
# only the current user can unlock it, either by saving
# changes or by explicitly calling the cancel url.
# could be a redirect from create() so check that owner == $user
my $user = $self->get_user($c);
if ( $cmspage->locked ) {
# how old is the lock?
my $lock_period = $c->config->{cms}->{lock_period} || 3600;
if ( ( $cmspage->lock_time + $lock_period ) < time() ) {
$c->log->debug("lock expired on $cmspage");
$cmspage->lock($user);
}
elsif ( $cmspage->lock_owner ne $user ) {
croak( "$cmspage is already locked by " . $cmspage->lock_owner );
}
else {
# extend the lock every time we hit this url
if ( $cmspage->unlock && $cmspage->lock($user) ) {
$c->log->debug("$cmspage lock re-acquired by $user");
}
else {
croak("failed to re-acquire $cmspage lock for $user");
}
}
}
else {
$cmspage->lock($user);
}
$DEBUG and warn "svn update $cmspage";
# make sure we're working on the latest copy,
# in case the repository is non-local and we're
# behind a load balancer (for example)
#$cmspage->up; # **not** ->update
my %res;
$res{template} = 'cms/yui/editor.tt';
return \%res;
}
sub _filter_text {
my ( $self, $text_ref ) = @_;
# return number of s/// changes to $$text_ref
my $n = 0;
$n += $$text_ref =~ s/<code class="tt">//g;
$n += $$text_ref =~ s/<\/code>//g;
$n += $$text_ref =~ s/<br>/\n/g;
# pesky Win32 line-endings
$n += $$text_ref =~ s/\r\n/\n/g;
return $n;
}
sub _get_attrs {
my ( $self, $c, $cmspage ) = @_;
for my $key ( sort keys %{ $cmspage->attrs } ) {
if ( defined $c->req->params->{$key} ) {
$cmspage->attrs->{$key} = $c->req->params->{$key};
}
}
# new ad hoc attrs
for my $new_attrs_name ( grep {m/^new_attr_name_\d+$/} $c->req->param ) {
my ($id) = ( $new_attrs_name =~ m/_(\d+)$/ );
my $key = $c->req->params->{$new_attrs_name} or next;
my $val = $c->req->params->{ 'new_attr_val_' . $id } || '';
$key =~ s/\W/_/g;
next if $key eq 'attrs_name'; # generic name
$cmspage->attrs->{$key} = $val;
}
# some minimal attrs required.
$cmspage->attrs->{owner} ||= $self->get_user($c);
$cmspage->attrs->{title} ||= 'no title';
}
=head2 do_action( I<c>, I<controller>, I<cmspage> )
Called by PUT(). Calls B<cms_mode> like GET() does,
but checks lock on I<cmspage> first.
do_action() is typically called for save()ing a I<cmspage>.
=cut
sub do_action {
my ( $self, $c, $controller, $cmspage ) = @_;
my $text = $c->req->params->{text};
if ( !defined $text ) {
croak('text param required');
}
my $action = $c->stash->{cms_mode} || 'save';
my $user = $self->get_user($c);
# is this file locked by this user?
if ( !$cmspage->locked ) {
croak( $cmspage->url . " is not locked for editing." );
}
if ( $cmspage->lock_owner ne $user ) {
croak( $cmspage->url . " is not locked by $user." );
}
# YUI editor adds HTML <br> to represent \n
# so filter those and any others.
my $filter += $self->_filter_text( \$text );
$self->_get_attrs( $c, $cmspage );
$cmspage->content($text);
$c->log->debug("Action = $action") if $c->debug;
if ( $self->can($action) ) {
return $self->$action( $c, $controller, $cmspage );
}
else {
croak("Bad action: $action");
}
}
=head2 cancel( I<c>, I<controller>, I<cmspage> )
Available as a B<cms_mode> method.
Reverts any local changes to I<cmspage> and unlocks the page.
If I<cmspage> has never been committed to the svn repository,
the file will be removed.
=cut
sub cancel {
my ( $self, $c, $controller, $cmspage ) = @_;
my $stat = $cmspage->status;
# if file has local mods (or flagged for addition)
# then remove/revert it and update.
if ( $stat ne '?' ) {
if ( $stat eq 'A' ) {
unless ( $cmspage->revert ) {
croak("Could not revert $cmspage");
return 0;
}
# TODO should page be removed too?
}
elsif ( $stat eq 'M' ) {
unless ( $cmspage->remove ) {
croak("Could not remove modified $cmspage");
return 0;
}
unless ( $cmspage->up ) {
croak("Count not svn update $cmspage");
return 0;
}
}
}
else {
lib/CatalystX/CMS.pm view on Meta::CPAN
=cut
sub save {
my ( $self, $c, $controller, $cmspage ) = @_;
return unless $self->validate( $c, $controller, $cmspage );
my $user = $self->get_user($c);
my $stat = $cmspage->save("edit by $user");
my $url = $cmspage->url;
my %res;
if ( $stat && $stat > 0 ) {
$c->log->debug("save returned $stat") if $c->debug;
$res{message} = "Committed $url as change $stat";
}
else {
$c->log->debug("save stat $stat indicates no change to $cmspage")
if $c->debug;
$res{message} = "No changes made to $url";
}
# TODO what if $url is a wrapper part?
$res{uri} = $c->uri_for($url);
return \%res;
}
=head2 preview( I<c>, I<controller>, I<cmspage> )
Available as a B<cms_mode> method.
Like save() but with no commit() and preserves lock
=cut
sub preview {
my ( $self, $c, $controller, $cmspage ) = @_;
return unless $self->validate( $c, $controller, $cmspage );
# force write since we own lock and want to keep it.
$cmspage->update(1);
return { template => $cmspage };
}
=head2 delete( I<c>, I<controller>, I<cmspage> )
Available as a B<cms_mode> method.
Called by DELETE(). Removes lock on I<cmspage> and
deletes the file from the local workspace B<and from the svn
repository>. See also cancel().
=cut
sub delete {
my ( $self, $c, $controller, $cmspage ) = @_;
if ( $cmspage->locked ) {
$cmspage->unlock or croak("can't unlock $cmspage");
}
my $user = $self->get_user($c);
my $stat = $cmspage->status;
if ($stat) {
# if the page has local mods, then remove working copy,
# svn update, and then svn delete
if ( $stat eq 'M' ) {
unless ( $cmspage->remove ) {
croak("Could not remove modified $cmspage");
}
unless ( $cmspage->up ) {
croak("Could not svn update $cmspage");
}
unless ( $cmspage->delete ) {
croak("Could not svn delete $cmspage");
}
unless ( $cmspage->commit("deleted by $user") ) {
croak("Could not commit delete of $cmspage");
}
}
# if the page is new, revert it and then remove
if ( $stat eq 'A' ) {
unless ( $cmspage->revert ) {
croak("Could not revert $cmspage");
return 0;
}
unless ( $cmspage->remove ) {
croak("Could not remove $cmspage");
return 0;
}
}
# if svn knows nothing about the file, just remove it
if ( $stat eq '?' ) {
unless ( $cmspage->remove ) {
croak("Could not remove $cmspage");
return 0;
}
}
}
else {
# no local mods. svn delete it.
unless ( $cmspage->delete ) {
croak("Count not svn delete $cmspage");
return 0;
}
unless ( $cmspage->commit("deleted by $user") ) {
croak("Could not commit delete of $cmspage");
return 0;
( run in 2.314 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )