merged dev

This commit is contained in:
Parziphal 2013-11-19 15:16:56 -05:00
commit fb7177093b
35 changed files with 939 additions and 167 deletions

View File

@ -33,8 +33,11 @@ Go to the location where you want MyImouto to be installed, then clone the repo,
* If you're not accessing the site locally, list the IP address you'll connect from in the 'safe_ips' array in _install/config.php_. * If you're not accessing the site locally, list the IP address you'll connect from in the 'safe_ips' array in _install/config.php_.
* Go to your site to complete the installation. After installation is completed, you may delete the install folder. * Go to your site to complete the installation. After installation is completed, you may delete the install folder.
* If you have problems, read below the Troubleshooting section or report them in the issues section. * If you have problems, read below the Troubleshooting section or report them in the issues section.
Updating
--------
Every time you update the files with `remote update` or something, also run `composer update` to update dependencies, specially for the framework. Every time you update the files with `git remote update` or something, also run `composer update` to update dependencies, specially for the framework, and also `php config/boot.php db:migrate` to run database migrations.
Troubleshooting Troubleshooting
--------------- ---------------

View File

@ -25,7 +25,7 @@ class CommentController extends ApplicationController
{ {
$comment = Comment::find($this->params()->id); $comment = Comment::find($this->params()->id);
if (current_user()->has_permission($comment)) { if (current_user()->has_permission($comment)) {
$comment->updateAttributes($this->params()->comment); $comment->updateAttributes(array_merge($this->params()->comment, ['updater_ip_addr' => $this->request()->remoteIp()]));
$this->respond_to_success("Comment updated", '#index'); $this->respond_to_success("Comment updated", '#index');
} else { } else {
$this->access_denied(); $this->access_denied();
@ -52,7 +52,7 @@ class CommentController extends ApplicationController
} }
$user_id = current_user()->id; $user_id = current_user()->id;
Rails::log($this->params()->comment);
$comment = new Comment(array_merge($this->params()->comment, array('ip_addr' => $this->request()->remoteIp(), 'user_id' => $user_id))); $comment = new Comment(array_merge($this->params()->comment, array('ip_addr' => $this->request()->remoteIp(), 'user_id' => $user_id)));
if ($this->params()->commit == "Post without bumping") { if ($this->params()->commit == "Post without bumping") {
$comment->do_not_bump_post = true; $comment->do_not_bump_post = true;

View File

@ -36,7 +36,7 @@ class DmailController extends ApplicationController
$dmail = $this->params()->dmail; $dmail = $this->params()->dmail;
if (empty($dmail['parent_id'])) if (empty($dmail['parent_id']))
$dmail['parent_id'] = null; $dmail['parent_id'] = null;
$this->dmail = Dmail::create(array_merge($dmail, ['from_id' => $this->current_user->id])); $this->dmail = Dmail::create(array_merge($dmail, ['from_id' => $this->current_user->id, 'ip_addr' => $this->request()->remoteIp()]));
if ($this->dmail->errors()->none()) { if ($this->dmail->errors()->none()) {
$this->notice("Message sent to ".$dmail['to_name']); $this->notice("Message sent to ".$dmail['to_name']);

View File

@ -65,7 +65,7 @@ class ForumController extends ApplicationController
if (empty($params['parent_id']) || !ctype_digit($params['parent_id'])) if (empty($params['parent_id']) || !ctype_digit($params['parent_id']))
$params['parent_id'] = null; $params['parent_id'] = null;
$this->forum_post = ForumPost::create(array_merge($params, ['creator_id' => $this->current_user->id])); $this->forum_post = ForumPost::create(array_merge($params, ['creator_id' => $this->current_user->id, 'ip_addr' => $this->request()->remoteIp()]));
if ($this->forum_post->errors()->blank()) { if ($this->forum_post->errors()->blank()) {
if (!$this->params()->forum_post['parent_id']) { if (!$this->params()->forum_post['parent_id']) {
@ -120,10 +120,12 @@ class ForumController extends ApplicationController
return; return;
} }
$this->forum_post->assignAttributes($this->params()->forum_post); $this->forum_post->assignAttributes(array_merge($this->params()->forum_post, ['updater_ip_addr' => $this->request()->remoteIp()]));
if ($this->forum_post->save()) { if ($this->forum_post->save()) {
$this->notice("Post updated"); $this->notice("Post updated");
$this->redirectTo(["#show", 'id' => $this->forum_post->root_id(), 'page' => ceil($this->forum_post->root()->response_count / 30.0)]);
$page = $this->params()->page ? $this->page_number() : ceil($this->forum_post->root()->response_count / 30.0);
$this->redirectTo(["#show", 'id' => $this->forum_post->root_id(), 'page' => $page]);
} else { } else {
$this->_render_error($this->forum_post); $this->_render_error($this->forum_post);
} }
@ -132,7 +134,7 @@ class ForumController extends ApplicationController
public function show() public function show()
{ {
$this->forum_post = ForumPost::find($this->params()->id); $this->forum_post = ForumPost::find($this->params()->id);
$this->children = ForumPost::where("parent_id = ?", $this->params()->id)->order("id")->paginate($this->page_number(), 30); $this->children = ForumPost::where("parent_id = ?", $this->params()->id)->order("id")->paginate($this->page_number(), 30);
if (!$this->current_user->is_anonymous() && $this->current_user->last_forum_topic_read_at < $this->forum_post->updated_at && $this->forum_post->updated_at < (time() - 3)) { if (!$this->current_user->is_anonymous() && $this->current_user->last_forum_topic_read_at < $this->forum_post->updated_at && $this->forum_post->updated_at < (time() - 3)) {
$this->current_user->updateAttribute('last_forum_topic_read_at', $this->forum_post->updated_at); $this->current_user->updateAttribute('last_forum_topic_read_at', $this->forum_post->updated_at);

View File

@ -0,0 +1,5 @@
<?php
class Advertisement extends Rails\ActiveRecord\Base
{
}

View File

@ -65,10 +65,10 @@ class Comment extends Rails\ActiveRecord\Base
{ {
$source_lang_list = implode(',', $source_langs); $source_lang_list = implode(',', $source_langs);
$key = "comment:" . $this->id . ":" . strtotime($this->updated_at) . ":" . $target_lang . ":" . $source_lang_list; $key = "comment:" . $this->id . ":" . strtotime($this->updated_at) . ":" . $target_lang . ":" . $source_lang_list;
# TODO
// return Rails::cache()->fetch($key) { return Rails::cache()->fetch($key, function() use ($target_lang, $source_langs) {
return $this->get_translated_formatted_body_uncached($target_lang, $source_langs); return $this->get_translated_formatted_body_uncached($target_lang, $source_langs);
// } });
} }
public function author() public function author()

View File

@ -21,21 +21,21 @@ class FlaggedPostDetail extends Rails\ActiveRecord\Base
static public function new_deleted_posts($user) static public function new_deleted_posts($user)
{ {
if ($user->is_anonymous()) if ($user->is_anonymous()) {
return 0; return 0;
}
return self::connection()->selectValue( return Rails::cache()->fetch(
"SELECT COUNT(*) FROM flagged_post_details fpd JOIN posts p ON (p.id = fpd.post_id) " . 'deleted_posts:'.$user->id.':'.$user->last_deleted_post_seen_at,
"WHERE p.status = 'deleted' AND p.user_id = ? AND fpd.user_id <> ? AND fpd.created_at > ?", ['expires_in' => '1 minute'],
$user->id, $user->id, $user->last_deleted_post_seen_at function() use ($user) {
return self::connection()->selectValue(
"SELECT COUNT(*) FROM flagged_post_details fpd JOIN posts p ON (p.id = fpd.post_id) " .
"WHERE p.status = 'deleted' AND p.user_id = ? AND fpd.user_id <> ? AND fpd.created_at > ?",
$user->id, $user->id, $user->last_deleted_post_seen_at
);
}
); );
# iTODO:
// return Rails.cache.fetch("deleted_posts:#{user.id}:#{user.last_deleted_post_seen_at.to_i}", :expires_in => 1.minute) do
// select_value_sql(
// "SELECT COUNT(*) FROM flagged_post_details fpd JOIN posts p ON (p.id = fpd.post_id) " +
// "WHERE p.status = 'deleted' AND p.user_id = ? AND fpd.user_id <> ? AND fpd.created_at > ?",
// user.id, user.id, user.last_deleted_post_seen_at).to_i
// end
} }
# XXX: author and flagged_by are redundant # XXX: author and flagged_by are redundant
@ -73,4 +73,4 @@ class FlaggedPostDetail extends Rails\ActiveRecord\Base
// {(options = array()) // {(options = array())
// return; api_attributes.to_xml(options.reverse_merge('root' => "flagged_post_detail")) // return; api_attributes.to_xml(options.reverse_merge('root' => "flagged_post_detail"))
// } // }
} }

View File

@ -18,7 +18,7 @@ class ForumPost extends Rails\ActiveRecord\Base
protected function callbacks() protected function callbacks()
{ {
return [ return [
'after_create' => ['initialize_last_updated_by', 'update_parent_on_create'], 'after_create' => ['initialize_last_updated_by', 'update_parent_on_create', 'clear_cache'],
'before_destroy' => ['update_parent_on_destroy'], 'before_destroy' => ['update_parent_on_destroy'],
'before_validation' => ['validate_title', 'validate_lock'] 'before_validation' => ['validate_title', 'validate_lock']
]; ];
@ -180,4 +180,9 @@ class ForumPost extends Rails\ActiveRecord\Base
{ {
return $this->creator->name; return $this->creator->name;
} }
}
protected function clear_cache()
{
Rails::cache()->delete("forum_posts");
}
}

View File

@ -104,12 +104,12 @@ class History extends Rails\ActiveRecord\Base
foreach (array_reverse($stack) as $node) { foreach (array_reverse($stack) as $node) {
$object = $node['o']; $object = $node['o'];
/** // /**
* MI: Only Pool model sets the undo (:after) callback. // * MI: Only Pool model sets the undo (:after) callback.
* Calling it manually at the end because runCallbacks doesn't behave like in Rails. // * Calling it manually at the end because runCallbacks doesn't behave like in Rails.
* TODO: fix callbacks in the framework and update this. // * TODO: fix callbacks in the framework and update this.
*/ // */
// $object->runCallbacks('undo', function() { $object->runCallbacks('undo', function() {
$changes = !empty($node['changes']) ? $node['changes'] : []; $changes = !empty($node['changes']) ? $node['changes'] : [];
if ($changes) { if ($changes) {
@ -137,8 +137,8 @@ class History extends Rails\ActiveRecord\Base
} }
} }
} }
$object->runCallbacks('after_undo'); // $object->runCallbacks('after_undo');
// }); });
$object->save(); $object->save();
} }

View File

@ -61,11 +61,11 @@ class Note extends Rails\ActiveRecord\Base
protected function callbacks() protected function callbacks()
{ {
return array_merge_recursive([ return [
'after_save' => [ 'after_save' => [
'update_post' 'update_post'
] ]
], $this->versioning_callbacks(), $this->versioningCallbacks()); ];
} }
protected function validations() protected function validations()

View File

@ -362,11 +362,11 @@ class Pool extends Rails\ActiveRecord\Base
protected function callbacks() protected function callbacks()
{ {
return array_merge_recursive([ return [
'before_destroy' => ['destroy_pool_posts'], 'before_destroy' => ['destroy_pool_posts'],
'after_save' => ['expire_cache'], 'after_save' => ['expire_cache'],
'before_validation' => ['normalize_name'], 'before_validation' => ['normalize_name'],
'after_undo' => ['update_pool_links'] 'after_undo' => ['update_pool_links']
], $this->versioning_callbacks()); ];
} }
} }

View File

@ -42,10 +42,10 @@ class PoolPost extends Rails\ActiveRecord\Base
protected function callbacks() protected function callbacks()
{ {
return array_merge_recursive([ return [
'before_create' => ['set_active_changed'], # MI 'before_create' => ['set_active_changed'], # MI
'after_save' => ['expire_cache'] 'after_save' => ['expire_cache']
], $this->versioning_callbacks()); ];
} }
public function can_change(User $user, $attribute) public function can_change(User $user, $attribute)

View File

@ -195,8 +195,9 @@ class Post extends Rails\ActiveRecord\Base
public function first_delete() public function first_delete()
{ {
$this->updateAttributes(array('status' => 'deleted')); $this->runCallbacks('delete', function() {
$this->runCallbacks('after_delete'); $this->updateAttributes(array('status' => 'deleted'));
});
} }
public function delete_from_database() public function delete_from_database()
@ -211,14 +212,14 @@ class Post extends Rails\ActiveRecord\Base
$this->runCallbacks('after_destroy'); $this->runCallbacks('after_destroy');
} }
# This method is in status_methods
public function undelete() public function undelete()
{ {
$this->status = 'active'; if ($this->status == 'active') {
$this->save(); return;
if ($this->parent_id) {
Post::update_has_children($this->parent_id);
} }
$this->runCallbacks('undelete', function() {
$this->updateAttributes(['status' => 'active']);
});
} }
public function service_icon() public function service_icon()
@ -228,20 +229,28 @@ class Post extends Rails\ActiveRecord\Base
protected function callbacks() protected function callbacks()
{ {
return array_merge_recursive([ return [
'before_save' => ['commit_tags', 'filter_parent_id'],
'before_create' => ['set_index_timestamp'], 'before_create' => ['set_index_timestamp'],
'after_create' => ['after_creation'], 'after_create' => ['after_creation'],
'after_delete' => ['clear_avatars', 'give_favorites_to_parent'],
'before_delete' => ['clear_avatars'],
'after_delete' => ['give_favorites_to_parent', 'decrement_count'],
'after_undelete'=> ['increment_count'],
'before_save' => ['commit_tags', 'filter_parent_id'],
'after_save' => ['update_parent', 'save_post_history', 'expire_cache'], 'after_save' => ['update_parent', 'save_post_history', 'expire_cache'],
'after_destroy' => ['expire_cache'], 'after_destroy' => ['expire_cache'],
'after_validation_on_create' => ['before_creation'],
'before_validation_on_create' => [ 'before_validation_on_create' => [
'download_source', 'ensure_tempfile_exists', 'determine_content_type', 'download_source', 'ensure_tempfile_exists', 'determine_content_type',
'validate_content_type', 'generate_hash', 'set_image_dimensions', 'validate_content_type', 'generate_hash', 'set_image_dimensions',
'set_image_status', 'check_pending_count', 'generate_sample', 'set_image_status', 'check_pending_count', 'generate_sample',
'generate_jpeg', 'generate_preview', 'move_file'] 'generate_jpeg', 'generate_preview', 'move_file'
], $this->versioning_callbacks()); ],
'after_validation_on_create' => ['before_creation']
];
} }
protected function associations() protected function associations()

View File

@ -5,25 +5,30 @@ trait PostCountMethods
{ {
# A small sanitation # A small sanitation
$tags = preg_replace('/ +/', ' ', trim($tags)); $tags = preg_replace('/ +/', ' ', trim($tags));
$cache_version = (int)Rails::cache()->read('$cache_version');
# No cache. This query is too slow, if no tags, just return row_count(). # iTODO: cache hash key
if (!$tags) { $key = 'post_count.' . $tags . ':' . 'v.' . $cache_version;
return self::row_count();
}
// cache_version = Rails.cache.read("$cache_version").to_i
# Use base64 encoding of tags query for memcache key
// tags_base64 = Base64.urlsafe_encode64(tags)
// key = "post-count/v=#{cache_version}/#{tags_base64}"
// count = Rails.cache.fetch(key) { $count = (int)Rails::cache()->fetch($key, function() use ($tags) {
// Post.count_by_sql(Post.generate_sql(tags, :count => true)) list($sql, $params) = Post::generate_sql($tags, ['count' => true]);
// }.to_i array_unshift($params, $sql);
list($sql, $params) = Post::generate_sql($tags, array('count' => true)); return Post::countBySql($params);
// vde($sql); });
array_unshift($params, $sql);
return $count;
return Post::countBySql($params);
# This is just too brittle, and hard to make work with other features that may
# hide posts from the index.
# if tags.blank?
# return select_value_sql("SELECT row_count FROM table_data WHERE name = 'posts'").to_i
# else
# c = select_value_sql("SELECT post_count FROM tags WHERE name = ?", tags).to_i
# if c == 0
# return Post.count_by_sql(Post.generate_sql(tags, :count => true))
# else
# return c
# end
# end
} }
static public function recalculate_row_count() static public function recalculate_row_count()

View File

@ -114,11 +114,13 @@ trait PostStatusMethods
return $hold; return $hold;
} }
public function undelete() # MI: Can't have a method with bang!
{ // public function undelete!()
if ($this->status == 'active') // {
return; // $this->status = 'active';
$this->updateAttribute('status', 'active'); // $this->save();
$this->runCallbacks('after_undelete'); // if ($this->parent_id) {
} // Post::update_has_children($this->parent_id);
// }
// }
} }

