OSDN Git Service

Newslash::Web: enable ReCaptcha plugin in test mode
[newslash/newslash.git] / src / newslash_web / lib / Newslash / Web.pm
1 package Newslash::Web;
2 use Mojo::Base 'Mojolicious';
3 use Mojo::Util qw(dumper);
4
5 use Newslash::Model;
6
7 use constant CONFIG_FILE => '/etc/newslash/newslash.conf';
8
9 # This method will run once at server start
10 sub startup {
11     my $app = shift;
12
13     # add commands in Newslash::Command
14     push @{$app->commands->namespaces}, 'Newslash::Command';
15
16     # load config file
17     # first, check existence of /etc/newslash.conf
18     if ($app->mode eq 'production' && -e CONFIG_FILE) {
19         $app->plugin('Newslash::Plugin::YAMLConfig', file => CONFIG_FILE);
20     }
21     else {
22         $app->plugin('Newslash::Plugin::YAMLConfig');
23     }
24     # TODO: load/save configs with database
25
26     if ($app->config->{Log} && $app->config->{Log}->{backtrace}) {
27         require Carp::Always;
28         Carp::Always->import;
29     }
30
31     # set log file
32     if ($app->config->{Log} && $app->config->{Log}->{system_log}) {
33         # check log is writable
34         my $pathname = $app->config->{Log}->{system_log};
35         if (-e $pathname) {
36             if (-w $pathname) {
37                 $app->log->debug("logs will be outputed to $pathname ...");
38                 $app->log(Mojo::Log->new);
39                 $app->log->path($pathname);
40             }
41             else {
42                 $app->log->error("cannot write system log to file: $pathname");
43             }
44         }
45         else {
46             if (open(my $fh, ">", $pathname)) {
47                 close($fh);
48                 $app->log->debug("logs will be outputed to $pathname ...");
49                 $app->log(Mojo::Log->new);
50                 $app->log->path($pathname);
51             }
52             else {
53                 $app->log->error("cannot create system log file: $pathname");
54             }
55         }
56     }
57
58     # set log level
59     if ($app->config->{Log} && $app->config->{Log}->{level}) {
60         my $loglv = $app->config->{Log}->{level};
61         if (grep { $loglv eq $_ } qw(debug info warn error fatal)) {
62             $app->log->level($loglv);
63         }
64         else {
65             $app->log->warn('invalid log level given in config file');
66         }
67     }
68
69     # add static contents directories
70     if ($app->config->{System} && $app->config->{System}->{static_dir}) {
71         for my $dir (@{$app->config->{System}->{static_dir}}) {
72             push @{$app->static->paths}, $dir;
73         }
74     }
75
76     ############################################################
77     #
78     # Plugin Settings
79     #
80     ############################################################
81
82     # when "test" mode, output debug logs.
83     $app->log->level('debug') if $app->mode eq 'test';
84
85     if ($app->mode eq 'development'
86         && $app->config->{Profiler}
87         && $app->config->{Profiler}->{enable}) {
88         if ($app->config->{Profiler}->{profiler} eq 'nytprof') {
89             $app->plugin('Mojolicious::Plugin::NYTProf', { nytprof => {} });
90         }
91     }
92
93     # enable logging
94     $app->plugin('Newslash::Plugin::AccessLog::Debug', $app->config->{Log} || {});
95     $app->plugin('Newslash::Plugin::AccessLog::LocalFile', $app->config->{Log} || {});
96
97     # secret key for hasing
98     $app->secrets([$app->config->{System}->{secret_key},]);
99
100     # Helpers for Newslash
101     $app->plugin('Newslash::Plugin::NewslashHelpers');
102
103     # use Epoch
104     $app->plugin('Newslash::Plugin::Epoch');
105
106     # use BasicAuth?
107     if ($app->config->{BasicAuth} && $app->config->{BasicAuth}->{enable}) {
108         $app->plugin('Newslash::Plugin::BasicAuth');
109     }
110
111     # use TimeLimitedCache ($app->cache)
112     $app->plugin('Newslash::Plugin::TimeLimitedCache');
113
114     # use KeyValue Store ($app->kvs)
115     $app->plugin('Newslash::Plugin::KeyValueStore');
116
117     # add Model Loader
118     my $model_opts = $app->config;
119     $model_opts->{Logger} = $app->log;
120     $app->helper(model => Newslash::Model::loader($model_opts));
121
122     if (@ARGV[0] ne "databaseinit") {
123         Newslash::Model::startup($model_opts, $app);
124     }
125     else {
126         $app->log->info("bypassing model startup...");
127     }
128
129     # use Easy Cache ($app->ezcache)
130     $app->plugin('Newslash::Plugin::EasyCache');
131
132     # use Template::Toolkit 2 render
133     $app->plugin('Newslash::Plugin::TT2Renderer');
134
135     # use CustomBoxes
136     $app->plugin('Newslash::Plugin::CustomBoxes');
137
138     # user AntiCsrf ($app->anti_csrf)
139     if ($app->mode ne 'test') {
140         # when test mode, disable AntiCsrf.
141         $app->plugin('Newslash::Plugin::AntiCsrf');
142     }
143
144     # contents preprocessor
145     $app->plugin('Newslash::Plugin::Preprocessor');
146
147     # javascript loader
148     $app->plugin('Newslash::Plugin::JavaScriptLoader');
149
150     # user authorization
151     $app->plugin('Newslash::Plugin::UserAuth');
152
153     # access control
154     $app->plugin('Newslash::Plugin::AccessControl');
155
156     # ReCaptcha control
157     $app->plugin('Newslash::Plugin::ReCaptcha');
158
159     # set canocal (for test.srad.jp)
160     $app->plugin('Newslash::Plugin::Canonical');
161
162     # DiscussionHelper
163     $app->plugin('Newslash::Plugin::DiscussionHelper');
164
165     # use HSTS
166     $app->plugin('Newslash::Plugin::Hsts');
167
168     # Event Que
169     $app->plugin('Newslash::Plugin::EventQue');
170
171     # Statics Logger
172     $app->plugin('Newslash::Plugin::Statics');
173
174     # Request Body based routing condition
175     $app->plugin('Newslash::Plugin::RequestBodyCondition');
176
177     # NS-RPC
178     $app->plugin('Newslash::Plugin::NSRPC');
179
180     # AD renderer
181     $app->plugin('Newslash::Plugin::ADRenderer');
182
183
184     ############################################################
185     #
186     # Routing Settings
187     #
188     ############################################################
189
190     my $r = $app->routes;
191
192     # index page
193     $r->get('/')->to('timeline#stories');
194     $r->get('/recent')->to('timeline#recent');
195     $r->get('/popular')->to('timeline#popular');
196     $r->get('/comments')->to('timeline#comments');
197     $r->get('/journals')->to('timeline#journals');
198     $r->get('/submissions')->to('timeline#submissions');
199     $r->get('/polls')->to('timeline#polls');
200
201     # Banned page
202     $r->get('/banned')->to('index#banned', noindex => 1);
203
204     # Login / Logout
205     $r->get('/login')->to('login#login');
206     $r->post('/login')->to('login#login');
207     $r->get('/logout')->to('login#logout');
208
209     # User Register
210     $r->get('/my/newuser')->to('login#newuser');
211     $r->post('/my/newuser')->to('login#newuser', captcha_check => 1);
212
213     # story page
214     $r->get('/story/:sid/' => [sid => qr|\d\d/\d\d/\d\d/\d+|])
215       ->to('story#single');
216
217     # comment page
218     $r->get('/comment/:cid/')->to('comment#single');
219
220     # journal page
221     $r->get('/journal/new')->to('journal#create', seclev => 1);
222     $r->get('/journal/:id/')->to('journal#single');
223
224     # submission page
225     $r->get('/submission/new')->to('submission#create');
226     $r->get('/submission/:id/')->to('submission#single');
227     #$r->post('/submission')->to('submission#create');
228
229     # polls page
230     $r->get('/poll/:qid')->to('poll#single');
231     $r->get('/vote/:qid')->to('poll#vote');
232     $r->post('/vote/:qid')->to('poll#vote_post', csrf_check_id => 'vote');
233
234     # archive page
235     $r->get('/story/:year/:month/:day/')->to('archive#story');
236     $r->get('/story/:year/:month/')->to('archive#story');
237     $r->get('/story/')->to('archive#story');
238
239     $r->get('/journal/:year/:month/:day/')->to('archive#journal');
240     $r->get('/journal/:year/:month/')->to('archive#journal');
241     $r->get('/journal/')->to('archive#journal');
242
243     $r->get('/submission/:year/:month/:day/')->to('archive#submission');
244     $r->get('/submission/:year/:month/')->to('archive#submission');
245     $r->get('/submission/')->to('archive#submission');
246
247     $r->get('/poll/:year/:month/')->to('archive#poll');
248     $r->get('/poll/')->to('archive#poll');
249
250     # tag page
251     $r->get('/tag/:tagname/:type/')->to('tag#list_tagged_items');
252     $r->get('/tag/:tagname/')->to('tag#list_tagged_items');
253     $r->get('/tag/')->to('tag#list_tags');
254
255     # my page
256     $r->get('/my/settings')->to('my#settings', seclev => 1);
257     $r->get('/my/sidebar')->to('my#sidebar', seclev => 1);
258     $r->get('/my/messages')->to('my#messages', seclev => 1);
259     $r->get('/my/')->to('user#home', seclev => 1);
260
261     # search page
262     $r->get('/search')->to('search#search');
263
264     # Admin
265     # pages under /admin needs seclev equal or greater than 10000;
266     my $admin = $r->under('/admin' => sub { my $c = shift; $c->stash(seclev => 10000); return 1; });
267
268     $admin->get('/firehose/:id/')->to('admin-firehose#single');
269     $admin->get('/submissions')->to('admin-submissions#index');
270
271     $admin->get('/css')->to('admin-css#edit');
272     $admin->get('/story/edit')->to('admin-story#edit');
273
274     $admin->get('/users')->to('admin-users#index');
275
276     $admin->get('/default-sidebar')->to('admin-sidebar#defaults');
277
278     $admin->get('/sidebar')->to('admin-sidebar#index');
279     $admin->get('/feed')->to('admin-feed#index');
280     $admin->get('/blocking')->to('admin-blocking#index');
281     $admin->get('/ad')->to('admin-ads#index');
282
283     $admin->get('/repository')->to('admin-repository#index');
284     $admin->get('/cache')->to('admin-config#cache');
285
286     # Admin API
287     # pages under /api/v1/admin needs seclev equal or greater than 10000;
288     my $admin_api = $r->under('/api/v1/admin' => sub { my $c = shift; $c->stash(seclev => 10000); return 1; });
289     $admin_api->get('/feed')->to('API::Admin::Feed#get');
290     $admin_api->post('/feed')->to('API::Admin::Feed#post');
291     $admin_api->get('/blocking')->to('API::Admin::Blocking#get');
292     $admin_api->post('/blocking')->to('API::Admin::Blocking#post');
293
294     $admin_api->get('/repository/export')->to('API::Admin::Repository#export');
295     $admin_api->get('/repository/import')->to('API::Admin::Repository#import');
296
297     $admin_api->post('/sidebar')->to('API::Admin::Sidebar#post');
298     $admin_api->get('/sidebar')->to('API::Admin::Sidebar#get');
299
300     # ad codes management
301     $app->rpc->route_to_model($admin_api->get('/ad/code/'), 'ad_codes', 'select');
302     $app->rpc->route_to_model($admin_api->post('/ad/code/')->over(request_body => {action => "create"}), 'ad_codes', 'create');
303     $app->rpc->route_to_model($admin_api->post('/ad/code/')->over(request_body => {action => "update"}), 'ad_codes', 'update');
304     $app->rpc->route_to_model($admin_api->post('/ad/code/')->over(request_body => {action => "delete"}), 'ad_codes', 'delete');
305
306     # API
307     my $api = $r->under('/api/v1');
308     $api->post('/login')->to('API::Login#login');
309
310     $api->get('/sidebar/item')->to('API::SidebarItem#get', seclev => 1);
311
312     $api->get('/comment')->to('API::Comment#get');
313     $api->post('/comment')->to('API::Comment#post', captcha_check => 1, csrf_check_id => 'comment');
314
315     $api->get('/user')->to('API::User#get');
316     $api->post('/user')->to('API::User#post', seclev => 1);
317
318     $api->get('/journal')->to('API::Journal#get');
319     $api->post('/journal')->to('API::Journal#post', seclev => 1, csrf_check_id => 'journal');
320
321     $api->get('/submission')->to('API::Submission#get');
322     $api->get('/submissions')->to('API::Submission#list');
323     $api->post('/submission')->to('API::Submission#post', captcha_check => 1, csrf_check_id => 'submission');
324
325     $api->get('/story')->to('API::Story#get');
326     $api->post('/story')->to('API::Story#post');
327
328     $api->get('/poll')->to('API::Poll#get');
329     $api->post('/poll')->to('API::Poll#post');
330     $api->post('/vote')->to('API::Poll#vote', csrf_check_id => 'vote');
331
332     $api->get('/moderation')->to('API::Moderation#get');
333     $api->post('/moderation')->to('API::Moderation#post', seclev => 1, csrf_check_id => 'moderation');
334
335     $api->get('/metamoderation')->to('API::Metamoderation#get');
336     $api->post('/metamoderation')->to('API::Metamoderation#post', seclev => 1, csrf_check_id => 'moderation');
337
338     $api->post('/relation')->to('API::Relation#post', seclev => 1, csrf_check_id => 'relation');
339
340     $api->get('/token')->to('API::Token#get');
341
342     # user page
343     # warning: these pathes uses regexp matching, so must write in tail of route definitions.
344     my $user = $r->under('/:nickname');
345     $user->get('/'             => [nickname => qr/~.*/])->to('user#home');
346     $user->get('/journals'     => [nickname => qr/~.*/])->to('user#journals');
347     $user->get('/journal'      => [nickname => qr/~.*/])->to('user#journals'); # for compatibility
348     $user->get('/comments'     => [nickname => qr/~.*/])->to('user#comments');
349     $user->get('/submissions'  => [nickname => qr/~.*/])->to('user#submissions');
350     $user->get('/friends'      => [nickname => qr/~.*/])->to('user#friends');
351     $user->get('/foes'         => [nickname => qr/~.*/])->to('user#foes');
352     $user->get('/fans'         => [nickname => qr/~.*/])->to('user#fans');
353     $user->get('/freaks'       => [nickname => qr/~.*/])->to('user#freaks');
354     $user->get('/achievements' => [nickname => qr/~.*/])->to('user#achievements');
355     #$r->get('/:user_name/journal' => [user_name => qr/~.*/])->to('journal#user_journals');
356
357 }
358
359 1;