Sequenzia/app/controllers/ApplicationController.php
2013-10-26 18:06:58 -05:00

421 lines
15 KiB
PHP
Executable File

<?php
class ApplicationController extends Rails\ActionController\Base
{
public function __call($method, $params)
{
if (preg_match("/^(\w+)_only$/", $method, $m)) {
if (current_user()->{'is_' . $m[1] . '_or_higher'}()) {
return true;
} else {
$this->access_denied();
return false;
}
}
# For many actions, GET invokes the HTML UI, and a POST actually invokes
# the action, so we often want to require higher access for POST (so the UI
# can invoke the login dialog).
elseif (preg_match("/^post_(\w+)_only$/", $method, $m)) {
if (!$this->request()->isPost())
return true;
elseif (current_user()->{'is_' . $m[1] . '_or_higher'}())
return true;
else {
$this->access_denied();
return false;
}
}
return parent::__call($method, $params);
}
/**
* This is found in SessionHelper in Moebooru
*/
public function page_number()
{
if (!isset($this->page_number))
$this->page_number = $this->params()->page ?: 1;
return $this->page_number;
}
# LoginSystem {
protected function access_denied()
{
$previous_url = $this->params()->url || $this->request()->fullPath();
$this->respondTo([
'html' => function()use($previous_url) {
$this->notice('Access denied');
$this->redirectTo("user#login", array('url' => $previous_url));
},
'xml' => function() {
$this->render(array('xml' => array('success' => false, 'reason' => "access denied"), 'root' => "response", 'status' => 403));
},
'json' => function() {
$this->render(array('json' => array('success' => false, 'reason' => "access denied"), 'status' => 403));
}
]);
}
public function user_can_see_posts()
{
if (!current_user()->can_see_posts()) {
$this->access_denied();
}
}
protected function set_current_user()
{
$user = null;
$AnonymousUser = array(
'id' => 0,
'level' => 0,
'name' => "Anonymous",
'show_samples' => true,
'language' => '',
'secondary_languages' => '',
'pool_browse_mode' => 1,
'always_resize_images' => true,
'ip_addr' => $this->request()->remoteIp()
);
if (!current_user() && $this->session()->user_id) {
$user = User::where(['id' => $this->session()->user_id])->first();
} else {
if ($this->cookies()->login && $this->cookies()->pass_hash) {
$user = User::authenticate_hash($this->cookies()->login, $this->cookies()->pass_hash);
} elseif (isset($this->params()->login) && isset($this->params()->password_hash)) {
$user = User::authenticate($this->params()->login, $this->params()->password_hash);
} elseif (isset($this->params()->user['name']) && isset($this->params()->user['password'])) {
$user = User::authenticate($this->params()->user['name'], $this->params()->user['password']);
}
$user && $user->updateAttribute('last_logged_in_at', date('Y-m-d H:i:s'));
}
if ($user) {
if ($user->is_blocked() && $user->ban && $user->ban->expires_at < date('Y-m-d H:i:s')) {
$user->updateAttribute('level', CONFIG()->starting_level);
Ban::destroyAll("user_id = ".$user->id);
}
$this->session()->user_id = $user->id;
} else {
$user = new User();
$user->assignAttributes($AnonymousUser, ['without_protection' => true]);
}
User::set_current_user($user);
$this->current_user = $user;
# For convenient access in activerecord models
$user->ip_addr = $this->request()->remoteIp();
Moebooru\Versioning\Versioning::init_history();
if (!current_user()->is_anonymous())
current_user()->log($this->request()->remoteIp());
}
# iTODO:
protected function set_country()
{
current_user()->country = '--';
// current_user()->country = Rails::cache()->fetch(['type' => 'geoip', 'ip' => $this->request()->remote_ip()], ['expires_in' => '+1 month']) do
// begin
// GeoIP->new(Rails.root.join('db', 'GeoIP.dat').to_s).country($this->request()->remote_ip()).country_code2
// rescue
// '--'
// end
// end
}
# } RespondToHelpers {
protected function respond_to_success($notice, $redirect_to_params, array $options = array())
{
$extra_api_params = isset($options['api']) ? $options['api'] : array();
$this->respondTo(array(
'html' => function() use ($notice, $redirect_to_params) {
$this->notice($notice);
$this->redirectTo($redirect_to_params);
},
'json' => function() use ($extra_api_params) {
$this->render(array('json' => array_merge($extra_api_params, array('success' => true))));
},
'xml' => function() use ($extra_api_params) {
$this->render(array('xml' => array_merge($extra_api_params, array('success' => true)), 'root' => "response"));
}
));
}
protected function respond_to_error($obj, $redirect_to_params, $options = array())
{
!is_array($redirect_to_params) && $redirect_to_params = array($redirect_to_params);
$extra_api_params = isset($options['api']) ? $options['api'] : array();
$status = isset($options['status']) ? $options['status'] : 500;
if ($obj instanceof Rails\ActiveRecord\Base) {
$obj = $obj->errors()->fullMessages(", ");
$status = 420;
}
if ($status == 420)
$status = "420 Invalid Record";
elseif ($status == 421)
$status = "421 User Throttled";
elseif ($status == 422)
$status = "422 Locked";
elseif ($status == 423)
$status = "423 Already Exists";
elseif ($status == 424)
$status = "424 Invalid Parameters";
$this->respondTo(array(
'html' => function()use($obj, $redirect_to_params) {
$this->notice("Error: " . $obj);
$this->redirectTo($redirect_to_params);
},
'json' => function()use($obj, $extra_api_params, $status) {
$this->render(array('json' => array_merge($extra_api_params, array('success' => false, 'reason' => $obj)), 'status' => $status));
},
'xml' => function()use($obj, $extra_api_params, $status) {
$this->render(array('xml' => array_merge($extra_api_params, array('success' => false, 'reason' => $obj)), 'root' => "response", 'status' => $status));
}
));
}
protected function respond_to_list($inst_var_name, array $formats = array())
{
$inst_var = $this->$inst_var_name;
$this->respondTo(array(
'html',
isset($formats['atom']) ? 'atom' : null,
'json' => function() use ($inst_var) {
$this->render(array('json' => $inst_var->toJson()));
},
'xml' => function() use ($inst_var, $inst_var_name) {
$this->render(array('xml' => $inst_var, 'root' => $inst_var_name));
}
));
}
protected function _render_error($record)
{
$this->record = $record;
$this->render(['inline' => '<?= $this->record->errors()->fullMessages("<br />") ?>', 'layout' => "bare", 'status' => 500]);
}
# }
// protected :build_cache_key
// protected :get_cache_key
public function get_ip_ban()
{
$ban = IpBans::where("ip_addr = ?", $this->request()->remoteIp())->first();
return $ban ?: null;
}
protected function check_ip_ban()
{
if ($this->request()->controller() == "banned" and $this->request()->action() == "index") {
return;
}
$ban = $this->get_ip_ban();
if (!$ban) {
return;
}
if ($ban->expires_at && $ban->expires_at < date('Y-m-d H:i:s')) {
IpBans::destroyAll("ip_addr = '{$this->request()->remoteIp()}'");
return;
}
$this->redirectTo('banned#index');
}
protected function save_tags_to_cookie()
{
if ($this->params()->tags || (is_array($this->params()->post) && isset($this->params()->post['tags']))) {
$post_tags = isset($this->params()->post['tags']) ? (string)$this->params()->post['tags'] : '';
$tags = TagAlias::to_aliased(explode(' ', (strtolower($this->params()->tags ?: $post_tags))));
if ($recent_tags = trim($this->cookies()->recent_tags))
$tags = array_merge($tags, explode(' ', $recent_tags));
$this->cookies()->recent_tags = implode(" ", array_slice($tags, 0, 20));
}
}
public function set_cache_headers()
{
$this->response()->headers()->add("Cache-Control", "max-age=300");
}
# iTODO:
public function cache_action()
{
// if ($this->request()->method() == 'get' && !preg_match('/Googlebot/', $this->request()->env()) && $this->params()->format != "xml" && $this->params()->format != "json") {
// list($key, $expiry) = $this->get_cache_key($this->controller_name(), $this->action_name(), $this->params(), 'user' => current_user());
// if ($key && count($key) < 200) {
// $cached = Rails::cache()->read($key);
// if ($cached) {
// $this->render(['text' => $cached, 'layout' => false]);
// return;
// }
// }
// $this->yield();
// if ($key && strpos($this->response->headers['Status'], '200') === 0) {
// Rails::cache()->write($key, $this->response->body, ['expires_in' => $expiry]);
// }
// } else {
// $this->yield();
// }
}
protected function init_cookies()
{
if ($this->request()->format() == "xml" || $this->request()->format() == "json")
return;
$forum_posts = ForumPost::where("parent_id IS NULL")->order("updated_at DESC")->limit(10)->take();
$this->cookies()->current_forum_posts = json_encode(array_map(function($fp) {
if (current_user()->is_anonymous()) {
$updated = false;
} else {
$updated = $fp->updated_at > current_user()->last_forum_topic_read_at;
}
return [$fp->title, $fp->id, $updated, ceil($fp->response_count / 30.0)];
}, $forum_posts->members()));
$this->cookies()->country = current_user()->country;
if (!current_user()->is_anonymous()) {
$this->cookies()->user_id = (string)current_user()->id;
$this->cookies()->user_info = current_user()->user_info_cookie();
$this->cookies()->has_mail = (current_user()->has_mail ? "1" : "0");
$this->cookies()->forum_updated = (current_user()->is_privileged_or_higher() && ForumPost::updated(current_user()) ? "1" : "0");
$this->cookies()->comments_updated = (current_user()->is_privileged_or_higher() && Comment::updated(current_user()) ? "1" : "0");
if (current_user()->is_janitor_or_higher()) {
$mod_pending = Post::where("status = 'flagged' OR status = 'pending'")->count();
$this->cookies()->mod_pending = (string)$mod_pending;
}
if (current_user()->is_blocked()) {
if (current_user()->ban)
$this->cookies()->block_reason = "You have been blocked. Reason: ".current_user()->ban->reason.". Expires: ".substr(current_user()->ban->expires_at, 0, 10);
else
$this->cookies()->block_reason = "You have been blocked.";
} else
$this->cookies()->block_reason = "";
$this->cookies()->resize_image = (current_user()->always_resize_images ? "1" : "0");
$this->cookies()->show_advanced_editing = (current_user()->show_advanced_editing ? "1" : "0");
$this->cookies()->my_tags = current_user()->my_tags;
$this->cookies()->blacklisted_tags = json_encode(current_user()->blacklisted_tags_array());
$this->cookies()->held_post_count = (string)current_user()->held_post_count();
} else {
$this->cookies()->delete('user_info');
$this->cookies()->delete('login');
$this->cookies()->blacklisted_tags = json_encode(CONFIG()->default_blacklists);
}
}
protected function set_title($title = null)
{
if (!$title)
$title = CONFIG()->app_name;
else
$title .= ' | ' . CONFIG()->app_name;
$this->page_title = $title;
}
protected function notice($str)
{
$this->cookies()->notice = $str;
}
protected function set_locale()
{
if ($this->params()->locale and in_array($this->params()->locale, CONFIG()->available_locales)) {
$this->cookies()->locale = [ 'value' => $this->params()->locale, 'expires' => '+1 year' ];
$this->I18n()->setLocale($this->params()->locale);
} elseif ($this->cookies()->locale and in_array($this->cookies()->locale, CONFIG()->available_locales)) {
$this->I18n()->setLocale($this->cookies()->locale);
} else
$this->I18n()->setLocale(CONFIG()->default_locale);
}
protected function sanitize_params()
{
if ($this->params()->page) {
if ($this->params()->page < 1)
$this->params()->page = 1;
} else
$this->params()->page = 1;
}
protected function admin_only()
{
if (!current_user()->is_admin())
$this->access_denied();
}
protected function member_only()
{
if (!current_user()->is_member_or_higher())
$this->access_denied();
}
protected function post_privileged_only()
{
if (!current_user()->is_privileged_or_higher())
$this->access_denied();
}
protected function post_member_only()
{
if (!current_user()->is_member_or_higher())
$this->access_denied();
}
protected function no_anonymous()
{
if (current_user()->is_anonymous())
$this->access_denied();
}
protected function sanitize_id()
{
$this->params()->id = (int)$this->params()->id;
}
# iTODO:
protected function filters()
{
return [
'before' => [
'set_current_user',
'set_country',
'set_locale',
'set_title',
'sanitize_params',
'check_ip_ban'
],
'after' => [
'init_cookies'
]
];
}
}