View File

@ -324,7 +324,7 @@ trait PostTagMethods
$this->new_tags = array_map(function ($x) use (&$new_tags_ids, &$new_tags_names) { $this->new_tags = array_map(function ($x) use (&$new_tags_ids, &$new_tags_names) {
$tag = Tag::find_or_create_by_name($x); $tag = Tag::find_or_create_by_name($x);
if (!in_array($tag->id, $new_tags_ids)) { if (!in_array($tag->id, $new_tags_ids)) {
$new_tags_ids[] = $tag->id; $new_tags_ids[] = $tag->id;
$new_tags_names[] = $tag->name; $new_tags_names[] = $tag->name;
return $tag; return $tag;
} }
@ -352,6 +352,10 @@ trait PostTagMethods
} }
} }
# Sort
sort($new_tags_names);
sort($this->new_tags);
$tag_set = implode(", ", array_map(function($x){return "(".$this->id.", ".$x->id.")";}, $this->new_tags)); $tag_set = implode(", ", array_map(function($x){return "(".$this->id.", ".$x->id.")";}, $this->new_tags));
$this->cached_tags = implode(' ', $new_tags_names); $this->cached_tags = implode(' ', $new_tags_names);

View File

@ -315,9 +315,9 @@ class Tag extends Rails\ActiveRecord\Base
# #
# === Parameters # === Parameters
# * :tag_name<String>:: The tag name to search for # * :tag_name<String>:: The tag name to search for
# TODO
static public function type_name($tag_name) static public function type_name($tag_name)
{ {
# iTODO: hash key
return Rails::cache()->fetch('tag_type.' . $tag_name, ['expires_in' => '1 day'], function() use ($tag_name) { return Rails::cache()->fetch('tag_type.' . $tag_name, ['expires_in' => '1 day'], function() use ($tag_name) {
return self::type_name_helper(str_replace(' ', '_', $tag_name)); return self::type_name_helper(str_replace(' ', '_', $tag_name));
}); });
@ -362,29 +362,29 @@ class Tag extends Rails\ActiveRecord\Base
# Get all tag types for the given tags. # Get all tag types for the given tags.
static public function batch_get_tag_types($post_tags) static public function batch_get_tag_types($post_tags)
{ {
$types = []; $post_tags_key = [];
foreach ($post_tags as $tag) {
$types[$tag] = self::type_name($tag);
}
return $types;
// $post_tags = Set.new(post_tags) foreach ($post_tags as $t) {
# iTODO: hash keys.
// post_tags_key = post_tags.each_with_object([]) { |t, k| k << { :tag_type => t } } $post_tags_key[] = 'tag_type.' . $t;
// # Without this, the following splat will eat the last argument because }
// # it'll be considered an option instead of key (being a hash). # Without this, the following splat will eat the last argument because
// post_tags_key << {} # it'll be considered an option instead of key (being a hash).
$post_tags_key[] = [];
// results = {}
// Rails.cache.read_multi(*post_tags_key).each do |cache_key, value| $results = [];
// # The if cache_key is required since there's small chance read_multi $cached = call_user_func_array([Rails::cache(), 'readMulti'], $post_tags_key);
// # returning nil key on certain key names. foreach ($cached as $cache_key => $value) {
// results[cache_key[:tag_type]] = value if cache_key # The if cache_key is required since there's small chance read_multi
// end # returning nil key on certain key names.
// (post_tags - results.keys).each do |tag| // if ($cache_key) {
// results[tag] = type_name(tag) $results[substr($cache_key, 9)] = $value;
// end // }
// return results }
foreach( array_diff( $post_tags, array_keys($results) ) as $tag ) {
$results[$tag] = self::type_name($tag);
}
return $results;
} }
# Returns tags (with type specified by input) related by input tag # Returns tags (with type specified by input) related by input tag
@ -414,15 +414,6 @@ class Tag extends Rails\ActiveRecord\Base
$reduced[] = ['name' => $row['name'], 'post_count' => $row['post_count']]; $reduced[] = ['name' => $row['name'], 'post_count' => $row['post_count']];
} }
return $reduced; return $reduced;
// return Post::select('posts.*, tags.name AS tag_name, tags.post_count AS tag_post_count')
// ->joins('JOIN posts_tags pt ON posts.id = pt.post_id JOIN tags ON pt.tag_id = tags.id')
// ->where('posts.status <> "deleted"')->where('tags.name IN (?)', $tag)
// ->where('tags.tag_type = ?', $type)->group('tags.name')->limit($limit)
// ->take()->reduce([], function($result, $hash) {
// $result[] = ['name' => $hash->tag_name, 'post_count' => $hash->tag_post_count];
// return $result;
// });
}); });
} }
@ -465,6 +456,7 @@ class Tag extends Rails\ActiveRecord\Base
!is_array($tags) && $tags = array($tags); !is_array($tags) && $tags = array($tags);
# iTODO: hash key
return Rails::cache()->fetch('category.reltags.tags.' . implode(',', $tags), ['expires_in' => '1 hour'], function() use ($tags) { return Rails::cache()->fetch('category.reltags.tags.' . implode(',', $tags), ['expires_in' => '1 hour'], function() use ($tags) {
$from = array("posts_tags pt0"); $from = array("posts_tags pt0");
$cond = array("pt0.post_id = pt1.post_id"); $cond = array("pt0.post_id = pt1.post_id");
@ -507,6 +499,13 @@ class Tag extends Rails\ActiveRecord\Base
return Rails::cache()->fetch('$tag_version', function() { return 0; }); return Rails::cache()->fetch('$tag_version', function() { return 0; });
} }
# Create a compact list of all active tags, sorted by post_count.
#
# "1`tagme` 2`fixme` 3`fixed`alias` "
#
# Each tag is bounded by backticks, so "`tagme`" can be used to match a whole tag.
#
# This is returned as a preencoded JSON string, so the entire block can be cached.
static public function get_json_summary() static public function get_json_summary()
{ {
$summary_version = self::get_summary_version(); $summary_version = self::get_summary_version();
@ -631,13 +630,13 @@ class Tag extends Rails\ActiveRecord\Base
protected function callbacks() protected function callbacks()
{ {
return array_merge_recursive([ return [
'after_save' => [ 'after_save' => [
'update_cache' 'update_cache'
], ],
'after_create' => [ 'after_create' => [
'update_cache_on_create' 'update_cache_on_create'
] ]
], $this->versioning_callbacks()); ];
} }
} }

View File

@ -139,4 +139,4 @@ class TagAlias extends Rails\ActiveRecord\Base
{ {
Moebooru\CacheHelper::expire_tag_version(); Moebooru\CacheHelper::expire_tag_version();
} }
} }

