##########description#################################################################
#
# Copyright (C) Daniel Guermeur - 1999-2001
# Copyright (C) Metadot Corporation - 2001-2005
#
# This file is part of Metadot Portal Server software $Name: Release_6_4_r3 $
#
# Metadot Portal Server software is free software; you can
# redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
#
# Metadot Portal Server software is distributed in the hope that it
# will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# Metadot Portal Server; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# For more information, please contact info@metadot.com.
#
############################################################################
package CMSDocument;
use strict;
use GizmoBuilder;
use Gizmo::CMSDocument::Version;
use Metadot::MIME::Types;
use Metadot::Controllable;
use Utility;
use Metadot::Notifiable;
use vars qw(@ISA);
@ISA=qw(GizmoBuilder Metadot::Rateable Metadot::Controllable Metadot::Notifiable);
my $version = "4.6";
sub get_version {
return $version;
}
use Metadot qw($USER $SESSION %FORM $PARAMS);
####################################
sub new {
my $proto = shift;
my $class = ref($proto) || $proto;
my $args = $class->normalize_constructor_args(shift);
my $id = $args->{id};
my $self;
if (defined ($id)){
return $class->restore($id);
} else {
$self = $class->SUPER::new($args);
}
$self->{cool}='No';
$self->{is_a} = __PACKAGE__;
$self->_form_initialize();
$self->set_field_info (
# "name", "CMS Document Name", 1,
"name", "" . $self->get_gizmo_name() . " Name", 1,
"file1", "File Name", 1,
"description", "Description", 1,
"t4", "Check in Comment", 1,
"t2", "Mod User ID", 0,
"t1", "File Mofidication Date" , 0,
"t9", "File Checked out?", 0,
"cool", "Star this " . $self->get_gizmo_name() . "?", 0,
## (qp)
"t6", "Revision major.minor", 0,
);
$self->{display_wrapped} = { show => 1,
};
bless ($self, $class); # reconsecrate
return $self;
}
# this class tries to save a FileHandle into file1, which breaks Oracle
sub add {
my $self = shift;
$self->_fix_file1();
return $self->SUPER::add(@_);
}
# this class tries to save a FileHandle into file1, which breaks Oracle
sub save {
my $self = shift;
$self->_fix_file1();
return $self->SUPER::save(@_);
}
# ensures that file1 is a string
sub _fix_file1 {
my $self = shift;
$self->{file1} = "$self->{file1}";
return $self;
}
sub customize_permissions {
my $self = shift;
my $ac = shift;
$self->SUPER::customize_permissions($ac);
# checkin/checkout
$ac->add_bundle('CHECKINOUT', 'Checkin Checkout', '8','2');
$ac->add_op('CHECKINOUT', 'cancelcheckout');
$ac->add_op('CHECKINOUT', 'checkout');
$ac->add_op('CHECKINOUT', 'modify_existing');
$ac->add_op('CHECKINOUT', 'save_existing');
$ac->add_op('CHECKINOUT', 'force_download');
Metadot::Notifiable->customize_permissions($ac);
return $ac;
}
sub get_gizmo_name {
my $self = shift;
return "Document With Version Control";
}
sub set_checked_out_status {
my $self = shift;
$self->{t9} = shift;
}
sub get_checked_out_status {
my $self = shift;
return $self->{t9};
}
sub get_checkout_owner {
my $self = shift;
return $self->{t2};
}
sub set_checkout_owner {
my $self = shift;
$self->{t2} = shift;
}
sub get_current_version {
my $self = shift;
return $self->{t3};
}
## (qp) to support major.minor format
sub get_next_version {
my $self = shift;
my $v = shift;
my $ret = $v;
if ( $v =~ /(\d+)\.(\d+)/ ) {
my $major = $1;
my $minor = $2;
$minor += 1;
$ret = "$major\.$minor";
}
return $ret;
}
sub set_current_version {
my $self = shift;
$self->{t3} = shift;
}
sub get_current_version_iid {
my $self = shift;
return $self->{i1};
}
sub set_current_version_iid {
my $self = shift;
$self->{i1} = shift;
}
sub set_downloaded_state {
my $self = shift;
$self->{t5} = shift;
}
sub get_downloaded_state {
my $self = shift;
return $self->{t5};
}
sub get_version_object {
my $self = shift;
my $version_iid = shift || $self->get_current_version_iid();
return Version->new($version_iid);
}
sub get_previous_versions {
my $self = shift;
my @results = ();
my $current_version_iid = $self->get_current_version_iid();
my $parent_iid = $self->get_iid();
if (defined($parent_iid) && defined($current_version_iid)) {
my $sth = DBAccess->sqlSelectMany("iid", "instance", "parentiid = $parent_iid and iid != $current_version_iid order by CreationDate desc");
while (my ($child_iid) = $sth->fetchrow_array()) {
push @results, Version->new($child_iid);
}
$sth->finish;
}
return \@results;
}
sub _form_initialize {
my $self = shift;
$self->{fields}->{t9}->{formtype} = "radio";
$self->{fields}->{t9}->{selectsize} = "1";
$self->{fields}->{t10}->{formtype} = "checkbox";
$self->{fields}->{t10}->{selectsize} = "1";
$self->{fields}->{t4}->{formtype} = "mediumtext";
# (qp)
$self->{fields}->{t6}->{formtype} = "text";
}
#aju
# sub www_show {
sub show {
my $self = shift;
$self->debug_msg(3, "CMSDocument::www_show()");
my $iid = $self->get_iid();
my $name = $self->get_name();
my $content;
my $current_version = $self->get_current_version();
my $imageslocation = $PARAMS->{'imageslocation'};
my $current_version_iid = $self->get_current_version_iid();
my $version = $self->get_version_object();
my $last_checkin_time = $version->get_modification_time();
my $last_checkin_name = $USER->get_fullname_from_uid($version->get_uid_of_modifier());
my $currfilename = $version->get_file_1();
my $file_icon = $version->get_file_1_icon();
my $current_remark = $version->get_comment();
$current_remark =~ s/\n/ /gi if $current_remark ;
$content .= " " ;
$content .= "
";
my $previous_versions = Version->show_previous($iid, $current_version_iid);
if ($previous_versions) {
$content .= "
Previous versions:
";
$content .= "
" ;
$content .= $previous_versions;
$content .= "
";
}
$content .= "
";
if ($FORM{checkingout} eq 'yes') {
unless ($self->get_downloaded_state() eq 'yes') {
$content .= $self->get_download_javascript();
$self->set_downloaded_state('yes');
$self->save();
}
}
return $content;
}
sub exec_show {
my ($self, $context) = @_;
if ($FORM{checkingout} eq 'yes') {
unless ($self->get_downloaded_state() eq 'yes') {
$self->set_downloaded_state('yes');
$self->save();
}
}
return $self->SUPER::exec_show($context);
}
sub get_download_javascript {
my $self = shift;
my $rand = rand;
my $current_version_iid = $self->get_current_version_iid();
my $result = <
EOM
;
return $result;
}
sub is_checked_out {
my $self = shift;
return ($self->get_checked_out_status() eq "Yes");
}
sub get_check_buttons () {
my $self = shift;
$self->debug_msg(3, "CMSDocument::get_check_buttons()");
my $imageslocation = $PARAMS->{'imageslocation'} ;
my $iid = $self->defined_or_exit($self->id,"id is missing.");
my $content = "" ;
if ($self->is_checked_out()) {
my $checkout_owner = $self->get_checkout_owner();
my $checkout_owner_name = $USER->get_fullname_from_uid($checkout_owner);
$content .= "is currently checked out by: $checkout_owner_name ";
if ($checkout_owner == $USER->{uid}) {
$content .= "";
}
if (($checkout_owner == $USER->{uid}) || ($self->is_allowed_to_do('modify', $USER))) {
$content .= " " ;
$content .= "";
}
} else {
if ($self->is_allowed_to_do('checkout', $USER)) {
$content .= "";
}
}
return $content ;
}
sub www_modify {
my $self = shift;
my $errormsg = shift;
$self->debug_msg(3, "CMSDocument::www_modify()");
my $iid = $self->id();
my $isa = $self->is_a();
my $target = $SESSION->{referer};
if (!defined $iid){
$self->click_back ("Error:", "id is missing.");
exit(0);
}
my ($checkout_owner, $checkout_status) = DBAccess->sqlSelect("t2,t9", "instance", "iid=$iid");
$errormsg = $errormsg ?
"
Please correct the following error(s):
\n$errormsg
\n" :
"";
my $form = $self->show_edit_form("Modify " . $self->get_gizmo_name() .
" information");
my $content = "" ;
# JSForm
my $form_tag = "
";
$self->print_form($content);
}
sub www_modify_existing {
my $self = shift;
my $name = $self->get_name();
my $errormsg = shift;
$self->debug_msg(3, "CMSDocument::www_modify_existing()");
my $iid = $self->id();
my $isa = $self->is_a();
my $target = $SESSION->{referer};
if (!defined $iid){
$self->click_back ("Error:", "id is missing.");
exit(0);
}
$errormsg = $errormsg ?
"
Please correct the following error(s):
\n$errormsg
\n" :
"";
# my $form = $self->show_edit_form_modify("$name Checking in an update to $isa");
my $form = $self->show_edit_form_modify("Checking in document update");
my $content = "" ;
# JSForm
my $form_tag = "
";
$self->print_form($content);
}
## build form for adding and updating
sub show_edit_form {
my $self = shift;
my $title = shift;
my $s = "";
my $iid = $self->{id};
$s .= "
" . $title . "
\n";
if (defined($iid) && '$iid' ne '0') { #editing
# if there is any intro text to be displayed at the top, add it.
$s .= "
Add a new File (*) ";
# JSForm
$self->{jsform}->add_check_simple("file1", "Add a new File", "notempty") if defined($self->{jsform}) ;
# JSForm
}
$s .= "
(*) Mandatory field(s) ";
return $s;
}
## build form for checking in
sub show_edit_form_modify {
my $self = shift;
my $title = shift;
my $s = "";
$s .= "
" . $title . "
\n";
# if there is any intro text to be displayed at the top, add it.
$s .= "
" . $self->get_intro_text() . "
";
$s .= " Check in comment (*) ";
$s .= "\n";
# JSForm
$self->{jsform}->add_check_simple("t4", "Check in comment", "notempty") if defined($self->{jsform}) ;
$s .= "
Upload a new version of the file (*) ";
# (qp )
$self->{t6} = $self->get_current_version();
$self->{t6} = $self->get_next_version( $self->{t6} );
$s .= $self->get_form_box( "t6" );
# JSForm
$self->{jsform}->add_check_simple("file1", "Upload a new version of the file", "notempty") if defined($self->{jsform}) ;
$s .= "
(*) Mandatory field(s) ";
return $s;
}
sub www_checkout {
my $self = shift;
my $iid = $self->id();
my $isa = $self->is_a();
#mark as checked out
$self->set_checked_out_status("Yes");
$self->set_downloaded_state("No");
#set the user
$self->set_checkout_owner($USER->{uid});
$self->save();
$self->md_redirect("index.pl?id=$iid&isa=$isa&op=show&checkingout=yes");
}
sub www_cancelcheckout {
my $self = shift;
my $iid = $self->id();
my $uid = $USER->uid();
my $isa = $self->is_a();
unless (($uid = $self->get_checkout_owner) || ($self->is_allowed_to_do('modify'))) {
$self->print_click_back("Sorry", "You must be the person who has the version checked out, or you must have edit privileges on this CMSDocument, in order to cancel a checkout\n");
exit;
}
$self->set_checked_out_status("No");
$self->set_checkout_owner("NULL");
$self->save();
$self->md_redirect("index.pl?id=$iid&isa=$isa&op=show");
}
## called for saving the first time and when editing
sub www_save {
my $self = shift;
my $checked_reqs = shift; #optional
my $order = 0;
my $uid = $USER->uid();
my $error = undef;
my $rev ;
if(ord substr($FORM{file1},0,1) < 32) {
$FORM{file1} = "" ;
}
if (!$checked_reqs) {
## check for required fields
#print STDERR "checking for field ";
foreach my $field (keys (%{$self->{fields}})) {
#print STDERR " $field : $FORM{$field}\n";
if (($field ne "file1") && ($field ne "t4")) {
if ($self->{fields}->{$field}->{required} &&
(!$FORM{$field} || !($FORM{$field} =~ /\S/)) # field is not just whitespace
) {
$error .= " ".$self->{fields}->{$field}->{label} .
" is a required field.\n";
}
}
}
}
## (qp) validate the major.minor revision specification
if ( defined( $FORM{"t6"} ) ) {
if ( $FORM{"t6"} =~ /^\d+\.\d+$/ ) {
# good
}
else {
# bad
$error .= " Revision number must be in the form M.N where M and N are integers.\n";
}
}
my $iid = $self->get_iid();
if (defined($error) && $iid){ ## if error and updating
$self->www_modify($error);
exit;
}
elsif (defined($error)) { ## if error and saving new
my $parentid = $self->parent_id();
my $parent = Gizmo->restore($parentid);
$parent->www_add_child($error, $self->is_a);
exit;
}
#print STDERR "\nwww_save::got past the error checks!\n";
if (!$iid){ ## we are creating new
foreach my $field (keys (%{$self->{fields}})) {
$order = $self->{fields}->{$field}->{order};
next if !defined($order) || $order <= 0;
$self->{$field} = $FORM{$field};
}
$iid = $self->add();
# (qp)
# $rev = "1.1";
$rev = ($self->{t6}) ? $self->{t6} : "1.0";
my $parent_id = $self->parent_id();
my $CMS_owner = $self->{uid} || $USER->{uid};
my $version = Version->new({ parent_id => $iid });
my $navigable_parent = $self->get_navigation_parent();
$version->set_version_number($rev);
$version->set_comment($self->{t4});
$version->set_uid_of_modifier($USER->{uid});
$version->set_owner($CMS_owner);
$version->add();
###must call add before uploading the file, in order to get an iid for the directory name
eval {
my $upload_file = $version->upload_file($FORM{file1});
};
if( $@ ) {
$version->delete();
$self->delete();
exit(0);
}
my $filename = $version->get_file1();
if ($filename =~ m/QUOTA_EXCEEDED/) {
#handle quota exceeded here
$version->set_file1("");
$version->delete();
$self->delete();
if ($filename eq 'USER_QUOTA_EXCEEDED') {
$self->print_click_back("Sorry", "You have exceeded your user file space quota. Remove some files from the server or ask the administrator for additional space.\n");
} else {
$self->print_click_back("Sorry", "You have exceeded the site-wide file space quota. Please remove some files from the server or ask the administrator for additional space.\n");
}
exit;
}
$version->save();
$self->set_current_version_iid($version->get_iid);
# (qp)
# $self->set_current_version("1.1" );
$self->set_current_version(($self->{t6}) ? $self->{t6} : "1.0");
#update the filename from the version
$self->{file1} = $filename;
$self->save();
$self->two_choices("New " . $self->get_gizmo_name() . " added!
What do you want to do?",
"confirm",
"Add another " . $self->get_gizmo_name(),
"index.pl?child_type=CMSDocument&isa=Category&iid=$parent_id&op=add_child",
"Enough for now!",
"index.pl?id=$parent_id",
);
} else {
$self->{name} = $FORM{"name"};
$self->{description} = $FORM{"description"};
## (qp)
$self->set_current_version( $FORM{"t6"} );
$self->{cool} = $FORM{"cool"};
$self->save();
$self->md_redirect("index.pl?iid=".$self->parent_id);
}
}
sub www_delete_ok {
my $self = shift;
my $iid = $self->get_iid();
Version->delete_children($iid);
$self->SUPER::www_delete_ok();
}
## called for updating
sub www_save_existing {
my $self = shift;
my $checked_reqs = shift; #optional
my $order = 0;
my $uid = $USER->uid();
my $error = undef;
my $rev ;
if ($USER->{uid} != $self->get_checkout_owner()) {
$self->print_click_back("Sorry", "You are not the person who currently has this item checked out\n");
exit;
}
if(ord substr($FORM{file1},0,1) < 32) {
$FORM{file1} = "" ;
}
if (!$checked_reqs) {
## check for required fields
#we only have two fielda to save and mofigy, file1 and comment
foreach my $field (keys (%{$self->{fields}})) {
if (($field ne "description") && ($field ne "name")) {
if ($self->{fields}->{$field}->{required} &&
(!$FORM{$field} || !($FORM{$field} =~ /\S/)) # field is not just whitespace
) {
$error .= " ".$self->{fields}->{$field}->{label} .
" is a required field.\n";
}
}
}
}
my $iid = $self->get_iid();
if (defined($error) && $iid){ ## if error and updating
$self->www_modify_existing($error);
exit;
}
elsif (defined($error)) { ## if error and saving new
my $parentid = $self->parent_id();
my $parent = Gizmo->restore($parentid);
$parent->www_add_child($error, $self->is_a);
exit;
}
my $CMS_owner = $self->{uid} || $USER->{uid};
my $current_version = $self->get_current_version();
## (qp) support major.minor format
## $current_version++;
if ( defined( $FORM{t6} ) ) {
$current_version = $FORM{t6};
}
else {
$current_version = $self->get_next_version( $current_version );
}
## end (qp)
$self->set_current_version($current_version);
my $version = Version->new({ parent_id => $iid });
$version->set_version_number($current_version);
$version->set_comment($FORM{t4});
$version->set_uid_of_modifier($USER->{uid});
$version->set_owner($CMS_owner);
$version->add();
###must call add before uploading the file, in order to get an iid for the directory name
eval {
$version->upload_file($FORM{file1});
};
if( $@ ) {
$version->delete();
exit(0);
}
my $filename = $version->get_file1();
if ($filename =~ m/QUOTA_EXCEEDED/) {
#handle quota exceeded here
$version->set_file1("");
$version->delete();
if ($filename eq 'USER_QUOTA_EXCEEDED') {
$self->print_click_back("Sorry", "You have exceeded your user file space quota. Remove some files from the server or ask the administrator for additional space.\n");
} else {
$self->print_click_back("Sorry", "You have exceeded the site-wide file space quota. Please remove some files from the server or ask the administrator for additional space.\n");
}
exit;
}
$version->save();
$self->set_current_version_iid($version->get_iid);
$self->set_checked_out_status("No");
# update the filename from the version
$self->{file1} = $filename;
$self->save();
$self->md_redirect("index.pl?iid=".$self->parent_id);
}
sub show_summary {
my $self = shift;
my $name = $self->get_name();
my $description = $self->get_description();
my $url = $self->get_url();
my $cool_icon = $self->get_cool_icon();
my $buttons = $self->get_buttons();
my $isa = $self->is_a();
my $iid = $self->id();
my $current_version_iid = $self->get_current_version_iid();
my $version = $self->get_version_object();
my $file_icon = $version->get_file_1_icon();
my $current_version = $self->get_current_version();
my $imageslocation = $PARAMS->{'imageslocation'};
my $html = '';
my $maxiLen = 60 ; # make a little smaller (need more general soln)
my $nameLen = length($name) ;
my $linkLen = length($url) ;
my $coolLen = ($cool_icon ne '') ? 10 : 0 ;
my $fileLen = ($file_icon ne '') ? 10 : 0 ;
my $fullLen = $nameLen + $linkLen + $coolLen + $fileLen ;
my $flgUrl = (defined($url) && $url ne '' && $url ne "http://") ;
# [vadim] upon Philippe's request
$description =~ s/\n/ /g ;
$html .= "
";
$html .= "
";
# cell #1 start
$html .= "
" ;
# cell #1 end
if ($buttons ne '') {
$html .= " $buttons" ;
}
$html .= "
";
return $html;
}
sub show_line {
my $self = shift;
my $name = $self->get_name();
my $description = $self->get_description();
my $url = $self->get_url();
my $file_icon = $self->get_file_1_icon();
my $cool_icon = $self->get_cool_icon();
my $buttons = $self->get_buttons();
my $html = '';
$html .= "$buttons $cool_icon $file_icon";
if (defined($url) && $url ne '' && $url ne "http://") {
$html .= "make_url($url)."\">$name\n";
} else {
$html .= $name . "\n";
}
$html .= $description;
return $html;
}
1;
__END__
=head1 NAME
Gizmo::CMSDoc - can either create a new Item (returing a pointer to the new object) or control
the way existing ones are displayed (returning the formatted HTML).
=head1 SYNOPSIS
use Gizmo::CMSDoc;
$cmsdoc = cmsdoc->new ($id);
$html = $cmsdoc->show ();
$html = $cmsdoc->show_as_bullet ();
$html = $cmsdoc->show_as_dash ();
$version = CMSDocument->get_version();
=head1 DESCRIPTION
cmsdoc is the basic building block for the Portal. Adding an cmsdoc allows the
user to create a link to a URL, and the user may also attach a file to an
cmsdoc.
=head1 Methods
Calling the new function instantiates a new cmsdoc or retrive its persistent info
from the backend database.
Class method to retrieve the version of the gizmo
$version = CMSDocument->get_version();
The remaining functions control how an cmsdoc is displayed:
$cmsdoc->show() displays an cmsdoc.
$cmsdoc->show_as_bullet() displays the cmsdoc as an cmsdoc in a bulleted list.
$cmsdoc_as_dash() show the cmsdoc with a dash in front of its name.
=cut