burguillos.info/lib/BurguillosInfo/Posts.pm

197 lines
6.1 KiB
Perl

package BurguillosInfo::Posts;
use v5.34.1;
use strict;
use warnings;
use feature 'signatures';
use Data::Dumper;
use MIME::Base64;
use BurguillosInfo::Categories;
use Const::Fast;
use Mojo::DOM;
use Path::Tiny;
use DateTime::Format::ISO8601;
use DateTime;
use BurguillosInfo::Preview;
const my $CURRENT_FILE => __FILE__;
const my $ROOT_PROJECT => path($CURRENT_FILE)->parent->parent->parent;
const my $PUBLIC_DIR => $ROOT_PROJECT->child('public');
const my $POSTS_DIR => $ROOT_PROJECT->child('content/posts');
my $cached_posts_by_category;
my $cached_posts_by_slug;
sub new {
return bless {}, shift;
}
sub _ReturnCacheFilter {
my $self = shift;
my %posts_by_category_filtered;
my %posts_by_slug_filtered;
my $iso8601 = DateTime::Format::ISO8601->new;
my $current_date = DateTime->now;
for my $category ( keys %$cached_posts_by_category ) {
for my $post ( @{ $cached_posts_by_category->{$category} } ) {
my $date_post;
eval {
$date_post = $iso8601->parse_datetime( $post->{date} );
};
if ($@) {
print Data::Dumper::Dumper $post;
}
if ( $date_post > $current_date ) {
next;
}
$posts_by_slug_filtered{ $post->{slug} } = $post;
$posts_by_category_filtered{ $post->{category} } //= [];
push @{ $posts_by_category_filtered{ $post->{category} } }, $post;
}
}
return ( \%posts_by_category_filtered, \%posts_by_slug_filtered );
}
sub _GeneratePostFromFile ( $self, $post_file ) {
warn "Bad file $post_file, omiting...", return
if !-f $post_file || $post_file !~ /\.xml$/;
my $dom = Mojo::DOM->new( $post_file->slurp_utf8 );
my $title = $dom->at(':root > title')->text
or die "Missing title at $post_file.";
my $author = $dom->at(':root > author')->text
or die "Missing author at $post_file.";
my $date = $dom->at(':root > date')->text
or die "Missing date at $post_file.";
my $ogdesc = $dom->at(':root > ogdesc')->text
or die "Missing ogdesc at $post_file";
my $category = $dom->at(':root > category')->text
or die "Missing category at $post_file.";
my $slug = $dom->at(':root > slug')->text
or die "Missing slug at $post_file.";
my $content = $dom->at(':root > content')->content
or die "Missing content at $post_file.";
my $image_element = $dom->at(':root > img');
my $image;
my $attributes = $self->_GetAttributes($post_file, $dom);
if ( defined $image_element ) {
$image = $image_element->attr->{src};
}
my $last_modification_date_element =
$dom->at(':root > last_modification_date');
my $last_modification_date;
if ( defined $last_modification_date_element ) {
$last_modification_date = $last_modification_date_element->content;
}
return {
title => $title,
author => $author,
date => $date,
ogdesc => $ogdesc,
category => $category,
slug => $slug,
content => $content,
(
( defined $last_modification_date )
? ( last_modification_date => $last_modification_date )
: ()
),
( ( defined $image ) ? ( image => $image ) : () ),
attributes => $attributes,
};
}
sub _GetAttributes($self, $post_file, $dom) {
my $attributes_tag = $dom->at(':root > attributes');
my %attributes;
if (defined $attributes_tag) {
my @attribute_list = $attributes_tag->find('attributes > attribute')->map('text')->each;
%attributes = map {
my $identifier = $_;
($identifier => 1);
} @attribute_list;
}
return \%attributes;
}
sub _GeneratePostCache ($self) {
$cached_posts_by_category = {};
$cached_posts_by_slug = {};
for my $post_file ( sort { $b cmp $a } $POSTS_DIR->children ) {
my $post = $self->_GeneratePostFromFile($post_file);
if (!defined $post) {
next;
}
my $category = $post->{category};
$cached_posts_by_category->{$category} //= [];
my $slug = $post->{slug};
my $category_posts = $cached_posts_by_category->{$category};
$cached_posts_by_slug->{$slug} = $post;
push @$category_posts, $post;
}
}
sub Retrieve {
my $self = shift;
if ( defined $cached_posts_by_category && defined $cached_posts_by_slug ) {
return $self->_ReturnCacheFilter;
}
$self->_GeneratePostCache();
return $self->_ReturnCacheFilter;
}
my $cache_all_post_categories = {};
sub RetrieveAllPostsForCategory ( $self, $category_name ) {
if (defined $cache_all_post_categories->{$category_name}) {
return $cache_all_post_categories->{$category_name};
}
my $categories = BurguillosInfo::Categories->new->Retrieve;
my $category = $categories->{$category_name};
my $posts = $self->RetrieveDirectPostsForCategory($category_name);
for my $child_category ( $category->{children}->@* ) {
my $child_category_name = $child_category->{slug};
push @$posts,
@{$self->RetrieveDirectPostsForCategory($child_category_name)};
}
@$posts = sort {
DateTime::Format::ISO8601->parse_datetime($b->{date}) <=>
DateTime::Format::ISO8601->parse_datetime($a->{date})
} @$posts;
$cache_all_post_categories->{$category_name} = $posts;
return $posts;
}
sub RetrieveDirectPostsForCategory ( $self, $category_name ) {
my ($post_by_category) = $self->Retrieve;
my $categories = BurguillosInfo::Categories->new->Retrieve;
my $category = $categories->{$category_name};
if ( !defined $category ) {
die "$category_name category does not exists";
}
my $posts = $post_by_category->{$category_name};
$posts //= [];
return [@$posts];
}
sub PreviewOg {
my $self = shift;
my $post = shift;
my $title = $post->{title};
my $content = $post->{content};
my $image_file = $post->{image};
return BurguillosInfo::Preview->Generate($title, $content, $image_file);
}
1;