File Coverage

lib/Kwiki/Keywords.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Kwiki::Keywords;
2 1     1   25649 use Kwiki::Plugin '-Base';
  0            
  0            
3             use Kwiki::Installer '-base';
4              
5             const class_id => 'keywords';
6             const class_title => 'Keywords';
7             const cgi_class => 'Kwiki::CGI::Keywords';
8             const config_file => 'keywords.yaml';
9              
10             field keywords_directory => '-init' =>
11             '$self->plugin_directory . "/keywords"';
12             field pages_directory => '-init' =>
13             '$self->plugin_directory . "/pages"';
14              
15             our $VERSION = '0.14';
16              
17             sub init {
18             super;
19             return unless $self->is_in_cgi;
20             io($self->keywords_directory)->mkdir;
21             io($self->pages_directory)->mkdir;
22             }
23              
24             sub register {
25             my $registry = shift;
26             $registry->add(hook => 'page:store', post => 'add_automatic_keywords');
27             $registry->add(action => 'keyword_display');
28             $registry->add(action => 'keyword_add');
29             $registry->add(action => 'keyword_del');
30             $registry->add(action => 'keyword_list');
31             $registry->add(widget => 'keywords',
32             template => 'keywords_widget.html',
33             show_for => 'display',
34             );
35             $registry->add(widget => 'keywords_related',
36             template => 'keywords_related_widget.html',
37             show_for => 'keyword_display',
38             );
39             $registry->add(toolbar => 'keyword_list',
40             template => 'keyword_list_button.html'
41             );
42             }
43              
44             sub keywords_from_cgi {
45             my @keywords = split /\s+/, $self->cgi->keyword;
46             return \@keywords;
47             }
48              
49             sub keyword_add {
50             my $keywords = $self->keywords_from_cgi;
51             my $page = $self->hub->pages->new_from_name($self->cgi->page_name);
52             my $count = 1;
53             for my $keyword (@$keywords) {
54             next unless $keyword;
55             die "'$keyword' contains illegal characters"
56             unless $keyword =~ /^[\w\-]+$/;
57             $self->add_keyword($page, $keyword);
58             last if ++$count > 5; # sanity limit
59             }
60             $self->redirect($page->uri);
61             }
62              
63             sub keyword_del {
64             my $keyword = $self->cgi->keyword;
65             my $page = $self->hub->pages->new_from_name($self->cgi->page_name);
66             $self->del_keyword($page, $keyword);
67             $self->redirect($page->uri);
68             }
69              
70             sub keyword_display {
71             my $keywords = $self->keywords_from_cgi;
72             my $pages = $self->get_pages_for_keywords(@$keywords);
73             $self->render_screen(
74             screen_title => "Pages with keywords {@$keywords}",
75             pages => $pages,
76             )
77             }
78              
79             sub keyword_list {
80             my $keywords = $self->get_all_keywords;
81             my $blog = $self->hub->have_plugin('blog');
82             $self->template_process($self->screen_template,
83             content_pane => 'keyword_list.html',
84             screen_title => "All Keywords",
85             keywords => $keywords,
86             blog => $blog,
87             );
88             }
89              
90             sub get_all_keywords {
91             my $io = io($self->keywords_directory);
92             return [
93             sort {lc($a) cmp lc($b)}
94             grep {
95             scalar(@{$self->get_pages_for_keyword($_)})
96             }
97             map {
98             $_->filename
99             } $io->all
100             ];
101             }
102              
103             sub get_pages_for_keywords {
104             return $self->get_pages_for_keyword(@_) if @_ == 1;
105              
106             my %page;
107             foreach my $keyword (@_) {
108             foreach (@{ $self->get_pages_for_keyword($keyword) }) {
109             my $title = $_->title;
110             if ($page{$title}) { $page{$title}[1]++; next; }
111             else { $page{$title} = [ $_, 1 ]; }
112             }
113             }
114             return [ map { $_->[0] } grep { $_->[1] == @_ } values %page ];
115             }
116              
117             sub get_pages_for_keyword {
118             my $keyword = shift;
119             my $io = io($self->keywords_directory . "/$keyword");
120             my $pages = $io->exists
121             ? [ map {
122             $self->hub->pages->new_from_name($_->filename)
123             } grep $_, $io->all ]
124             : [];
125             return $pages;
126             }
127              
128             sub keywords_for_page {
129             my $page = shift;
130             my $io = io($self->pages_directory . "/$page");
131             my $keywords = $io->exists
132             ? [
133             map { $_->filename } sort {
134             $b->mtime <=> $a->mtime or
135             lc("$a") cmp lc("$b")
136             } $io->all
137             ]
138             : [];
139             return $keywords;
140             }
141              
142             sub keywords_for_current_page {
143             my $page = $self->hub->pages->current->id;
144             return $self->keywords_for_page($page);
145             }
146              
147             sub get_related_keywords {
148             my ($keywords) = @_;
149             my $pages = $self->get_pages_for_keywords(@$keywords);
150              
151             my %relations;
152             for (@$pages) {
153             my $page_keywords = $self->keywords_for_page($_->id);
154             for my $related (@$page_keywords) {
155             next if grep { $related eq $_ } @$keywords;
156             $relations{$related}++
157             }
158             }
159             return [ keys %relations ];
160             }
161              
162             sub add_automatic_keywords {
163             my $hook = pop;
164             my $pages = $self; # we're running in the class with class id page
165             $self = $self->hub->keywords; # move ourselves into this class
166             return if $self->hub->config->keywords_no_automatic;
167             $self->add_author_keyword;
168             }
169              
170             sub add_author_keyword {
171             my $author = $self->hub->users->current->name;
172             my $page = $self->hub->pages->current;
173             $self->add_keyword($page, $author) if $author;
174             }
175              
176             sub add_keyword {
177             my $page = shift;
178             my $keyword = shift;
179             return unless $page->is_writable;
180             my $id = $page->id;
181             io($self->keywords_directory . "/$keyword/$id")->assert->touch;
182             io($self->pages_directory . "/$id/$keyword")->assert->touch;
183             }
184              
185             sub del_keyword {
186             my $page = shift;
187             my $keyword = shift;
188             return unless $page->is_writable;
189             my $id = $page->id;
190             io($self->keywords_directory . "/$keyword/$id")->unlink;
191             io($self->pages_directory . "/$id/$keyword")->unlink;
192             }
193              
194             package Kwiki::CGI::Keywords;
195             use Kwiki::CGI -Base;
196              
197             cgi 'keyword';
198             cgi 'page_name';
199              
200             package Kwiki::Keywords;
201              
202             __DATA__