View File

@ -51,21 +51,20 @@ class User extends Rails\ActiveRecord\Base
public function log($ip) public function log($ip)
{ {
// Rails.cache.fetch({ 'type' => :user_logs, 'id' => self.id, 'ip' => ip }, 'expires_in' => 10.minutes) do # iTODO: UserLog doesn't exist yet.
// Rails.cache.fetch({ 'type' => :user_logs, 'id' => :all }, 'expires_id' => 1.day) do return;
// UserLog.where('created_at < ?', 3.days.ago).delete_all
// end # iTODO: hash key
// begin return Rails::cache()->fetch('type.user_logs;id.'.$this->id.';ip.'.$ip, ['expires_in' => '10 minutes'], function() use ($ip) {
// log_entry = self.user_logs.find_or_initialize_by_ip_addr('ip_addr' => ip) # iTODO: hash key
// log_entry.created_at = Time.now Rails::cache()->fetch('type.user_logs;id.all', ['expires_in' => '1 day'], function() {
// log_entry.save return UserLog::where('created_at < ?', date('Y-m-d 0:0:0', strtotime('-3 days')))->deleteAll();
// # Once in a blue moon there will be race condition on find_or_initialize });
// # resulting unique key constraint violation.
// # It doesn't really affect anything so just ignore that error. $log_entry = UserLog::where(['ip_addr' => $ip])->firstOrInitialize();
// rescue ActiveRecord::RecordNotUnique $log_entry->created_at = date('Y-m-d H:i:s');
// true return $log_entry->save();
// end });
// end
} }
# UserBlacklistMethods { # UserBlacklistMethods {
@ -200,10 +199,13 @@ class User extends Rails\ActiveRecord\Base
static public function find_name($user_id) static public function find_name($user_id)
{ {
# iTODO: return Rails::cache()->fetch('user_name:' . $user_id, function() use ($user_id) {
// return Rails.cache.fetch("user_name:#{user_id}") do try {
return self::_find_name_helper($user_id); return self::find($user_id)->name;
// end } catch (Rails\ActiveRecord\Exception\RecordNotFoundException $e) {
return CONFIG()->default_guest_name;
}
});
} }
static public function find_by_name($name) static public function find_by_name($name)
@ -221,10 +223,9 @@ class User extends Rails\ActiveRecord\Base
// } // }
# iTODO: protected function update_cached_name()
protected function _update_cached_name()
{ {
// Rails::cache()->write("user_name:".$this->id, $this->name); Rails::cache()->write("user_name:".$this->id, $this->name);
} }
# } # }
@ -269,17 +270,19 @@ class User extends Rails\ActiveRecord\Base
{ {
$type = !empty($options['type']) ? $options['type'] : null; $type = !empty($options['type']) ? $options['type'] : null;
// uploaded_tags = Rails.cache.read("uploaded_tags/#{id}/#{type}") $uploaded_tags = Rails::cache()->read("uploaded_tags/". $this->id . "/" . $type);
// return uploaded_tags unless uploaded_tags == nil if ($uploaded_tags) {
return $uploaded_tags;
}
// if ((Rails.env == "test") == "test") { if (Rails::env() == "test") {
// # disable filtering in test mode to simplify tests # disable filtering in test mode to simplify tests
// popular_tags = "" $popular_tags = "";
// } else { } else {
$popular_tags = implode(', ', self::connection()->selectValues("SELECT id FROM tags WHERE tag_type = " . CONFIG()->tag_types['General'] . " ORDER BY post_count DESC LIMIT 8")); $popular_tags = implode(', ', self::connection()->selectValues("SELECT id FROM tags WHERE tag_type = " . CONFIG()->tag_types['General'] . " ORDER BY post_count DESC LIMIT 8"));
if ($popular_tags) if ($popular_tags)
$popular_tags = "AND pt.tag_id NOT IN (${popular_tags})"; $popular_tags = "AND pt.tag_id NOT IN (${popular_tags})";
// } }
if ($type) { if ($type) {
$type = (int)$type; $type = (int)$type;
@ -310,28 +313,28 @@ class User extends Rails\ActiveRecord\Base
$uploaded_tags = self::connection()->select($sql); $uploaded_tags = self::connection()->select($sql);
// Rails.cache.write("uploaded_tags/#{id}/#{type}", uploaded_tags, 'expires_in' => 1.day) Rails::cache()->write("uploaded_tags/" . $this->id . "/" . $type, $uploaded_tags, ['expires_in' => '1 day']);
return $uploaded_tags; return $uploaded_tags;
} }
# iTODO:
public function voted_tags(array $options = array()) public function voted_tags(array $options = array())
{ {
$type = !empty($options['type']) ? $options['type'] : null; $type = !empty($options['type']) ? $options['type'] : null;
// $favorite_tags = Rails.cache.read("favorite_tags/#{id}/#{type}") $favorite_tags = Rails::cache()->read("favorite_tags/". $this->id . "/" . $type);
// if ($favorite_tags != nil) if ($favorite_tags) {
// return $favorite_tags; return $favorite_tags;
}
// if (Rails.env == "test") { if (Rails::env() == "test") {
// # disable filtering in test mode to simplify tests # disable filtering in test mode to simplify tests
// popular_tags = "" $popular_tags = "";
// } else { } else {
$popular_tags = implode(', ', self::connection()->selectValues("SELECT id FROM tags WHERE tag_type = " . CONFIG()->tag_types['General'] . " ORDER BY post_count DESC LIMIT 8")); $popular_tags = implode(', ', self::connection()->selectValues("SELECT id FROM tags WHERE tag_type = " . CONFIG()->tag_types['General'] . " ORDER BY post_count DESC LIMIT 8"));
if ($popular_tags) if ($popular_tags)
$popular_tags = "AND pt.tag_id NOT IN (${popular_tags})"; $popular_tags = "AND pt.tag_id NOT IN (${popular_tags})";
// } }
if ($type) { if ($type) {
$type = (int)$type; $type = (int)$type;
@ -362,7 +365,7 @@ class User extends Rails\ActiveRecord\Base
$favorite_tags = self::connection()->select($sql); $favorite_tags = self::connection()->select($sql);
// Rails.cache.write("favorite_tags/#{id}/#{type}", favorite_tags, 'expires_in' => 1.day) Rails::cache()->write("favorite_tags/" . $this->id . "/" . $type, $favorite_tags, ['expires_in' => '1 day']);
return $favorite_tags; return $favorite_tags;
} }
@ -392,16 +395,14 @@ class User extends Rails\ActiveRecord\Base
return $this->post_count; return $this->post_count;
} }
# iTODO:
public function held_post_count() public function held_post_count()
{ {
return Post::where("user_id = ? AND is_held AND status <> 'deleted'", $this->id)->count(); $version = (int)Rails::cache()->read('$cache_version');
// $version = (int)Rails::cache()->read("%cache_version"); $key = 'held-post-count/v=' . $version . '/u=' . $this->id;
// $key = "held-post-count/v=".$version."/u=".$this->id;
return Rails::cache()->fetch($key, function() {
// return Rails::cache()->fetch($key) { return Post::where(['user_id' => $this->id, 'is_held' => true])->where('status <> ?', 'deleted')->count();
// Post::count(['conditions' => ["user_id = ? AND is_held AND status <> 'deleted'", $this->id]]); });
// }
} }
# } # }
@ -794,7 +795,7 @@ class User extends Rails\ActiveRecord\Base
'before_create' => $before_create, 'before_create' => $before_create,
'before_save' => array('_encrypt_password'), 'before_save' => array('_encrypt_password'),
'before_validation' => array('_commit_secondary_languages'), 'before_validation' => array('_commit_secondary_languages'),
'after_save' => array('_commit_blacklists', '_update_cached_name'), 'after_save' => array('_commit_blacklists', 'update_cached_name'),
'after_create' => array('_set_default_blacklisted_tags', '_increment_count'), 'after_create' => array('_set_default_blacklisted_tags', '_increment_count'),
'after_destroy' => array('_decrement_count') 'after_destroy' => array('_decrement_count')
); );

