File Coverage

blib/lib/Dwimmer.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 Dwimmer;
2 1     1   856 use Dancer ':syntax';
  0            
  0            
3              
4             use 5.008005;
5              
6             our $VERSION = '0.32';
7              
8             use Data::Dumper qw(Dumper);
9             use Dwimmer::DB;
10             use Dwimmer::Tools qw(_get_db _get_site _get_redirect read_file $SCHEMA_VERSION);
11              
12             use Encode qw(decode);
13             use Fcntl qw(:flock);
14             use List::Util qw(min);
15             use Template;
16             use XML::RSS;
17              
18             load_app 'Dwimmer::Admin', prefix => "/_dwimmer";
19              
20             # list of pages that can be accessed withot any login
21             my %open = map { $_ => 1 } qw(
22             /poll
23             /_dwimmer/login.json
24             /_dwimmer/session.json
25             /_dwimmer/register_email.json /_dwimmer/register_email
26             /_dwimmer/validate_email.json /_dwimmer/validate_email
27             );
28              
29             hook before => sub {
30             my $path = request->path_info;
31              
32             # debug(request->uri);
33              
34             my $db = _get_db();
35             my ($version) = $db->storage->dbh->selectrow_array('PRAGMA user_version');
36              
37             #see also do_dbh https://metacpan.org/module/DBIx::Class::Storage::DBI#dbh_do
38             if ( $version != $SCHEMA_VERSION ) {
39             return halt("Database is currently at version $version while we need version $SCHEMA_VERSION");
40             }
41             my ( $host, $url ) = _get_redirect();
42             if ($host) {
43             debug("Redirection to $url");
44             return redirect $url;
45             }
46              
47             my ( $site_name, $site ) = _get_site();
48             return halt("Could not find site called '$site_name' in the database") if not $site;
49              
50             # TODO send text or json whatever is appropriate
51             # return to_json { error => 'no_site_found' } if not $site;
52              
53             return if $open{$path};
54             return if $path !~ m{/_}; # only the pages starting with /_ are management pages that need restriction
55              
56             if ( not session->{logged_in} ) {
57             if ( $path =~ /json$/ ) {
58             request->path_info('/_dwimmer/needs_login.json');
59             } else {
60             request->path_info('/_dwimmer/needs_login');
61             }
62             }
63             return;
64             };
65              
66             get '/search' => sub {
67             my $text = param('text');
68             return 'No search term provided'
69             if not defined $text or $text =~ /^\s*$/;
70              
71             my $results = Dwimmer::Admin::search(text => $text);
72             template 'search_results', { results => $results };
73             };
74              
75              
76             sub route_index {
77             my ( $site_name, $site ) = _get_site();
78              
79             my $path = request->path_info;
80             my $data = Dwimmer::Admin::get_page_data( $site, $path );
81              
82             if ($data) {
83             if ( $data->{body} =~ s{\[poll://([^]]+)\]}{} ) {
84             my $poll = $1;
85             if ( not params->{submitted} ) {
86             $data->{body} = _poll($poll);
87             }
88             }
89              
90             # disable special tag processing for now, will need to
91             $data->{body} =~ s{\[\[(\w+)://([^]]+)\]\]}{_process($1, $2)}eg;
92             $data->{body} =~ s{\[\[([\w .\$@%-]+)\]\]}{$1}g;
93              
94             return Dwimmer::Admin::render_response( 'index', { page => $data } );
95             } else {
96              
97             # TODO: actually this should check if the user has the right to create a new page
98             # on this site
99             if ( session->{logged_in} ) {
100             return Dwimmer::Admin::render_response( 'error', { page_does_not_exist => 1, creation_offer => 1 } );
101             } else {
102             return Dwimmer::Admin::render_response( 'error', { page_does_not_exist => 1 } );
103             }
104             }
105             };
106              
107             get '/update.rss' => sub {
108             my $db = _get_db();
109             my ( $site_name, $site ) = _get_site();
110              
111             my $host = request->uri_base;
112             my $rss = XML::RSS->new( version => '1.0' );
113             my $year = 1900 + (localtime)[5];
114             $rss->channel(
115             title => "Dwimmer.org",
116             link => $host,
117             description => "A Dwimmer based site",
118             dc => {
119             language => 'en-us',
120             publisher => 'szabgab@gmail.com',
121             rights => "Copyright $year",
122             },
123             syn => {
124             updatePeriod => "hourly",
125             updateFrequency => "1",
126             updateBase => "1901-01-01T00:00+00:00",
127             }
128             );
129              
130             my @pages = $db->resultset('Page')->search( { siteid => $site->id } );
131             #my @urls = map { { loc => [ $host . $_->filename ] } } @res;
132              
133             my $RSS = 10;
134              
135             # TODO this whole thing should be a single query and not one for each item!
136             foreach my $p (reverse @pages[-min($RSS, scalar @pages) .. -1]) {
137             my $page = $db->resultset('PageHistory')->find( { siteid => $site->id, pageid => $p->id, revision => $p->revision } );
138             my $text = $page->body;
139             # $text =~ s{"/}{"$host/}g;
140             $rss->add_item(
141             title => decode('utf-8', $page->title),
142             link => $host . $page->filename,
143             description => decode('utf-8', $text),
144             dc => {
145             creator => $page->author->name,
146             date => POSIX::strftime("%Y-%m-%dT%H:%M:%S+00:00", localtime $page->timestamp), # 2008-05-14T13:43:49+00:00
147             subject => $page->title,
148             }
149             );
150             }
151              
152             return $rss->as_string;
153             };
154              
155              
156             # http://www.sitemaps.org/protocol.html
157             get '/sitemap.xml' => sub {
158              
159             # see also Dwimmer::Admin get_pages.json
160             my $db = _get_db();
161             my ( $site_name, $site ) = _get_site();
162             my @res = $db->resultset('Page')->search( { siteid => $site->id } );
163              
164             # lastmode => YYYY-MM-DD
165             # changefreq
166             # priority
167             my $host = request->uri_base;
168              
169             my $xml = qq(\n);
170             foreach my $r (@res) {
171             $xml .= qq( \n);
172             $xml .= qq( $host) . $r->filename . qq(\n);
173             $xml .= qq( \n);
174             }
175             $xml .= qq();
176              
177             content_type "text/xml";
178             return $xml;
179             };
180              
181             get qr{^/([a-zA-Z0-9][\w .\$@%-]*)?$} => \&route_index;
182              
183             # TODO plan:
184             # when a pages is marked as a "poll" there are going to be two parts of it
185             # one is a json file describing the actual poll
186             # the other is the content of the page in the database that will be shown upon posting the poll
187             # actually this probbaly should be shown only if we get a parmater in the get request.
188             # and the whole thing will be replaced by the result page once the poll is closed.
189             post '/poll' => sub {
190             my $id = params->{id};
191             return Dwimmer::Admin::render_response( 'error', { invalid_poll_id => $id } )
192             if $id !~ /^[\w-]+$/;
193              
194             my $json_file = path( config->{appdir}, 'polls', "$id.json" );
195             return Dwimmer::Admin::render_response( 'error', { poll_not_found => $id } )
196             if not -e $json_file;
197              
198             my $log_file = path( config->{appdir}, 'polls', "$id.txt" );
199             my %data = params();
200             $data{IP} = request->address;
201             $data{TS} = time;
202             $data{SID} = session->id;
203             if ( open my $fh, '>>', $log_file ) {
204             flock( $fh, LOCK_EX );
205             print $fh to_json( \%data ), "\n";
206             close $fh;
207             }
208             redirect request->uri_base . "/$id?submitted=1";
209             };
210              
211             sub _poll {
212             my ($action) = @_;
213             if ( $action !~ m{^[\w-]+$} ) {
214             return qq{Invalid poll name "$action"};
215             }
216             my $json_file = path( config->{appdir}, 'polls', "$action.json" );
217              
218             if ( not -e $json_file ) {
219             debug("File '$json_file' not found");
220             return "Poll Not found";
221             }
222             my $data = eval { from_json scalar read_file $json_file };
223             if ($@) {
224             debug("Could not read json file '$json_file': $@");
225             return "Could not read poll data";
226             }
227              
228             my $html;
229             open my $out, '>', \$html or die;
230             my $t = Template->new(
231             ABSOLUTE => 1,
232              
233             # encoding: 'utf8'
234             START_TAG => '<%',
235             END_TAG => '%>',
236             );
237              
238             #return path(config->{appdir}, 'views', 'poll.tt') . -s path(config->{appdir}, 'views', 'poll.tt');
239             $t->process( path( config->{appdir}, 'views', 'poll.tt' ), { poll => $data }, $out );
240              
241             #use Capture::Tiny qw();
242             #my ($out, $err) = Capture::Tiny::capture { $t->process(path(config->{appdir}, 'views', 'poll.tt'), {poll => $data}) };
243             close $out;
244             return $html;
245             }
246              
247             sub _process {
248             my ( $scheme, $action ) = @_;
249             if ( $scheme eq 'http' or $scheme eq 'https' ) {
250             return qq{$action};
251             }
252              
253              
254             return qq{Unknown scheme: "$scheme"};
255             }
256              
257             true;
258              
259             =head1 NAME
260              
261             Dwimmer - A platform to develop things
262              
263             =head1 COPYRIGHT
264              
265             (c) 2011 Gabor Szabo
266              
267             =head1 LICENSE
268              
269             This program is free software; you can redistribute it and/or
270             modify it under the same terms as Perl 5 itself.
271              
272             =cut
273              
274             # Copyright 2011 Gabor Szabo
275             # LICENSE
276             # This program is free software; you can redistribute it and/or
277             # modify it under the same terms as Perl 5 itself.
278