Files
selima-perl/htdocs/emandy/magicat/lib/perl5/Selima/emandy/Rebuild.pm
2026-03-10 21:31:43 +08:00

437 lines
14 KiB
Perl

# Mandy Wu's Website
# Rebuild.pm: The subroutines to rebuild the web pages.
# Copyright (c) 2006-2018 imacat.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Author: imacat <imacat@mail.imacat.idv.tw>
# First written: 2006-11-14
package Selima::emandy::Rebuild;
use 5.008;
use strict;
use warnings;
use base qw(Exporter);
use vars qw(@EXPORT @EXPORT_OK);
BEGIN {
@EXPORT = qw(rebuild_all rebuild_pages rebuild_links rebuild_legend compose_page);
@EXPORT_OK = @EXPORT;
# Prototype declaration
sub rebuild_all();
sub rebuild_pages(;$);
sub rebuild_links(;$);
sub rebuild_legend(;$);
sub compose_page($;$);
}
use Config qw(%Config);
use Data::Dumper qw();
use Fcntl qw(:flock);
use File::Basename qw(basename);
use IO::NestedCapture qw(CAPTURE_STDOUT);
use Lingua::ZH::Numbers;
use Selima::DataVars qw($DBH :output :rebuild :requri);
use Selima::GetLang;
use Selima::Guest;
use Selima::PageFunc;
use Selima::ShortCut;
use Selima::emandy::HTML;
use vars qw($PKGL10N);
# rebuild_all: Rebuild everything
sub rebuild_all() {
local ($_, %_);
# Lock the required tables
$DBH->lock(map { $_ => LOCK_SH } @REBUILD_TABLES);
# Rebuild the pages
rebuild_pages;
# Rebuild the links
rebuild_links;
# Rebuild the legend
rebuild_legend;
# Rebuild the index
# To be done
#rebuild_index;
return;
}
# rebuild_pages: Rebuild the pages
sub rebuild_pages(;$) {
local ($_, %_);
my ($sql, $sth, $count, $rebuild_everything);
my $lang;
$sql = $_[0];
$lang = getlang;
# Rebuild everything
$rebuild_everything = !defined $sql;
if ($rebuild_everything) {
$sql = "SELECT * FROM pages"
. " WHERE NOT hid;\n";
}
$sth = $DBH->prepare($sql);
$sth->execute;
$count = $sth->rows;
# Bounce if no pages to build on a partial rebuild
# This prevents needless sitemap rebuilding
return if !$rebuild_everything && $count == 0;
# Build each page
for (my $i = 0; $i < $count; $i++) {
my ($page, $html);
$page = $sth->fetchrow_hashref;
# Read the picture into the picture deposit
# To be done
$html = compose_page($page, $lang);
goutpage $html, $$page{"path"}, $lang
if defined $html;
# Output related pictures only when rebuilding everything
# To be done
}
return;
}
# rebuild_links: Rebuild the links
sub rebuild_links(;$) {
local ($_, %_);
my ($sql, $sth, $count, $FD, $rebuild_everything);
my ($lang, $args, $html);
$sql = $_[0];
$lang = getlang;
# Rebuild everything
$rebuild_everything = !defined $sql;
if ($rebuild_everything) {
@_ = $DBH->cols("linkcat");
push @_, $DBH->strcat("'/links'", "linkcat_path(sn, id, parent)")
. " AS path";
$sql = "SELECT " . join(", ", @_) . " FROM linkcat"
. " WHERE linkcat_isshown(sn, hid, parent);\n";
}
$sth = $DBH->prepare($sql);
$sth->execute;
$count = $sth->rows;
for (my $i = 0; $i < $count; $i++) {
my ($page, $sql1, $sth1, $count1, $row1);
$page = $sth->fetchrow_hashref;
# Find the ancesters
@_ = $DBH->cols("linkcat");
push @_, $DBH->strcat("'/links'", "linkcat_path(sn, id, parent)")
. " AS path";
$sql1 = "SELECT " . join(", ", @_) . " FROM linkcat"
. " WHERE linkcat_ischild(sn, " . $$page{"sn"} . ")"
. " ORDER BY linkcat_fullord(parent, ord);\n";
$sth1 = $DBH->prepare($sql1);
$sth1->execute;
$count1 = $sth1->rows;
for (my $i = 0, $$page{"parents"} = []; $i < $count1; $i++) {
push @{$$page{"parents"}}, $sth1->fetchrow_hashref;
}
# Find the subcategories
@_ = $DBH->cols("linkcat");
push @_, $DBH->strcat("'/links'", "linkcat_path(sn, id, parent)")
. " AS path";
$sql1 = "SELECT " . join(", ", @_) . " FROM linkcat"
. " WHERE parent=" . $$page{"sn"}
. " AND linkcat_isshown(sn, hid, parent)"
. " ORDER BY ord;\n";
$sth1 = $DBH->prepare($sql1);
$sth1->execute;
$count1 = $sth1->rows;
for (my $i = 0, $$page{"scats"} = []; $i < $count1; $i++) {
my ($sql2, $sth2, $row2);
$row1 = $sth1->fetchrow_hashref;
# Find the belonging links
$sql2 = "SELECT count(linkcatz.sn) AS count FROM linkcatz"
. " INNER JOIN links ON linkcatz.link=links.sn"
. " INNER JOIN linkcat ON linkcatz.cat=linkcat.sn"
. " WHERE linkcatz.cat=" . $$row1{"sn"}
. " AND NOT links.hid;\n";
$sth2 = $DBH->prepare($sql2);
$sth2->execute;
$row2 = $sth2->fetchrow_hashref;
$$row1{"links"} = $$row2{"count"};
push @{$$page{"scats"}}, $row1;
}
# Find the belonging links
@_ = map "links.$_", $DBH->cols("links");
$sql1 = "SELECT " . join(", ", @_) . " FROM links"
. " INNER JOIN linkcatz ON linkcatz.link=links.sn"
. " WHERE linkcatz.cat=" . $$page{"sn"}
. " AND NOT links.hid;\n";
$sth1 = $DBH->prepare($sql1);
$sth1->execute;
$count1 = $sth1->rows;
for (my $i = 0, $$page{"links"} = []; $i < $count1; $i++) {
push @{$$page{"links"}}, $sth1->fetchrow_hashref;
}
$html = compose_page($page, $lang);
goutpage $html, $$page{"path"}, $lang
if defined $html;
}
# Build the root index page
@_ = $DBH->cols("linkcat");
push @_, $DBH->strcat("'/links'", "linkcat_path(sn, id, parent)")
. " AS path";
$sql = "SELECT " . join(", ", @_) . " FROM linkcat"
. " WHERE parent IS NULL"
. " AND linkcat_isshown(sn, hid, parent)"
. " ORDER BY ord;\n";
$sth = $DBH->prepare($sql);
$sth->execute;
$count = $sth->rows;
for ($_ = 0, @_ = qw(); $_ < $count; $_++) {
my ($cat, $sql1, $sth1, $count1);
$cat = $sth->fetchrow_hashref;
# Find the belonging links
$sql1 = "SELECT count(linkcatz.sn) AS count FROM linkcatz"
. " INNER JOIN links ON linkcatz.link=links.sn"
. " INNER JOIN linkcat ON linkcatz.cat=linkcat.sn"
. " WHERE linkcatz.cat=" . $$cat{"sn"}
. " AND NOT links.hid;\n";
$sth1 = $DBH->prepare($sql1);
$sth1->execute;
$$cat{"links"} = ${$sth1->fetch}[0];
push @_, $cat;
}
$ALT_PAGE_PARAM = {
"path" => "/links/",
"lang" => $lang,
"keywords" => __("related links"),
"class" => "links",
"static" => 1,
"all_linguas" => [$lang]};
$args = page_param;
# Obtain the page
IO::NestedCapture->start(CAPTURE_STDOUT);
binmode IO::NestedCapture->instance->{"STDOUT_current"}[-1], ":utf8";
html_header __("Related Links"), $args;
html_links_index @_, $args;
html_footer $args;
IO::NestedCapture->stop(CAPTURE_STDOUT);
$FD = IO::NestedCapture->get_last_out;
$html = join "", <$FD>;
undef $ALT_PAGE_PARAM;
goutpage $html, "/links/", $lang;
return;
}
# rebuild_legend: Rebuild the legend
sub rebuild_legend(;$) {
local ($_, %_);
my ($start, $sql, $sth, $count, $FD, $page, @pages, $total);
my ($lang, $args, $html);
$start = $_[0];
$start = 1 if !defined $start;
$lang = getlang;
# Obtain the total number of legend entries
$_ = "SELECT count(*) FROM legend WHERE NOT hid;\n";
$sth = $DBH->prepare($_);
$sth->execute;
$total = ${$sth->fetch}[0];
# Obtain all the available pages numbers
@_ = qw();
push @_, "pageno AS no";
push @_, "legend_page_start(pageno) AS start";
push @_, "legend_page_end(pageno) AS end";
$sql = "SELECT " . join(", ", @_) . " FROM legend"
. " WHERE NOT hid GROUP BY pageno ORDER BY pageno;\n";
$sth = $DBH->prepare($sql);
$sth->execute;
$count = $sth->rows;
for (my $i = 0, @pages = qw(); $i < $count; $i++) {
$page = $sth->fetchrow_hashref;
$$page{"path"} = sprintf "/legend/%04d.html", $$page{"no"};
push @pages, $page;
}
# Build each page
foreach my $page (@pages) {
next if $$page{"no"} < $start;
my ($args, $LIST, $html, $FD);
Lingua::ZH::Numbers->charset("traditional");
$_ = number_to_zh($$page{"no"});
$$page{"title"} = sprintf __("Legend Volume %s"), $_;
$$page{"kw"} = __("legend");
$ALT_PAGE_PARAM = {
"path" => $$page{"path"},
"lang" => $lang,
"keywords" => $$page{"kw"},
"class" => "legend",
"static" => 1,
"all_linguas" => [$lang]};
$args = page_param;
# Set the list parameter
$LIST = new Selima::emandy::List::Legend::Public;
$LIST->{"view"} = "legend_public";
$LIST->{"pageno"} = $$page{"no"};
$LIST->{"lastpage"} = ${$pages[$#pages]}{"no"};
$LIST->{"total"} = $total;
$args = {%$args, %{$LIST->page_param}};
# Obtain the page
IO::NestedCapture->start(CAPTURE_STDOUT);
binmode IO::NestedCapture->instance->{"STDOUT_current"}[-1], ":utf8";
html_header $$page{"title"}, $args;
$LIST->html($args);
html_footer $args;
IO::NestedCapture->stop(CAPTURE_STDOUT);
$FD = IO::NestedCapture->get_last_out;
$html = join "", <$FD>;
undef $ALT_PAGE_PARAM;
goutpage $html, $$page{"path"}, $lang;
# Make the symbolic link for the default language
if (defined $Config{"d_symlink"}) {
my ($targfile, $linkfile);
$_ = $$page{"path"};
$_ .= "index.html" if /\/$/;
$targfile = basename($_ . ".xhtml");
$linkfile = "$DOC_ROOT$_.html";
unless (-l $linkfile && readlink $linkfile eq $targfile) {
unlink $linkfile if -l $linkfile;
symlink $targfile, $linkfile;
}
}
}
# Make the symbolic link for the latest page
if (defined $Config{"d_symlink"}) {
my ($targfile, $linkfile);
if (@pages > 0) {
$targfile = sprintf "%04d.html.xhtml",
${$pages[$#pages]}{"no"};
} else {
$targfile = "index.html.xhtml";
}
$linkfile = "$DOC_ROOT/legend/latest.html.xhtml";
unless (-l $linkfile && readlink $linkfile eq $targfile) {
unlink $linkfile if -l $linkfile;
symlink $targfile, $linkfile;
}
$targfile = "latest.html.xhtml";
$linkfile = "$DOC_ROOT/legend/latest.html.html";
unless (-l $linkfile && readlink $linkfile eq $targfile) {
unlink $linkfile if -l $linkfile;
symlink $targfile, $linkfile;
}
}
# Build the root index page
$ALT_PAGE_PARAM = {
"path" => "/legend/",
"lang" => $lang,
"keywords" => __("legend"),
"class" => "legend",
"static" => 1,
"all_linguas" => [$lang],
"toc" => ".."};
if (@pages > 0) {
$$ALT_PAGE_PARAM{"first"} = "0001.html";
$$ALT_PAGE_PARAM{"last"} = "latest.html";
${$pages[$#pages]}{"path"} = "/legend/latest.html";
}
$args = page_param;
# Obtain the page
IO::NestedCapture->start(CAPTURE_STDOUT);
binmode IO::NestedCapture->instance->{"STDOUT_current"}[-1], ":utf8";
html_header __("Legend"), $args;
html_legend_index @pages, $args;
html_footer $args;
IO::NestedCapture->stop(CAPTURE_STDOUT);
$FD = IO::NestedCapture->get_last_out;
$html = join "", <$FD>;
undef $ALT_PAGE_PARAM;
goutpage $html, "/legend/", $lang;
# Make the symbolic link for the default language
if (defined $Config{"d_symlink"}) {
my ($targfile, $linkfile);
$_ = "/legend/index.html";
$targfile = basename($_ . ".xhtml");
$linkfile = "$DOC_ROOT$_.html";
unless (-l $linkfile && readlink $linkfile eq $targfile) {
unlink $linkfile if -l $linkfile;
symlink $targfile, $linkfile;
}
}
return;
}
# compose_page: Compose a page
sub compose_page($;$) {
local ($_, %_);
my ($page, $lang, $args, $FD);
($page, $lang) = @_;
$lang = getlang if !defined $lang;
$ALT_PAGE_PARAM = {
"path" => $$page{"path"},
"lang" => $lang,
"keywords" => $$page{"kw"},
"static" => 1,
"all_linguas" => [$lang]};
$$ALT_PAGE_PARAM{"preview"} = $page
if exists $$page{"preview"};
if (exists $$page{"class"} && defined $$page{"class"} && $$page{"class"} ne "") {
$$ALT_PAGE_PARAM{"class"} = $$page{"class"};
} elsif ($$page{"path"} =~ /^\/links\//) {
$$ALT_PAGE_PARAM{"class"} = "links";
}
$args = page_param;
# Obtain the page
IO::NestedCapture->start(CAPTURE_STDOUT);
binmode IO::NestedCapture->instance->{"STDOUT_current"}[-1], ":utf8";
html_header $$page{"title"}, $args;
if ($$page{"path"} =~ /^\/links\/$/) {
#html_links_index $page, $args;
} elsif ($$page{"path"} =~ /^\/links\/.+$/) {
html_links $page, $args;
} else {
html_body $page, $args;
}
html_footer $args;
IO::NestedCapture->stop(CAPTURE_STDOUT);
$FD = IO::NestedCapture->get_last_out;
$_ = join "", <$FD>;
undef $ALT_PAGE_PARAM;
return $_;
}
return 1;