123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- # Copyright (C) 2006 Charles Mauch <cmauch@gmail.com>
- #
- # This program 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 3 of the License, or
- # (at your option) any later version.
- #
- # This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
- # Grab MLDBM at http://search.cpan.org/dist/MLDBM/lib/MLDBM.pm
- # ie: http://search.cpan.org/CPAN/authors/id/C/CH/CHAMAS/MLDBM-2.01.tar.gz
- use strict;
- use v5.10;
- use Fcntl;
- use MLDBM qw( DB_File Storable );
- AddModuleDescription('backlinkage.pl', 'Inline Backlinks');
- our ($q, %Action, %Page, @MyAdminCode, $DataDir, $LinkPattern);
- my $debug=1; # Set Text Output Verbosity when compiling
- my $backfile = $DataDir . '/backlinks.db'; # Where data lives
- # Stuff buildback action into admin menu.
- push(@MyAdminCode, \&BacklinksMenu);
- sub BacklinksMenu {
- my ($id, $menuref, $restref) = @_;
- push(@$menuref,
- ScriptLink('action=buildback', T('Rebuild BackLink database'))
- );
- }
- # Build Database, called my oddmuse uri action
- $Action{buildback} = \&BuildBacklinkDatabase;
- sub BuildBacklinkDatabase {
- print GetHttpHeader('text/plain');
- Unlink($backfile); # Remove old database
- tie my %backhash, 'MLDBM', encode_utf8($backfile) or die "Cannot open file $backfile $!\n";
- log1("Starting Database Store Process ... please wait\n\n");
- foreach my $name (AllPagesList()) {
- log3("Opening $name ... \n");
- OpenPage($name);
- my @backlinks = BacklinkProcess($name,$Page{text});
- my $hash = $backhash{$name}; # Declare Hash Ref
- my $backlinkcount = 0; # Used to create link key
- foreach my $link (@backlinks) {
- $backlinkcount++;
- $hash->{'link' . $backlinkcount} = $link;
- }
- log2("$backlinkcount Links found in $name\n") if $backlinkcount;
- $backhash{$name} = $hash; # Store Hash data in HoH
- }
- if ($debug >= 3) {
- log4("Printing dump of USABLE Data we stored, sorted and neat\n");
- for my $source (sort keys %backhash) {
- for my $role (sort keys %{ $backhash{$source} }) {
- log4("\n\$HoH\{\'$source\'\}\{\'$role\'\} = \"$backhash{$source}{$role}\"");
- }
- }
- }
- untie %backhash;
- log1("Done. \n");
- }
- # Used to filter though page text to find links, ensure there is only 1 link per destination
- # per page, and then return an array of backlinks.
- sub BacklinkProcess {
- my $name = $_[0];
- my $text = $_[1];
- my %seen = ();
- my @backlinks;
- my @wikilinks = ($text =~ m/$LinkPattern/g);
- foreach my $links (@wikilinks) {
- my ($class, $resolved, $title, $exists) = ResolveId($links);
- if ($exists) {
- push (@backlinks,$resolved) unless (($seen{$resolved}++) or ($resolved eq $name));
- }
- }
- return @backlinks;
- }
- # Function used by user to display backlinks in proper html.
- sub GetBackLink {
- my (@backlinks, @unpopped, @alldone);
- my $id = $_[0];
- our ($BacklinkBanned);
- $BacklinkBanned = "HomePage|ScratchPad" if !$BacklinkBanned;
- tie my %backhash, 'MLDBM', encode_utf8($backfile), O_CREAT|O_RDWR, oct(644) or die "Cannot open file $backfile $!\n";
- # Search database for matches
- while ( my ($source, $hashes) = each %backhash ) {
- while ( my ($key, $value) = each %$hashes ) {
- if ($id =~ /$value/) {
- push (@backlinks, $source);
- }
- }
- }
- untie %backhash;
- # Render backlinks into html links
- foreach my $backlink (@backlinks) {
- my ($class, $resolved, $title, $exists) = ResolveId($backlink);
- if (($resolved ne $id) && ($resolved !~ /^($BacklinkBanned)$/)) {
- push(@unpopped, ScriptLink(UrlEncode($resolved), $resolved, $class . ' backlink', undef, Ts('Internal Page: %s', $resolved)));
- }
- }
- my $arraycount = @unpopped;
- return if !$arraycount; # Dont bother with the rest if empty results
- # Pop and Push data to make it look good (no trailing commas)
- my $temp = pop(@unpopped);
- foreach my $backlink (@unpopped) {
- push(@alldone, $backlink . ", ");
- }
- push(@alldone, $temp); # And push last entry back in
- print $q->div({-class=>'docmeta'}, $q->h2(T('Pages that link to this page')), @alldone);
- }
- # Debug functions, all expect a string as input, and print it if the debug level is high enough.
- # This allows for increasing levels of verbosity for runtime commenting.
- sub log1 { # Very little info (only outputs if error - great for scripts)
- return if (($debug < 1) or ($debug == 4));
- my $msg = shift;
- print "$msg";
- }
- sub log2 { # Info Messages
- return if (($debug < 2) or ($debug == 4));
- my $msg = shift;
- print "$msg";
- }
- sub log3 { # More Info for the curious
- return if (($debug < 3) or ($debug == 4));
- my $msg = shift;
- print "$msg";
- }
- sub log4 { # Dump all sorts of garbage (usally data structures)
- return if ($debug < 4);
- my $msg = shift;
- print "$msg";
- }
|