package Newslash::Web;
use Mojo::Base 'Mojolicious';
use Mojo::Util qw(dumper);
-
-use Newslash::Model;
+use List::Util qw(any);
use constant CONFIG_FILE => '/etc/newslash/newslash.conf';
+has subcommand => "";
# This method will run once at server start
sub startup {
my $app = shift;
+ if ($ARGV[0]) {
+ $app->subcommand($ARGV[0]);
+ }
+
+ # add commands in Newslash::Command
+ push @{$app->commands->namespaces}, 'Newslash::Command';
+
# load config file
# first, check existence of /etc/newslash.conf
if ($app->mode eq 'production' && -e CONFIG_FILE) {
$app->plugin('Newslash::Plugin::YAMLConfig', file => CONFIG_FILE);
}
else {
- #$app->plugin('JSONConfig');
- $app->plugin('Newslash::Plugin::YAMLConfig');
+ if ($app->subcommand eq "configdump") {
+ $app->plugin('Newslash::Plugin::YAMLConfig', default => {});
+ }
+ else {
+ $app->plugin('Newslash::Plugin::YAMLConfig');
+ }
}
+
+ # load default configuration values
+ $app->plugin('Newslash::Plugin::DefaultConfig');
+
# TODO: load/save configs with database
if ($app->config->{Log} && $app->config->{Log}->{backtrace}) {
Carp::Always->import;
}
- # set log file
+ # system log config
if ($app->config->{Log} && $app->config->{Log}->{system_log}) {
- # check log is writable
- my $pathname = $app->config->{Log}->{system_log};
- if (-e $pathname) {
- if (-w $pathname) {
- $app->log->debug("logs will be outputed to $pathname ...");
- $app->log(Mojo::Log->new);
- $app->log->path($pathname);
- }
- else {
- $app->log->error("cannot write system log to file: $pathname");
- }
- }
- else {
- if (open(my $fh, ">", $pathname)) {
- close($fh);
- $app->log->debug("logs will be outputed to $pathname ...");
- $app->log(Mojo::Log->new);
- $app->log->path($pathname);
- }
- else {
- $app->log->error("cannot create system log file: $pathname");
- }
+ my $cnf = $app->config->{Log}->{system_log};
+
+ # set log level
+ if ($cnf->{level}) {
+ my $loglv = $cnf->{level};
+ if (grep { $loglv eq $_ } qw(debug info warn error fatal)) {
+ $app->log->level($loglv);
+ $app->log->info("set log level to $loglv");
+ }
+ else {
+ $app->log->warn('invalid log level given in config file');
+ }
+ }
+
+ # file output settings
+ if ($cnf->{mode} eq "local_file") {
+ my $pathname = $cnf->{local_file};
+ # check log is writable
+ if (!$pathname) {
+ $app->log->error("cannot write system log to file: filename not given");
+ }
+ elsif (-e $pathname) {
+ if (-w $pathname) {
+ $app->log->debug("logs will be outputed to $pathname ...");
+ $app->log(Mojo::Log->new);
+ $app->log->path($pathname);
+ }
+ else {
+ $app->log->error("cannot write system log to file: $pathname");
+ }
+ }
+ else {
+ if (open(my $fh, ">", $pathname)) {
+ close($fh);
+ $app->log->debug("logs will be outputed to $pathname ...");
+ $app->log(Mojo::Log->new);
+ $app->log->path($pathname);
+ }
+ else {
+ $app->log->error("cannot create system log file: $pathname");
+ }
+ }
}
}
- # set log level
- if ($app->config->{Log} && $app->config->{Log}->{level}) {
- my $loglv = $app->config->{Log}->{level};
- if (grep { $loglv eq $_ } qw(debug info warn error fatal)) {
- $app->log->level($loglv);
- }
- else {
- $app->log->warn('invalid log level given in config file');
+ # add static contents directories
+ if ($app->config->{System} && $app->config->{System}->{static_dir}) {
+ for my $dir (@{$app->config->{System}->{static_dir}}) {
+ push @{$app->static->paths}, $dir;
}
}
+ # secret key for hasing
+ $app->secrets([$app->config->{System}->{secret_key},]);
+
+ # when "test" mode, output debug logs.
+ $app->log->level('debug') if $app->mode eq 'test';
+
+ # check if 'maintenance' mode
+ my $maintenance_mode = 0;
+ if ($app->subcommand
+ && any { $app->subcommand eq $_ } qw[configdump configimport databaseinit
+ testdatainsert useradd usermod
+ ]) {
+ $maintenance_mode = 1;
+ }
+
############################################################
#
# Plugin Settings
#
############################################################
- # when "test" mode, output debug logs.
- $app->log->level('debug') if $app->mode eq 'test';
-
+ # profiler settings
if ($app->mode eq 'development'
&& $app->config->{Profiler}
&& $app->config->{Profiler}->{enable}) {
}
}
- # renderer helper
- # $app->plugin('Newslash::Plugin::RendererHelper');
-
- # enable logging
- $app->plugin('Newslash::Plugin::AccessLog::Debug', $app->config->{Log} || {});
- $app->plugin('Newslash::Plugin::AccessLog::LocalFile', $app->config->{Log} || {});
-
- # secret key for hasing
- $app->secrets([$app->config->{System}->{secret_key},]);
+ # enable access logging
+ $app->plugin('Newslash::Plugin::AccessLog');
# Helpers for Newslash
$app->plugin('Newslash::Plugin::NewslashHelpers');
- # stash for plugins
- #$app->config->{_Plugins} = {};
-
# use Epoch
$app->plugin('Newslash::Plugin::Epoch');
- # use BasicAuth?
- if ($app->config->{BasicAuth} && $app->config->{BasicAuth}->{enable}) {
- $app->plugin('Newslash::Plugin::BasicAuth');
- }
+ # support BasicAuth
+ $app->plugin('Newslash::Plugin::BasicAuth');
# use TimeLimitedCache ($app->cache)
$app->plugin('Newslash::Plugin::TimeLimitedCache');
$app->plugin('Newslash::Plugin::KeyValueStore');
# add Model Loader
- my $model_opts = $app->config;
- $model_opts->{Logger} = $app->log;
- $app->helper(model => Newslash::Model::loader($model_opts));
- Newslash::Model::startup($model_opts, $app);
+ $app->plugin('Newslash::Plugin::Model', { bypass_startup => $maintenance_mode });
# use Easy Cache ($app->ezcache)
- $app->plugin('Newslash::Plugin::EasyCache');
+ #$app->plugin('Newslash::Plugin::EasyCache');
+
+ # use CompositeCache Cache ($app->ccache)
+ $app->plugin('Newslash::Plugin::CompositeCache');
# use Template::Toolkit 2 render
$app->plugin('Newslash::Plugin::TT2Renderer');
- # use ViewFunctions
- #$app->plugin('Newslash::Plugin::ViewFunctions');
+ # use ResponseFilter (Faculities)
+ $app->plugin('Newslash::Plugin::ResponseFilter');
# use CustomBoxes
$app->plugin('Newslash::Plugin::CustomBoxes');
- # user AntiCsrf ($app->anti_csrf)
- if ($app->mode ne 'test') {
- # when test mode, disable AntiCsrf.
- $app->plugin('Newslash::Plugin::AntiCsrf');
- }
+ # use AntiCsrf
+ $app->plugin('Newslash::Plugin::AntiCsrf');
# contents preprocessor
$app->plugin('Newslash::Plugin::Preprocessor');
+ if ($maintenance_mode) {
+ $app->log->info("bypassing preprocessor...");
+ }
+ else {
+ $app->preprocessor->generate_all;
+ }
# javascript loader
$app->plugin('Newslash::Plugin::JavaScriptLoader');
+ if ($maintenance_mode) {
+ $app->log->info("bypassing javascriptloader...");
+ }
+ else {
+ $app->javascript_loader->load_all_bundles;
+ }
# user authorization
$app->plugin('Newslash::Plugin::UserAuth');
$app->plugin('Newslash::Plugin::AccessControl');
# ReCaptcha control
- if ($app->mode ne 'test') {
- $app->plugin('Newslash::Plugin::ReCaptcha');
- }
+ $app->plugin('Newslash::Plugin::ReCaptcha');
+
+ # Post Filter
+ $app->plugin('Newslash::Plugin::PostFilter');
# set canocal (for test.srad.jp)
$app->plugin('Newslash::Plugin::Canonical');
# Event Que
$app->plugin('Newslash::Plugin::EventQue');
- # Statics Logger
- $app->plugin('Newslash::Plugin::Statics');
+ # Stats Logger
+ $app->plugin('Newslash::Plugin::Stats');
# Request Body based routing condition
$app->plugin('Newslash::Plugin::RequestBodyCondition');
# AD renderer
$app->plugin('Newslash::Plugin::ADRenderer');
- ############################################################
- #
- # Generate site-global used javascript file
- #
- ############################################################
- my $templ_name = "common/siteconfig.js";
- my $mod_reasons = $app->model('moderations')->reasons();
- my $topics = $app->model('tags')->get_topics;
- my @acl2_types = $app->model('users')->acl2_types;
- my $keywords = {};
- for my $topic (@$topics) {
- my $lc_keyword = lc($topic->{keyword});
- my $lc_textname = lc($topic->{textname});
- $keywords->{$lc_keyword} = {keyword => $topic->{keyword},
- textname => $topic->{textname},
- image => $topic->{image}};
- if ($lc_keyword ne $lc_textname) {
- $keywords->{$lc_textname} = $keywords->{$lc_keyword};
- }
- }
- my $vars = {
- moderate_reasons => $mod_reasons,
- topics => $keywords,
- acl2_types => \@acl2_types,
- };
- my $siteconfig = $app->tt2renderer->render($templ_name, $vars);
- $app->preprocessor->add_content("js/siteconfig.js", $siteconfig, "text/javascript; charset=utf-8");
+ # HTTP Compression
+ $app->plugin('Newslash::Plugin::HttpCompression');
+
+ # Users helper
+ $app->plugin('Newslash::Plugin::Users');
+
+ # Stories helper
+ $app->plugin('Newslash::Plugin::Stories');
+
+ # Sendmail helper
+ $app->plugin('Newslash::Plugin::Sendmail');
+
+ # Wiki contents reader helper
+ $app->plugin('Newslash::Plugin::WikiContentsReader');
############################################################
#
$r->get('/submissions')->to('timeline#submissions');
$r->get('/polls')->to('timeline#polls');
- # siteconfig.js for global settings
- $r->get('/siteconfig/:epoch/siteconfig.js')->to('site_config#site_config');
+ # RSS
+ $r->get('/:rss_type' => [format => ['rss', 'xml']])->to('rss#stories');
+ $r->get('/journals/rss')->to('rss#journals');
# Banned page
$r->get('/banned')->to('index#banned', noindex => 1);
$r->post('/login')->to('login#login');
$r->get('/logout')->to('login#logout');
- # User Register
- $r->get('/my/newuser')->to('login#newuser');
- $r->post('/my/newuser')->to('login#newuser', captcha_check => 1);
-
# story page
$r->get('/story/:sid/' => [sid => qr|\d\d/\d\d/\d\d/\d+|])
->to('story#single');
$r->get('/comment/:cid/')->to('comment#single');
# journal page
+ # also see user page settings for /~username/journal/
$r->get('/journal/new')->to('journal#create', seclev => 1);
$r->get('/journal/:id/')->to('journal#single');
$r->get('/submission/:year/:month/')->to('archive#submission');
$r->get('/submission/')->to('archive#submission');
+ $r->get('/comment/:year/:month/:day/')->to('archive#comment');
+ $r->get('/comment/:year/:month/')->to('archive#comment');
+ $r->get('/comment/')->to('archive#comment');
+
$r->get('/poll/:year/:month/')->to('archive#poll');
$r->get('/poll/')->to('archive#poll');
$r->get('/my/messages')->to('my#messages', seclev => 1);
$r->get('/my/')->to('user#home', seclev => 1);
+ # User Register
+ $r->get('/my/newuser')->to('login#newuser');
+ $r->post('/my/newuser')->to('login#newuser', captcha_check => 1);
+ $r->get('/my/activation')->to('login#activation');
+ $r->get('/my/resetpassword')->to('login#reset_password');
+ $r->post('/my/resetpassword')->to('login#reset_password', captcha_check => 1);
+
+ # Change Email
+ $r->get('/my/change_email')->to('my#change_email', seclev => 1);
+
# search page
$r->get('/search')->to('search#search');
+ # about
+ $r->get('/about')->to('about#about');
+
+ #faq
+ $r->get('/faq/editorial')->to('faq#editorial');
+ $r->get('/faq/UI')->to('faq#UI');
+ $r->get('/faq/firehose')->to('faq#firehose');
+ $r->get('/faq/com-mod')->to('faq#com_mod');
+ $r->get('/faq/metamod')->to('faq#metamod');
+ $r->get('/faq/accounts')->to('faq#accounts');
+ $r->get('/faq/friends')->to('faq#friends');
+ $r->get('/faq/tech')->to('faq#tech');
+ $r->get('/faq/')->to('faq#faq');
+
# Admin
# pages under /admin needs seclev equal or greater than 10000;
my $admin = $r->under('/admin' => sub { my $c = shift; $c->stash(seclev => 10000); return 1; });
$admin->get('/sidebar')->to('admin-sidebar#index');
$admin->get('/feed')->to('admin-feed#index');
+ $admin->get('/filter')->to('admin-filter#index');
$admin->get('/blocking')->to('admin-blocking#index');
$admin->get('/ad')->to('admin-ads#index');
# Admin API
# pages under /api/v1/admin needs seclev equal or greater than 10000;
my $admin_api = $r->under('/api/v1/admin' => sub { my $c = shift; $c->stash(seclev => 10000); return 1; });
+
$admin_api->get('/feed')->to('API::Admin::Feed#get');
$admin_api->post('/feed')->to('API::Admin::Feed#post');
+ $admin_api->get('/filter')->to('API::Admin::Filter#get');
+ $admin_api->post('/filter')->to('API::Admin::Filter#post');
$admin_api->get('/blocking')->to('API::Admin::Blocking#get');
$admin_api->post('/blocking')->to('API::Admin::Blocking#post');
my $api = $r->under('/api/v1');
$api->post('/login')->to('API::Login#login');
+ $api->post('/newuser/validate')->to('API::User#validate_new_user');
+ $api->post('/newuser/create')->to('API::User#create_new_user');
+ $api->post('/newuser/password')->to('API::User#newuser_password');
+
$api->get('/sidebar/item')->to('API::SidebarItem#get', seclev => 1);
$api->get('/comment')->to('API::Comment#get');
$api->get('/story')->to('API::Story#get');
$api->post('/story')->to('API::Story#post');
+ $api->get('/timeline')->to('API::Timeline#get');
+
$api->get('/poll')->to('API::Poll#get');
$api->post('/poll')->to('API::Poll#post');
$api->post('/vote')->to('API::Poll#vote', csrf_check_id => 'vote');
# user page
# warning: these pathes uses regexp matching, so must write in tail of route definitions.
- my $user = $r->under('/:nickname');
- $user->get('/' => [nickname => qr/~.*/])->to('user#home');
- $user->get('/journals' => [nickname => qr/~.*/])->to('user#journals');
- $user->get('/journal' => [nickname => qr/~.*/])->to('user#journals'); # for compatibility
- $user->get('/comments' => [nickname => qr/~.*/])->to('user#comments');
- $user->get('/submissions' => [nickname => qr/~.*/])->to('user#submissions');
- $user->get('/friends' => [nickname => qr/~.*/])->to('user#friends');
- $user->get('/foes' => [nickname => qr/~.*/])->to('user#foes');
- $user->get('/fans' => [nickname => qr/~.*/])->to('user#fans');
- $user->get('/freaks' => [nickname => qr/~.*/])->to('user#freaks');
- $user->get('/achievements' => [nickname => qr/~.*/])->to('user#achievements');
- #$r->get('/:user_name/journal' => [user_name => qr/~.*/])->to('journal#user_journals');
+ my $user = $r->under('/~:nickname');
+ $user->get('/' => [nickname => qr/.*/])->to('user#home');
+ $user->get('/journal/:id' => [nickname => qr/.*/])->to('journal#single');
+ $user->get('/journals' => [nickname => qr/.*/])->to('user#journals');
+ $user->get('/journal' => [nickname => qr/.*/])->to('user#journals'); # for compatibility
+ $user->get('/comments' => [nickname => qr/.*/])->to('user#comments');
+ $user->get('/submissions' => [nickname => qr/.*/])->to('user#submissions');
+ $user->get('/friends' => [nickname => qr/.*/])->to('user#friends');
+ $user->get('/foes' => [nickname => qr/.*/])->to('user#foes');
+ $user->get('/fans' => [nickname => qr/.*/])->to('user#fans');
+ $user->get('/freaks' => [nickname => qr/.*/])->to('user#freaks');
+ $user->get('/achievements' => [nickname => qr/.*/])->to('user#achievements');
}