# # (C)2001-2002 Projecto Natura # package Biblio::Catalog::News; use Biblio::Catalog; use CGI qw/:standard/; use XML::DT ; require v5.6.0; use strict; use warnings; require Exporter; # Module Stuff our @ISA = qw/Exporter Biblio::Catalog/; our %EXPORT_TAGS = ( all => [ qw// ]); our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} }); our @EXPORT = qw/ /; # Version our $VERSION = '0.02'; our @REQ_FIELDS = ( qw/date title/ ); our @KNOWN_FIELDS = ( @REQ_FIELDS, qw/time url description author/ ); # First argument is a reference to the list of items we want on the # catalog of news. sub new { my $class = shift; my $fields = shift; my %tmp = (); @tmp{@$fields} = @$fields; my $self = { FIELDS => \%tmp }; for (@REQ_FIELDS) { $self->{FIELDS}{$_} = $_; } return bless $self, $class; } sub simple_attr { my $record = shift; my $key = shift; if (exists($record->{$key})) { if ($key eq "time") { return sprintf("%d:%02d", $record->{time}{hour},$record->{time}{minutes}); } elsif ($key eq "date") { return sprintf("%d-%02d-%02d", $record->{date}{year},$record->{date}{month},$record->{date}{day}); } else { return $record->{$key} } } else { return ""; } } sub asHTML { my $record = shift; return apply_template($record, def_template($record)); } sub asText { my $record = shift; my $answer = ""; for (keys %$record) { next if ref($_); $answer.=$_; } return $answer; } sub asRelations { my $record = shift; return (); } # This works for _ALL_ records... sub as_HTML { my $self = shift; my $count = shift || -1; ## Here we really mean || (not // on perl 6) my $template = shift; my $ssub; if (exists($self->{time})) { $ssub = sub { my $sb = sprintf("%d%2d%2d%2d%2d", $b->{date}{year},$b->{date}{month},$b->{date}{day}, $b->{time}{hour},$b->{time}{minutes}); my $sa = sprintf("%d%2d%2d%2d%2d", $a->{date}{year},$a->{date}{month},$a->{date}{day}, $a->{time}{hour},$a->{time}{minutes}); $sb =~ s/\s/0/g; $sa =~ s/\s/0/g; $sb <=> $sa } } else { $ssub = sub { my $sb = sprintf("%d%2d%2d", $b->{date}{year},$b->{date}{month},$b->{date}{day}); my $sa = sprintf("%d%2d%2d", $a->{date}{year},$a->{date}{month},$a->{date}{day}); $sb =~ s/\s/0/g; $sa =~ s/\s/0/g; $sb <=> $sa } } # we ensure all records are equal, so... :) $template = def_template($self->{DATA}[0]) unless defined $template; my $HTML = "\n"; for my $new ( sort $ssub @{$self->{DATA}}) { last unless $count; $count--; $HTML .= apply_template($new, $template); } # if (exists($self->{ENCODING})) { # return lat1::utf8($HTML); # } else { return $HTML; # } } sub apply_template { my ($record, $template) = @_; my $tmp = $template; while ($template =~ m!\[([A-Z]+)(\.([A-Z]+))?\]!g) { my $name = $1; if ($2) { my $name2 = $3; $tmp =~ s/\[$name\.$name2\]/$record->{lc($name)}{lc($name2)} || ""/e; } else { $tmp =~ s/\[$name\]/simple_attr($record,lc($name))/e; } } return $tmp; } sub def_template { my $record = shift; my $tmpl = ""; my $author = ""; $author = "([AUTHOR]) - " if exists $record->{author}; my $title = "$author"; if (exists($record->{url})) { $title.= "[TITLE]"; } else { $title.= "[TITLE]"; } if (exists($record->{time})) { $title = "[DATE] [TIME] - $title"; } else { $title = "[DATE] - $title"; } if (exists($record->{description})) { return "$title
[DESCRIPTION]
\n"; } else { return $title; } } sub load { my $class = shift; my $filename = shift; my %handler=( '-default' => sub { $c }, '-type' => { fields => 'SEQ', date => 'MAP', data => 'SEQ', time => 'MAP', new => 'MAP', news => 'MAP', meta => 'MAP', }, 'news' => sub{ $c->{ENCODING} = $c->{meta}{encoding} if exists($c->{meta}{encoding}); $c->{DATA} = $c->{data}; delete($c->{data}); $c->{FIELDS} = $c->{meta}{fields}; delete($c->{meta}{fields}); delete($c->{meta}); return $c; }, 'fields' => sub{ my %h = (); @h{@$c}=@$c; return \%h }, ); return bless(dt($filename,%handler),$class); } sub asList { my $self = shift; return @{$self->{DATA}}; } # Save to an XML file. sub save { my $self = shift; my $filename = shift; open XML, ">$filename" or die "Cannot open file $filename: $!"; ## Print print XML "{ENCODING}\"" if exists $self->{ENCODING}; print XML "?>\n"; print XML "\n"; ## Now, print info print XML " \n"; print XML " $self->{ENCODING}\n" if exists $self->{ENCODING}; print XML " \n"; for (sort keys %{$self->{FIELDS}}) { print XML " $_\n"; } print XML " \n"; print XML " \n"; ## Aux function for recursive dump. sub dump_data { my ($spaces, $tag, $hash) = @_; print XML "$spaces<$tag>\n"; for my $k (sort keys %$hash) { if (ref($hash->{$k}) eq "HASH") { dump_data(" ".$spaces, $k, $hash->{$k}); } else { print XML " $spaces<$k>$hash->{$k}\n"; } } print XML "$spaces\n"; } print XML " \n"; for (@{$self->{DATA}}) { dump_data(' ','new', $_); } print XML " \n"; print XML "\n"; close XML; } # add records. Each record is a map from keywords to respective # data. If any required field is missing, that record is not added. sub add { my $self = shift; RECORD: for my $record (@_) { # Check if it is an hash reference next unless ref $record eq "HASH"; # Treat TIME if (exists($self->{FIELDS}{time})) { if (exists($record->{time})) { $record->{time} = make_time($record->{time}) } else { $record->{time} = today_time() } } # Treat DATE if (exists($record->{date})) { $record->{date} = make_date($record->{date}) } else { $record->{date} = today_date(); } # Check REQUIRED FIELDS for (@REQ_FIELDS) { next RECORD unless exists($record->{$_}); } # Remove unwanted fields for (keys %{$record}) { delete $record->{$_} unless exists $self->{FIELDS}{$_}; } # Add undefined fields for (keys %{$self->{FIELDS}}) { $record->{$_} = " " unless exists $record->{$_}; } push @{$self->{DATA}}, $record; } } sub make_time { my $time = shift; my $new = {}; if ($time =~ m!^(\d?\d):?(\d\d)$!) { $new -> {hour} = $1; $new -> {minutes} = $2; } else { $new = today_time(); } return $new; } sub make_date { my $date = shift; my $new = {}; if ($date =~ m!^(\d\d\d\d)[-./]?(\d\d)[-./]?(\d\d)$!) { $new->{day} = $3; $new->{month} = $2; $new->{year} = $1; } elsif ($date =~ m!^(\d\d)[-./](\d\d)[-./](\d\d\d\d)$!) { $new->{day} = $1; $new->{month} = $2; $new->{year} = $3; } else { $new = today_date(); } return $new; } sub today_date { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = localtime(time); return { day => $mday, month => $mon+1, year => $year+1900 }; } sub today_time { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = localtime(time); return { hour => $hour, minutes => $min, }; } sub add_as_HTML { my $self = shift; my $parms = shift; my $conf = shift; my $HTML = ""; if (exists($parms->{date})) { if (exists($conf->{authfile})) { my $username; my $password; if (exists($self->{FIELDS}{author})) { $username = $parms->{author}; } else { $username = $parms->{username}; } $password = $parms->{passwd}; unless ( open X, "<$conf->{authfile}" ) { print "Cannot open passwd file"; exit; } while() { chomp; m!^(\S+)\s+(\S+)$!; my ($u,$p) = ($1,$2); if ($u eq $username) { if (crypt($password, $p) eq $p) { $self->add($parms); $self->save($conf->{outfile} || "novidades.xml"); $HTML .= "New added!"; last; } } } if ($HTML eq "") { $HTML .= "Authorization failed"; } } else { $self->add($parms); $self->save($conf->{outfile} || "novidades.xml"); $HTML .= "New added!"; } } else { my $date = today_date; $date = "$date->{year}-$date->{month}-$date->{day}"; my $time = today_time; $time = "$time->{hour}:$time->{minutes}"; $HTML.= start_multipart_form(); $HTML.= "
\n Date\n"; $HTML.= " \n"; $HTML.= "$date\n
\n"; if ($self->{FIELDS}{time}) { $HTML.= "
\n Time\n"; $HTML.= " \n"; $HTML.= "$time\n
\n"; } $HTML.= "
\n Title\n"; $HTML.= " \n"; $HTML.= "
\n"; for (keys %{$self->{FIELDS}}) { next if $_ eq "time" or $_ eq "date" or $_ eq "title"; $HTML.= "
\n ".ucfirst($_)."\n"; if ($_ eq "description") { $HTML.= " \n"; } else { $HTML.= " \n"; } $HTML.= "
\n"; } if (exists($conf->{authfile})) { unless (exists($self->{FIELDS}{author})) { $HTML.= "
\n Username\n"; $HTML.= " \n"; $HTML.= "
\n"; } $HTML.= "
\n Password\n"; $HTML.= " \n"; $HTML.= "
\n"; } $HTML.=" \n"; $HTML.="\n"; } return $HTML; } 1; __END__ =head1 NAME Biblio::Catalog::News - Perl extension for managing XML News as a catalog =head1 SYNOPSIS use Biblio::Catalog::News; $new_cat = Biblio::Catalog::News->new([ qw/author title date time/ ]); $new_cat->add( { title => "title" }, { title => "title2" } ); $new_cat->save( $filename ); $other_cat = Biblio::Catalog::News->load( $filename ); $other_cat->as_HTML( $count, $template ); @records = $other_cat->asList(); =head1 DESCRIPTION This module creates an XML file of news. This file will be handled as a catalog as described by Biblio::Catalog. The news file is a set of records. Each record consists of some data fields. This module assumes some fields as possible fields. Some are required and some are optional, and can be defined in the constructor in any order you would like. =head2 Fields Valid fields in the news file are: =over 4 =item C As any new you can imagine, there is necessary a date. This date consists of a day, month and year. It is B. =item C