Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 381 lines (284 sloc) 9.202 kB
13febf8 first commit
Zbigniew Lukasiak authored
1 use strict;
2 use warnings;
3 package Nblog;
4
5 use Moose;
6 use MooseX::NonMoose;
7 use Moose::Util::TypeConstraints;
8
18a17d6 stylesheets
Zbigniew Lukasiak authored
9 use Plack::Request;
d01d03e delete.tt added; subclassing HTML::CalendarMonthSimple
Zbigniew Lukasiak authored
10 use Nblog::Calendar;
844d1c5 using Plack::App::ResetPass
Zbigniew Lukasiak authored
11 use Nblog::ResetPassApp;
f69fd33 calendar; some more static files copied from ravlog
Zbigniew Lukasiak authored
12 use DateTime;
18a17d6 stylesheets
Zbigniew Lukasiak authored
13
fba9b41 Middleware to app
Zbigniew Lukasiak authored
14 use Plack::Middleware::Static;
15 use Plack::Middleware::Session;
16 use Plack::Session::Store::Cache;
515c8df inheritance of static files (static_root an array)
Zbigniew Lukasiak authored
17 use Plack::App::Cascade;
18 use Plack::App::URLMap;
19 use Plack::App::File;
e15eeb0 using Plack::Middleware::Auth::Form
Zbigniew Lukasiak authored
20 use Plack::Middleware::Auth::Form;
515c8df inheritance of static files (static_root an array)
Zbigniew Lukasiak authored
21
fba9b41 Middleware to app
Zbigniew Lukasiak authored
22 use CHI;
23
13febf8 first commit
Zbigniew Lukasiak authored
24 extends 'WebNano';
25 use Nblog::Schema;
26 use WebNano::Renderer::TT;
146bff8 using File::ShareDir
Zbigniew Lukasiak authored
27 use File::ShareDir ();
28
29 use Cwd qw[abs_path];
30 use File::Spec ();
31
9a8d6b6 Registration
Zbigniew Lukasiak authored
32 use Nblog::RegisterApp;
13febf8 first commit
Zbigniew Lukasiak authored
33
34 with 'MooseX::SimpleConfig';
35
146bff8 using File::ShareDir
Zbigniew Lukasiak authored
36 my $configfile = File::Spec->catfile( dist_dir(), 'nblog_config.pl' );
37
38 sub dist_dir {
39 my $inc = 'Nblog.pm';
40 my $path = $INC{$inc} || '';
41 if ($path
42 and ( $path =~ s!(\S.*?)[\\/]?\bb?lib\b.*!$1! || $path =~ s!(\.[\\/])?\bb?lib\b.*!.! )
43 and ( -e "$path/Makefile.PL" || -e "$path/dist.ini" )
44 and -e "$path/share"
45 ) {
46 return abs_path "$path/share";
47 }
48 else {
49 return File::ShareDir::dist_dir( 'Nblog' );
50 }
51 }
52
9eca373 default config
Zbigniew Lukasiak authored
53 has '+configfile' => ( default => $configfile );
18a17d6 stylesheets
Zbigniew Lukasiak authored
54
5f3ccb2 Feeds
Zbigniew Lukasiak authored
55 has 'name' => ( is => 'ro', isa => 'Str' );
56
853397f rough support for https
Zbigniew Lukasiak authored
57 has 'secure' => ( is => 'ro', isa => 'Num' );
58
13febf8 first commit
Zbigniew Lukasiak authored
59 subtype 'Nblog::Schema::Connected' => as class_type( 'Nblog::Schema' );
60 coerce 'Nblog::Schema::Connected'
61 => from 'HashRef'
6d541cb multiple blogs
Zbigniew Lukasiak authored
62 => via { Nblog::Schema->new_from_config( $_ ); };
13febf8 first commit
Zbigniew Lukasiak authored
63
64 has schema => ( is => 'ro', isa => 'Nblog::Schema::Connected', coerce => 1 );
65
66 subtype 'Nblog::WebNano::Renderer::TT' => as class_type ( 'WebNano::Renderer::TT' );
67 coerce 'Nblog::WebNano::Renderer::TT'
68 => from 'HashRef'
69 => via { WebNano::Renderer::TT->new( %$_ ) };
70
71 has renderer => ( is => 'ro', isa => 'Nblog::WebNano::Renderer::TT', coerce => 1 );
72
73 around handle => sub {
74 my $orig = shift;
75 my $self = shift;
76 my $env = shift;
77 if( $env->{'psgix.session'}{user_id} ){
78 $env->{user} = $self->schema->resultset( 'User' )->find( $env->{'psgix.session'}{user_id} );
79 }
80 $self->$orig( $env, @_ );
81 };
82
b02f787 displaying tags
Zbigniew Lukasiak authored
83 sub tags { shift->schema->resultset( 'Tag' )->all }
84
f69fd33 calendar; some more static files copied from ravlog
Zbigniew Lukasiak authored
85 sub calendar {
86 my ( $self ) = @_;
87
88 my $dt = DateTime->now();
d01d03e delete.tt added; subclassing HTML::CalendarMonthSimple
Zbigniew Lukasiak authored
89 my $cal = new Nblog::Calendar(
f69fd33 calendar; some more static files copied from ravlog
Zbigniew Lukasiak authored
90 'year' => $dt->year,
91 'month' => $dt->month
92 );
93 $cal->border(0);
94 $cal->width(50);
95 $cal->headerclass('month_date');
96 $cal->showweekdayheaders(0);
97
98 my @articles = $self->schema->resultset('Article')->from_month( $dt->month );
99
100 foreach my $article (@articles)
101 {
102 my $location =
103 '/archived/'
104 . $article->created_at->year() . '/'
105 . $article->created_at->month() . '/'
106 . $article->created_at->mday();
107 $cal->setdatehref( $article->created_at->mday(), $location );
108 }
109
110 return $cal->as_HTML;
111 }
112
3eafdba some data for templates fixed
Zbigniew Lukasiak authored
113 sub ravlog_txt_to_url {
114 my $self = shift;
115
116 my ( $txt, $id ) = @_;
117
118 $txt =~ s/(\'|\!|\`|\?)//g;
119 $txt =~ s/ /\_/g;
120
121 return $txt;
122 }
123 sub render_ravlog_date {
124 my $self = shift;
125 my $date = shift;
126 my $dt = $self->datetime_to_ravlog_time($date);
127 my $output = "<span class=\"ravlog_date\" title=\""
128 . $dt
129 . "\">$dt</span>";
130 return $output;
131 }
132
133 sub datetime_to_ravlog_time {
134 my $self = shift;
135
136 my ($d) = shift;
137 my $ext =
138 $d->day_abbr() . ", "
139 . $d->day() . " "
140 . $d->month_abbr() . " "
141 . $d->year() . " "
142 . $d->hour . ":"
143 . $d->minute . ":"
144 . $d->second();
145 return $ext;
146 }
147
148
149 sub archives
150 {
151 my ( $self ) = @_;
152
153 my @articles = $self->schema->resultset('Article')->all();
154
155 unless (@articles)
156 {
157 return "<p>No Articles in Archive!</p>";
158 }
159
160 my $months;
161 foreach my $article (@articles)
162 {
163 my $month = $article->created_at()->month_name();
164 my $year = $article->created_at()->year();
165 my $key = "$year $month";
166 if ( ( defined $months->{$key}->{count} ) && ( $months->{$key}->{count} > 0 ) )
167 {
168 $months->{$key}->{count} += 1;
169 }
170 else
171 {
172 $months->{$key}->{count} = 1;
173 $months->{$key}->{year} = $year;
174 $months->{$key}->{month} = $article->created_at()->month();
175 }
176 }
177
178 my @out;
179 while ( my ( $key, $value ) = each( %{$months} ) )
180 {
181 push @out,
182 "<li><a href='/archived/$value->{year}/$value->{month}'>$key</a> <span class='special_text'>($value->{count})</span></li>";
183 }
184 return join( ' ', @out );
185 }
186
1b645c3 controller for articles
Zbigniew Lukasiak authored
187 sub ravlog_url_to_query {
188 my $self = shift;
189
190 my ($txt) = shift;
191
192 $txt =~ s/\_/ /g;
193 $txt =~ s/s /\%/g;
194 return ( "%" . $txt . "%" );
195 }
196
fc3d643 list after creations of some thigs; pages
Zbigniew Lukasiak authored
197 sub pages {
68ec051 separate login page
Zbigniew Lukasiak authored
198 return shift->schema->resultset('Page')->search( { display_in_drawer => 1 } )->all();
fc3d643 list after creations of some thigs; pages
Zbigniew Lukasiak authored
199 }
3eafdba some data for templates fixed
Zbigniew Lukasiak authored
200
515c8df inheritance of static files (static_root an array)
Zbigniew Lukasiak authored
201 has static_root => (
202 traits => ['Array'],
203 is => 'ro',
204 isa => 'ArrayRef[Str]',
205 handles => { static_roots => 'elements' },
206 );
207
f69fd33 calendar; some more static files copied from ravlog
Zbigniew Lukasiak authored
208
e0ab81a psgi_callback to psgi_app
Zbigniew Lukasiak authored
209 around psgi_app => sub {
7fa0bdd improve dist.ini; renderer root as root for static files instead of h…
Zbigniew Lukasiak authored
210 my $orig = shift;
211 my $self = shift;
844d1c5 using Plack::App::ResetPass
Zbigniew Lukasiak authored
212 my $app = Plack::App::URLMap->new;
213 my $reset_pass = Nblog::ResetPassApp->new( schema => $self->schema, renderer => $self->renderer );
214 $app->map( '/ResetPass', $reset_pass );
515c8df inheritance of static files (static_root an array)
Zbigniew Lukasiak authored
215 my $cascade = Plack::App::Cascade->new;
216 my $favicon_c = Plack::App::Cascade->new;
217 for my $root ( $self->static_roots ){
218 $cascade->add( Plack::App::File->new(root => $root )->to_app );
8fbbe25 favicon fixed
Zbigniew Lukasiak authored
219 $favicon_c->add( Plack::App::File->new( file => "$root/images/favicon.ico" )->to_app );
515c8df inheritance of static files (static_root an array)
Zbigniew Lukasiak authored
220 };
221 $app->map( '/static', $cascade );
222 $app->map( '/favicon.ico', $favicon_c );
223 $app->map( '/', $self->$orig( @_ ) );
9a8d6b6 Registration
Zbigniew Lukasiak authored
224 $app->map( '/Register', Nblog::RegisterApp->new( renderer => $self->renderer, schema => $self->schema )->to_app );
e15eeb0 using Plack::Middleware::Auth::Form
Zbigniew Lukasiak authored
225 $app = Plack::Middleware::Auth::Form->wrap(
226 $app->to_app,
227 authenticator => sub {
228 my( $username, $password ) = @_;
229 my $user = $self->schema->resultset( 'User' )->search( { username => $username } )->first;
230 if( $user && $user->check_password( $password ) ){
231 return { user_id => $user->id };
232 }
233 return 0;
234 },
235 no_login_page => 1,
19c51ee test data
Zbigniew Lukasiak authored
236 secure => $self->secure,
e15eeb0 using Plack::Middleware::Auth::Form
Zbigniew Lukasiak authored
237 );
515c8df inheritance of static files (static_root an array)
Zbigniew Lukasiak authored
238 return Plack::Middleware::Session->wrap(
e15eeb0 using Plack::Middleware::Auth::Form
Zbigniew Lukasiak authored
239 $app,
515c8df inheritance of static files (static_root an array)
Zbigniew Lukasiak authored
240 store => Plack::Session::Store::Cache->new(
241 cache => CHI->new(driver => 'FastMmap')
242 )
243 );
fba9b41 Middleware to app
Zbigniew Lukasiak authored
244 };
245
13febf8 first commit
Zbigniew Lukasiak authored
246 1;
7fa0bdd improve dist.ini; renderer root as root for static files instead of h…
Zbigniew Lukasiak authored
247
248 __END__
249
250 # ABSTRACT: A simple blog engine
251
37180ea @zby Synopsis
authored
252 =head1 SYNOPSIS
253
68c343e some docs
Zbigniew Lukasiak authored
254 You can run Nblog with L<plackup> from a following simple C<app.psgi> file,
37180ea @zby Synopsis
authored
255 it will use the default config with a in-memory database:
256
257 use Nblog;
258
259 my $app = Nblog->new_with_config();
260
261 $app->psgi_app;
262
20b488d @zby INSTALL was outdated; some docs changes
authored
263 You can login with username 'test' and password: 'pass_for_test'.
37180ea @zby Synopsis
authored
264
68c343e some docs
Zbigniew Lukasiak authored
265 =head1 DESCRIPTION
266
267 Warning: still experimental.
268
8ef9e28 Ravlog
Zbigniew Lukasiak authored
269 This is a simple blog engine, rewrite of Ravlog (https://github.com/gshank/ravlog) in L<WebNano> .
270 The main idea is that it is easy to start and yet very configurable,
68c343e some docs
Zbigniew Lukasiak authored
271 with everything overridable.
272
273 =head2 Features
274
275 =over
276
277 =item nice urls
278
279 =item multiple typesetting languages
280
281 From Text::WikiFormat, through Textile to POD in HTML
282
283 =item code formatting
284
285 Perl only for now - based on http://alexgorbatchev.com/SyntaxHighlighter/
286
287 =item search
288
289 =item tags
290
291 =item calendar
292
293 =item RSS
294
295 =back
296
297 =head2 Step by step customisation
298
299 Here is another C<.psgi> file:
37180ea @zby Synopsis
authored
300
301 use Nblog;
302
303 my $app = Nblog->new_with_config(
304 schema => {
305 connect_info => [
306 'dbi:SQLite:dbname=blog.db',
307 ],
308 deploy_on_start => 1,
309 },
310
311 );
312
313 $app->psgi_app;
314
68c343e some docs
Zbigniew Lukasiak authored
315 This one will use a 'blog.db' file in the current directory
316 as the blog database. The 'deploy_on_start' parameter requests
317 that the database will be (re)created anew - you should remove it on the subsequent
318 runs.
37180ea @zby Synopsis
authored
319
320 To customize Nblog you can provide values directly at the C<new_with_config> call
321 or provide a different configuration file(s) (see L<MooseX::SimpleConfig>).
322
68c343e some docs
Zbigniew Lukasiak authored
323 Customizing by overriding some of the static files and templates can be done
324 with following C<.psgi> files:
325
326 use Nblog;
327
328 my $app = Nblog->new_with_config( static_root => [ 'static', Nblog::dist_dir() . '/static', ] );
329
330 $app->psgi_app;
331
332 and
333
334 use Nblog;
335
336 my $app = Nblog->new_with_config( renderer => {
337 root => [ 'templates', Nblog::dist_dir() . '/templates' ],
338 TEMPLATE_EXTENSION => 'tt',
339 INCLUDE_PATH => [ 'templates/globals', Nblog::dist_dir() . '/templates/globals' ],
340 PRE_PROCESS => 'config.tt',
341 WRAPPER => 'wrapper.tt',
342 VARIABLES => {
343 site_name => 'Writers Unite!',
344 sidebar => 1,
345 }
346 }
347 );
348
349 $app->psgi_app;
350
351 Finally you can also subclass Nblog:
352
353 {
354 package MyBlog;
355 use Moose;
356 extends 'Nblog';
357
358 sub controller_search_path { [ ref(shift), 'Nblog' ] };
359 }
360
361 {
362 package MyBlog::Controller::SomeNewPage;
363 use Moose;
364
365 extends 'WebNano::Controller';
366
367 sub index_action { return __PACKAGE__ };
368 }
369
370 my $app = MyBlog->new_with_config();
371
372 $app->psgi_app;
373
374
375 Now going to C<http://0.0.0.0:5000/SomeNewPage/> should result in page with C<MyBlog::Controller::SomeNewPage>.
376
377 =head1 SEE ALSO
378
379 L<WebNano>
37180ea @zby Synopsis
authored
380
Something went wrong with that request. Please try again.