View File

@ -125,10 +125,10 @@ class WikiPage extends Rails\ActiveRecord\Base
protected function callbacks() protected function callbacks()
{ {
return array_merge_recursive([ return [
'before_save' => ['normalize_title'], 'before_save' => ['normalize_title'],
'before_validation_on_update' => ['ensure_changed'] 'before_validation_on_update' => ['ensure_changed']
], $this->versioningCallbacks()); ];
} }
protected function associations() protected function associations()

View File

@ -19,7 +19,7 @@
<div class="post-footer" style="clear: left;"> <div class="post-footer" style="clear: left;">
<ul class="flat-list pipe-list"> <ul class="flat-list pipe-list">
<?php if (current_user()->has_permission($this->post, 'creator_id')) : ?> <?php if (current_user()->has_permission($this->post, 'creator_id')) : ?>
<li> <?= $this->linkTo($this->t('.edit'), ['action' => "edit", 'id' => $this->post->id]) ?> <li> <?= $this->linkTo($this->t('.edit'), ['action' => "edit", 'id' => $this->post->id, 'page' => (int)$this->params()->page]) ?>
<li> <?= $this->linkTo($this->t('.delete'), ["#destroy", 'id' => $this->post->id], ['confirm' => $this->t('.delete_confirm'), 'method' => 'post']) ?> <li> <?= $this->linkTo($this->t('.delete'), ["#destroy", 'id' => $this->post->id], ['confirm' => $this->t('.delete_confirm'), 'method' => 'post']) ?>
<?php endif ?> <?php endif ?>
<?php if ($this->post->is_parent() && current_user()->is_mod_or_higher()) : ?> <?php if ($this->post->is_parent() && current_user()->is_mod_or_higher()) : ?>

