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 )