OSDN Git Service

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