View File

@ -3,6 +3,9 @@
<?= $this->formTag("#update", function(){ ?> <?= $this->formTag("#update", function(){ ?>
<?= $this->hiddenFieldTag("id", $this->params()->id) ?> <?= $this->hiddenFieldTag("id", $this->params()->id) ?>
<?php if ($this->params()->page) : ?>
<?= $this->hiddenFieldTag("page", (int)$this->params()->page, ['id' => '']) ?>
<?php endif ?>
<table> <table>
<tr><td><label for="forum_post_title"><?= $this->t('.post_title') ?></label></td><td><?= $this->textField('forum_post', 'title', ['size' => 60]) ?></td></tr> <tr><td><label for="forum_post_title"><?= $this->t('.post_title') ?></label></td><td><?= $this->textField('forum_post', 'title', ['size' => 60]) ?></td></tr>
<tr><td colspan="2"><?= $this->textArea('forum_post', 'body', ['rows' => 20, 'cols' => 80]) ?></td></tr> <tr><td colspan="2"><?= $this->textArea('forum_post', 'body', ['rows' => 20, 'cols' => 80]) ?></td></tr>

View File

@ -244,6 +244,9 @@ abstract class DefaultConfig
public $available_locales = ['de', 'en', 'es', 'ja', 'ru', 'zh_CN']; public $available_locales = ['de', 'en', 'es', 'ja', 'ru', 'zh_CN'];
# The default name to use for anyone who isn't logged in.
public $default_guest_name = "Anonymous";
public $admin_contact = 'admin@myimouto'; public $admin_contact = 'admin@myimouto';
# Background color when resizing transparent PNG/GIF images. # Background color when resizing transparent PNG/GIF images.

View File

@ -0,0 +1,16 @@
<?php
class CreateAdvertisements extends Rails\ActiveRecord\Migration\Base
{
public function up()
{
$this->createTable('advertisements', function($t) {
$t->column('image_url', 'string', ['null' => false]);
$t->column('referral_url', 'string', ['null' => false]);
$t->column('ad_type', 'string', ['null' => false]);
$t->column('status', 'string', ['null' => false]);
$t->column('hit_count', 'integer', ['null' => false, 'default' => 0]);
$t->column('width', 'integer', ['null' => false]);
$t->column('height', 'integer', ['null' => false]);
});
}
}

View File

@ -0,0 +1,8 @@
<?php
class AddIpAddrToDmails extends Rails\ActiveRecord\Migration\Base
{
public function up()
{
$this->addColumn('dmails', 'ip_addr', 'string', ['length' => 46]);
}
}

View File

@ -0,0 +1,9 @@
<?php
class AddIpAddrToForumPosts extends Rails\ActiveRecord\Migration\Base
{
public function up()
{
$this->addColumn('forum_posts', 'ip_addr', 'string', ['length' => 46]);
$this->addColumn('forum_posts', 'updater_ip_addr', 'string', ['length' => 46]);
}
}

View File

@ -0,0 +1,8 @@
<?php
class AddUpdaterIpAddrToComments extends Rails\ActiveRecord\Migration\Base
{
public function up()
{
$this->addColumn('comments', 'updater_ip_addr', 'string', ['limit' => 46]);
}
}

599
db/schema.sql Normal file
View File

@ -0,0 +1,599 @@
CREATE TABLE `artists` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`alias_id` int(11) DEFAULT NULL,
`group_id` int(11) DEFAULT NULL,
`name` varchar(128) NOT NULL,
`updated_at` datetime NOT NULL,
`updater_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_artists__updater_id` (`updater_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `artists_urls` (
`artist_id` int(11) NOT NULL,
`url` varchar(256) NOT NULL,
`normalized_url` varchar(256) NOT NULL,
KEY `artist_id` (`artist_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `bans` (
`user_id` int(11) NOT NULL,
`reason` text NOT NULL,
`expires_at` datetime NOT NULL,
`banned_by` int(11) NOT NULL,
`old_level` int(11) NOT NULL,
KEY `user_id` (`user_id`),
KEY `fk_bans__banned_by` (`banned_by`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `batch_uploads` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`ip` varchar(15) NOT NULL,
`url` varchar(512) NOT NULL,
`tags` text NOT NULL,
`active` tinyint(1) NOT NULL DEFAULT '0',
`status` varchar(32) NOT NULL DEFAULT 'pending',
`created_at` datetime DEFAULT NULL,
`data_as_json` text NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_batch_uploads__user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`post_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`ip_addr` varchar(16) NOT NULL,
`created_at` datetime DEFAULT '0000-00-00 00:00:00',
`body` text NOT NULL,
`updated_at` datetime NOT NULL,
`is_spam` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `fk_comments__user_id` (`user_id`),
KEY `fk_comments__post_id` (`post_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `dmails` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`from_id` int(11) NOT NULL,
`to_id` int(11) NOT NULL,
`title` text NOT NULL,
`body` text NOT NULL,
`created_at` datetime DEFAULT NULL,
`has_seen` tinyint(1) NOT NULL DEFAULT '0',
`parent_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `from_id` (`from_id`,`to_id`),
KEY `fk_dmails__to_id` (`to_id`),
KEY `fk_dmails__parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `favorites` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`post_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `post_id__user_id` (`post_id`,`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `flagged_post_details` (
`created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`reason` varchar(512) NOT NULL,
`is_resolved` tinyint(1) NOT NULL DEFAULT '0',
KEY `post_id` (`post_id`),
KEY `fk_flag_post_details__user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `forum_posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`title` text NOT NULL,
`body` text NOT NULL,
`creator_id` int(11) NOT NULL,
`parent_id` int(11) DEFAULT NULL,
`last_updated_by` int(11) DEFAULT NULL,
`is_sticky` tinyint(1) NOT NULL DEFAULT '0',
`response_count` int(11) NOT NULL DEFAULT '0',
`is_locked` tinyint(1) NOT NULL DEFAULT '0',
`text_search_index` text,
PRIMARY KEY (`id`),
KEY `fk_forum_posts__creator_id` (`creator_id`),
KEY `fk_forum_posts__last_updated_by` (`last_updated_by`),
KEY `fk_forum_posts__parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `histories` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime NOT NULL,
`user_id` int(11) DEFAULT NULL,
`group_by_id` int(11) NOT NULL,
`group_by_table` varchar(12) NOT NULL,
`aux_as_json` text,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8;
CREATE TABLE `history_changes` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`column_name` char(24) NOT NULL,
`remote_id` bigint(20) NOT NULL,
`table_name` char(24) NOT NULL,
`value` text,
`history_id` bigint(20) unsigned NOT NULL,
`previous_id` bigint(20) DEFAULT NULL,
`value_index` text NOT NULL,
PRIMARY KEY (`id`),
KEY `previous_id` (`previous_id`),
KEY `fk_history_changes__history_id` (`history_id`)
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8;
CREATE TABLE `ip_bans` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`expires_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`ip_addr` varchar(15) NOT NULL,
`reason` text NOT NULL,
`banned_by` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_ip_bans__banned_by` (`banned_by`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `job_tasks` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`task_type` varchar(64) NOT NULL,
`data_as_json` text,
`status` varchar(64) NOT NULL,
`status_message` text,
`repeat_count` int(11) NOT NULL DEFAULT '0',
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
CREATE TABLE `note_versions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`x` int(11) NOT NULL,
`y` int(11) NOT NULL,
`width` int(11) NOT NULL,
`height` int(11) NOT NULL,
`body` text NOT NULL,
`version` int(11) NOT NULL,
`ip_addr` varchar(64) NOT NULL,
`is_active` tinyint(1) NOT NULL DEFAULT '1',
`note_id` int(11) NOT NULL,
`post_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `fk_note_versions__note_id` (`note_id`),
KEY `fk_note_versions__post_id` (`post_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `notes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(11) NOT NULL,
`x` int(11) NOT NULL,
`y` int(11) NOT NULL,
`width` int(11) NOT NULL,
`height` int(11) NOT NULL,
`ip_addr` varchar(64) NOT NULL,
`version` int(11) NOT NULL DEFAULT '1',
`is_active` tinyint(1) NOT NULL DEFAULT '1',
`post_id` int(11) NOT NULL,
`body` text NOT NULL,
PRIMARY KEY (`id`),
KEY `post_id` (`post_id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `pasts` (
`id` int(11) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `pools` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL,
`description` text NOT NULL,
`user_id` int(11) NOT NULL,
`is_active` tinyint(1) NOT NULL DEFAULT '1',
`created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`post_count` int(3) NOT NULL DEFAULT '0',
`is_public` binary(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
UNIQUE KEY `pool_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `pools_posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`post_id` int(11) NOT NULL,
`pool_id` int(11) NOT NULL,
`sequence` varchar(16) NOT NULL,
`next_post_id` int(11) DEFAULT NULL,
`prev_post_id` int(11) DEFAULT NULL,
`active` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
KEY `post_id` (`post_id`),
KEY `fk_pools_posts__next_post_id` (`next_post_id`),
KEY `fk_pools_posts__prev_post_id` (`prev_post_id`),
KEY `fk_pools_posts__pool_id` (`pool_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `post_tag_histories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`post_id` int(11) NOT NULL,
`tags` text NOT NULL,
`user_id` int(11) NOT NULL,
`ip_addr` varchar(39) NOT NULL,
`created_at` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_post_tag_histories__post_id` (`post_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
CREATE TABLE `post_votes` (
`post_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`score` int(1) DEFAULT '0',
`updated_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
UNIQUE KEY `post_id` (`post_id`,`user_id`),
KEY `score` (`score`),
KEY `fk_user_id__users_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`ip_addr` varchar(64) NOT NULL,
`file_size` int(11) NOT NULL,
`md5` varchar(32) NOT NULL,
`last_commented_at` datetime DEFAULT NULL,
`file_ext` varchar(4) NOT NULL,
`last_noted_at` datetime DEFAULT NULL,
`source` varchar(249) DEFAULT NULL,
`cached_tags` text NOT NULL,
`width` int(11) NOT NULL,
`height` int(11) NOT NULL,
`created_at` datetime NOT NULL,
`rating` char(1) NOT NULL DEFAULT 'q',
`preview_width` int(3) NOT NULL,
`preview_height` int(3) NOT NULL,
`actual_preview_width` int(3) NOT NULL,
`actual_preview_height` int(3) NOT NULL,
`score` int(3) NOT NULL DEFAULT '0',
`is_shown_in_index` tinyint(1) NOT NULL DEFAULT '1',
`is_held` tinyint(1) NOT NULL DEFAULT '0',
`has_children` tinyint(1) NOT NULL DEFAULT '0',
`status` enum('deleted','flagged','pending','active') CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT 'active',
`is_rating_locked` tinyint(1) NOT NULL DEFAULT '0',
`is_note_locked` tinyint(1) NOT NULL DEFAULT '0',
`parent_id` int(11) DEFAULT NULL,
`sample_width` int(5) DEFAULT NULL,
`sample_height` int(5) DEFAULT NULL,
`sample_size` int(11) DEFAULT NULL,
`index_timestamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`jpeg_width` int(11) DEFAULT NULL,
`jpeg_height` int(11) DEFAULT NULL,
`jpeg_size` int(11) DEFAULT NULL,
`random` int(11) NOT NULL,
`approver_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `md5` (`md5`),
KEY `fk_posts__parent_id` (`parent_id`),
KEY `posts__approver_id` (`approver_id`),
KEY `fk_posts__user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
CREATE TABLE `posts_tags` (
`post_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
UNIQUE KEY `post_id` (`post_id`,`tag_id`),
KEY `fk_posts_tags__post_id` (`post_id`),
KEY `fk_posts_tags__tag_id` (`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `schema_migrations` (
`version` varchar(255) NOT NULL,
UNIQUE KEY `version` (`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `table_data` (
`name` varchar(32) NOT NULL,
`row_count` int(11) NOT NULL DEFAULT '0',
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `tag_aliases` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
`alias_id` int(11) NOT NULL,
`is_pending` tinyint(1) NOT NULL DEFAULT '0',
`reason` varchar(128) DEFAULT NULL,
`creator_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `alias_unique` (`name`,`alias_id`),
KEY `name` (`name`),
KEY `fk_tag_aliases__alias_id` (`alias_id`),
KEY `fk_tag_aliases__creator_id` (`creator_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `tag_implications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`predicate_id` int(11) NOT NULL,
`consequent_id` int(11) NOT NULL,
`is_pending` tinyint(1) NOT NULL DEFAULT '0',
`reason` varchar(128) DEFAULT NULL,
`creator_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `predicate_id__consequent_id` (`predicate_id`,`consequent_id`),
KEY `fk_tag_implications__consequent_id` (`consequent_id`),
KEY `fk_tag_implications__creator_id` (`creator_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `tag_subscriptions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`tag_query` text CHARACTER SET latin1 NOT NULL,
`cached_post_ids` text CHARACTER SET latin1 NOT NULL,
`name` varchar(32) CHARACTER SET latin1 NOT NULL,
`is_visible_on_profile` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`post_count` int(11) NOT NULL DEFAULT '0',
`cached_related` text,
`cached_related_expires_on` datetime DEFAULT NULL,
`tag_type` smallint(6) NOT NULL,
`is_ambiguous` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8;
CREATE TABLE `user_blacklisted_tags` (
`user_id` int(11) NOT NULL,
`tags` text CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
UNIQUE KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_records` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`reported_by` int(11) NOT NULL,
`created_at` datetime NOT NULL,
`is_positive` tinyint(1) NOT NULL DEFAULT '1',
`body` text NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_user_records__user_id` (`user_id`),
KEY `fk_user_records__reported_by` (`reported_by`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`password_hash` varchar(40) DEFAULT NULL,
`created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`level` int(11) NOT NULL DEFAULT '20',
`email` varchar(249) DEFAULT NULL,
`avatar_post_id` int(11) DEFAULT NULL,
`avatar_width` double DEFAULT NULL,
`avatar_height` double DEFAULT NULL,
`avatar_top` double DEFAULT NULL,
`avatar_bottom` double DEFAULT NULL,
`avatar_left` double DEFAULT NULL,
`avatar_right` double DEFAULT NULL,
`avatar_timestamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`my_tags` text,
`invite_count` int(11) NOT NULL DEFAULT '0',
`invited_by` int(11) DEFAULT NULL,
`show_samples` tinyint(1) NOT NULL DEFAULT '1',
`show_advanced_editing` tinyint(1) NOT NULL DEFAULT '0',
`pool_browse_mode` tinyint(1) NOT NULL DEFAULT '0',
`use_browser` tinyint(1) NOT NULL DEFAULT '0',
`always_resize_images` tinyint(1) NOT NULL DEFAULT '0',
`last_logged_in_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`last_forum_topic_read_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`last_comment_read_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`last_deleted_post_seen_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`language` text,
`secondary_languages` text,
`receive_dmails` tinyint(1) NOT NULL DEFAULT '1',
`has_mail` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
KEY `fk_users__avatar_post_id` (`avatar_post_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
CREATE TABLE `wiki_page_versions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`version` int(11) NOT NULL DEFAULT '1',
`title` varchar(64) NOT NULL,
`body` text NOT NULL,
`user_id` int(11) DEFAULT NULL,
`ip_addr` varchar(15) NOT NULL,
`wiki_page_id` int(11) NOT NULL,
`is_locked` tinyint(1) NOT NULL DEFAULT '0',
`text_search_index` text NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `fk_wiki_page_versions__wiki_page` (`wiki_page_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `wiki_pages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`version` int(11) NOT NULL DEFAULT '1',
`title` varchar(64) NOT NULL,
`body` text NOT NULL,
`user_id` int(11) DEFAULT NULL,
`ip_addr` varchar(15) NOT NULL,
`is_locked` tinyint(1) NOT NULL DEFAULT '0',
`text_search_index` text NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `artists`
ADD CONSTRAINT `fk_artists__updater_id` FOREIGN KEY (`updater_id`) REFERENCES `users` (`id`) ON DELETE SET NULL;
ALTER TABLE `artists_urls`
ADD CONSTRAINT `fk_artists_urls__artist_id` FOREIGN KEY (`artist_id`) REFERENCES `artists` (`id`) ON DELETE CASCADE;
ALTER TABLE `bans`
ADD CONSTRAINT `fk_bans__banned_by` FOREIGN KEY (`banned_by`) REFERENCES `users` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_bans__user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
ALTER TABLE `batch_uploads`
ADD CONSTRAINT `fk_batch_uploads__user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
ALTER TABLE `comments`
ADD CONSTRAINT `fk_comments__post_id` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_comments__user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
ALTER TABLE `dmails`
ADD CONSTRAINT `fk_dmails__from_id` FOREIGN KEY (`from_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_dmails__parent_id` FOREIGN KEY (`parent_id`) REFERENCES `dmails` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_dmails__to_id` FOREIGN KEY (`to_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
ALTER TABLE `flagged_post_details`
ADD CONSTRAINT `fk_flag_post_details__user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`),
ADD CONSTRAINT `fk_flag_post_det__post_id` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE;
ALTER TABLE `forum_posts`
ADD CONSTRAINT `fk_forum_posts__creator_id` FOREIGN KEY (`creator_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_forum_posts__last_updated_by` FOREIGN KEY (`last_updated_by`) REFERENCES `users` (`id`) ON DELETE SET NULL,
ADD CONSTRAINT `fk_forum_posts__parent_id` FOREIGN KEY (`parent_id`) REFERENCES `forum_posts` (`id`) ON DELETE CASCADE;
ALTER TABLE `history_changes`
ADD CONSTRAINT `fk_history_changes__history_id` FOREIGN KEY (`history_id`) REFERENCES `histories` (`id`) ON DELETE CASCADE;
ALTER TABLE `ip_bans`
ADD CONSTRAINT `fk_ip_bans__banned_by` FOREIGN KEY (`banned_by`) REFERENCES `users` (`id`) ON DELETE CASCADE;
ALTER TABLE `note_versions`
ADD CONSTRAINT `fk_note_versions__note_id` FOREIGN KEY (`note_id`) REFERENCES `notes` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_note_versions__post_id` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE;
ALTER TABLE `notes`
ADD CONSTRAINT `fk_notes__post_id` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE;
ALTER TABLE `pools_posts`
ADD CONSTRAINT `fk_pools_posts__next_post_id` FOREIGN KEY (`next_post_id`) REFERENCES `posts` (`id`) ON DELETE SET NULL,
ADD CONSTRAINT `fk_pools_posts__pool_id` FOREIGN KEY (`pool_id`) REFERENCES `pools` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_pools_posts__post_id` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_pools_posts__prev_post_id` FOREIGN KEY (`prev_post_id`) REFERENCES `posts` (`id`) ON DELETE SET NULL;
ALTER TABLE `post_tag_histories`
ADD CONSTRAINT `fk_post_tag_histories__post_id` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE;
ALTER TABLE `post_votes`
ADD CONSTRAINT `fk_post_id__posts_id` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_user_id__users_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
ALTER TABLE `posts`
ADD CONSTRAINT `fk_parent_id__posts_id` FOREIGN KEY (`parent_id`) REFERENCES `posts` (`id`) ON DELETE SET NULL,
ADD CONSTRAINT `fk_posts__user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL,
ADD CONSTRAINT `posts__approver_id` FOREIGN KEY (`approver_id`) REFERENCES `users` (`id`) ON DELETE SET NULL;
ALTER TABLE `posts_tags`
ADD CONSTRAINT `fk_posts_tags__post_id` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_posts_tags__tag_id` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE;
ALTER TABLE `tag_aliases`
ADD CONSTRAINT `fk_tag_aliases__alias_id` FOREIGN KEY (`alias_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_tag_aliases__creator_id` FOREIGN KEY (`creator_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
ALTER TABLE `tag_implications`
ADD CONSTRAINT `fk_consequent_id` FOREIGN KEY (`consequent_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_tag_implications__consequent_id` FOREIGN KEY (`consequent_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_tag_implications__creator_id` FOREIGN KEY (`creator_id`) REFERENCES `users` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_tag_implications__predicate_id` FOREIGN KEY (`predicate_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE;
ALTER TABLE `user_blacklisted_tags`
ADD CONSTRAINT `fk_user_bl_tags__user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
ALTER TABLE `user_records`
ADD CONSTRAINT `fk_user_records__reported_by` FOREIGN KEY (`reported_by`) REFERENCES `users` (`id`) ON DELETE CASCADE,
ADD CONSTRAINT `fk_user_records__user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
ALTER TABLE `wiki_page_versions`
ADD CONSTRAINT `fk_wiki_page_versions__wiki_page` FOREIGN KEY (`wiki_page_id`) REFERENCES `wiki_pages` (`id`) ON DELETE CASCADE;
ALTER TABLE `wiki_pages`
ADD CONSTRAINT `fk_wiki_pages__user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL;
DELIMITER //
CREATE TRIGGER `pools_posts_insert_trg` BEFORE INSERT ON `pools_posts`
FOR EACH ROW
BEGIN
UPDATE pools SET post_count = post_count + 1 WHERE id = NEW.pool_id;
END
//
CREATE TRIGGER `pools_posts_update_trg` BEFORE UPDATE ON `pools_posts`
FOR EACH ROW
BEGIN
IF (OLD.active <> NEW.active) THEN
IF (NEW.active) THEN
UPDATE pools SET post_count = post_count + 1 WHERE id = NEW.pool_id;
ELSE
UPDATE pools SET post_count = post_count - 1 WHERE id = NEW.pool_id;
END IF;
END IF;
END
//
CREATE TRIGGER `pools_posts_delete_trg` BEFORE DELETE ON `pools_posts`
FOR EACH ROW
BEGIN
UPDATE pools SET post_count = post_count - 1 WHERE id = OLD.pool_id;
END
//
CREATE TRIGGER `trg_posts__insert` AFTER INSERT ON `posts`
FOR EACH ROW
BEGIN
UPDATE table_data SET row_count = row_count + 1 WHERE name = 'posts';
END
//
CREATE TRIGGER `trg_posts__delete` AFTER DELETE ON `posts`
FOR EACH ROW
BEGIN
UPDATE table_data SET row_count = row_count - 1 WHERE name = 'posts';
END
//
CREATE TRIGGER `trg_posts_tags__insert` AFTER INSERT ON `posts_tags`
FOR EACH ROW
BEGIN
UPDATE tags SET post_count = post_count + 1 WHERE tags.id = NEW.tag_id;
END
//
CREATE TRIGGER `trg_posts_tags__delete` AFTER DELETE ON `posts_tags`
FOR EACH ROW
BEGIN
UPDATE tags SET post_count = post_count - 1 WHERE tags.id = OLD.tag_id;
END
//
DELIMITER ;

2
db/seeds.php Executable file
View File

@ -0,0 +1,2 @@
<?php

View File

@ -0,0 +1,54 @@
<?php
return array (
0 =>
array (
'id' =>
array (
'type' => 'int(11)',
'default' => NULL,
),
'image_url' =>
array (
'type' => 'varchar(255)',
'default' => NULL,
),
'referral_url' =>
array (
'type' => 'varchar(255)',
'default' => NULL,
),
'ad_type' =>
array (
'type' => 'varchar(255)',
'default' => NULL,
),
'status' =>
array (
'type' => 'varchar(255)',
'default' => NULL,
),
'hit_count' =>
array (
'type' => 'int(11)',
'default' => '0',
),
'width' =>
array (
'type' => 'int(11)',
'default' => NULL,
),
'height' =>
array (
'type' => 'int(11)',
'default' => NULL,
),
),
1 =>
array (
'pri' =>
array (
0 => 'id',
),
),
)
;

View File

@ -42,6 +42,11 @@ return array (
'type' => 'tinyint(1)', 'type' => 'tinyint(1)',
'default' => '0', 'default' => '0',
), ),
'updater_ip_addr' =>
array (
'type' => 'varchar(46)',
'default' => NULL,
),
), ),
1 => 1 =>
array ( array (

View File

@ -42,6 +42,11 @@ return array (
'type' => 'int(11)', 'type' => 'int(11)',
'default' => NULL, 'default' => NULL,
), ),
'ip_addr' =>
array (
'type' => 'varchar(255)',
'default' => NULL,
),
), ),
1 => 1 =>
array ( array (

View File

@ -62,6 +62,16 @@ return array (
'type' => 'text', 'type' => 'text',
'default' => NULL, 'default' => NULL,
), ),
'ip_addr' =>
array (
'type' => 'varchar(255)',
'default' => NULL,
),
'updater_ip_addr' =>
array (
'type' => 'varchar(255)',
'default' => NULL,
),
), ),
1 => 1 =>
array ( array (

View File

@ -0,0 +1,15 @@
<?php
return array (
0 =>
array (
'version' =>
array (
'type' => 'varchar(255)',
'default' => NULL,
),
),
1 =>
array (
),
)
;

View File

@ -140,7 +140,7 @@ trait VersioningTrait
self::connection()->executeSql($sql, static::tableName(), $this->id); self::connection()->executeSql($sql, static::tableName(), $this->id);
} }
public function versioning_callbacks() public function moeVersioningCallbacks()
{ {
return [ return [
'after_save' => [ 'after_save' => [