Merge branch 'master' of github.com:r888888888/danbooru

This commit is contained in:
r888888888
2013-04-30 23:25:35 -07:00
33 changed files with 51230 additions and 50 deletions

View File

@@ -6,7 +6,9 @@ group :test do
gem "mocha", :require => "mocha/setup"
gem "ffaker", :git => "http://github.com/EmmanuelOga/ffaker.git"
gem "simplecov", :require => false
gem "testrbl"
gem "pry"
gem "vcr"
gem "webmock"
end
group :assets do

View File

@@ -53,6 +53,7 @@ GEM
activesupport (3.2.12)
i18n (~> 0.6)
multi_json (~> 1.0)
addressable (2.3.4)
arel (3.0.2)
awesome_print (1.1.0)
aws-s3 (0.6.3)
@@ -73,6 +74,7 @@ GEM
capistrano
chronic (0.9.1)
coderay (1.0.9)
crack (0.3.2)
daemons (1.1.9)
delayed_job (3.0.5)
activesupport (~> 3.0)
@@ -178,7 +180,6 @@ GEM
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
term-ansicolor (1.1.4)
testrbl (0.2.0)
therubyracer (0.11.4)
libv8 (~> 3.11.8.12)
ref
@@ -198,6 +199,10 @@ GEM
kgio (~> 2.6)
rack
raindrops (~> 0.7)
vcr (2.4.0)
webmock (1.11.0)
addressable (>= 2.2.7)
crack (>= 0.3.2)
webrobots (0.1.1)
whenever (0.8.2)
activesupport (>= 2.3.4)
@@ -236,8 +241,9 @@ DEPENDENCIES
simple_form
simplecov
term-ansicolor
testrbl
therubyracer
uglifier (>= 1.0.3)
unicorn
vcr
webmock
whenever

View File

@@ -408,22 +408,75 @@ Danbooru.Note = {
Danbooru.Note.TranslationMode.active = true;
$("#original-file-link").click();
$("#image").one("click", Danbooru.Note.TranslationMode.create_note);
Danbooru.notice('Click on the image to create a note (shortcut is <span class="key">n</span>)');
$("#image").one("click", function() { $(".note-box").show() }); /* override the 'hide all note boxes' click event */
$("#image").one("mousedown", Danbooru.Note.TranslationMode.Drag.start).one("mouseup", Danbooru.Note.TranslationMode.Drag.stop);
Danbooru.notice('Click or drag on the image to create a note (shortcut is <span class="key">n</span>)');
},
stop: function() {
Danbooru.Note.TranslationMode.active = false;
},
create_note: function(e) {
create_note: function(e,dragged,x,y,w,h) {
Danbooru.Note.TranslationMode.active = false;
var offset = $("#image").offset();
Danbooru.Note.new(e.pageX - offset.left, e.pageY - offset.top);
if(dragged) {
if(w > 9 && h > 9) { /* minimum note size: 10px */
Danbooru.Note.new(x-offset.left,y-offset.top,w,h);
}
} else {
Danbooru.Note.new(e.pageX - offset.left, e.pageY - offset.top);
}
Danbooru.Note.TranslationMode.stop();
$(".note-box").show();
e.stopPropagation();
e.preventDefault();
},
Drag: {
dragging: false,
dragStartX: 0,
dragStartY: 0,
dragDistanceY: 0,
dragDistanceY: 0,
start: function (e) {
e.preventDefault(); /* don't drag the image */
$(window).mousemove(Danbooru.Note.TranslationMode.Drag.drag);
Danbooru.Note.TranslationMode.Drag.dragStartX = e.pageX;
Danbooru.Note.TranslationMode.Drag.dragStartY = e.pageY;
},
drag: function (e) {
Danbooru.Note.TranslationMode.Drag.dragDistanceX = e.pageX - Danbooru.Note.TranslationMode.Drag.dragStartX;
Danbooru.Note.TranslationMode.Drag.dragDistanceY = e.pageY - Danbooru.Note.TranslationMode.Drag.dragStartY;
if(Danbooru.Note.TranslationMode.Drag.dragDistanceX > 9 && Danbooru.Note.TranslationMode.Drag.dragDistanceY > 9) {
Danbooru.Note.TranslationMode.Drag.dragging = true; /* must drag at least 10pixels (minimum note size) in both dimensions. */
}
if(Danbooru.Note.TranslationMode.Drag.dragging) {
var offset = $("#image").offset();
$('#note-helper').css({ /* preview of the note you are dragging */
display: 'block',
left: (Danbooru.Note.TranslationMode.Drag.dragStartX - offset.left + 1),
top: (Danbooru.Note.TranslationMode.Drag.dragStartY - offset.top + 1),
width: (Danbooru.Note.TranslationMode.Drag.dragDistanceX - 3),
height: (Danbooru.Note.TranslationMode.Drag.dragDistanceY - 3)
});
}
},
stop: function (e) {
$(window).unbind("mousemove");
if(Danbooru.Note.TranslationMode.Drag.dragging) {
$('#note-helper').css({display:'none'});
Danbooru.Note.TranslationMode.create_note(e, true, Danbooru.Note.TranslationMode.Drag.dragStartX, Danbooru.Note.TranslationMode.Drag.dragStartY, Danbooru.Note.TranslationMode.Drag.dragDistanceX-1, Danbooru.Note.TranslationMode.Drag.dragDistanceY-1);
Danbooru.Note.TranslationMode.Drag.dragging = false; /* border of the note is pixel-perfect on the preview border */
} else { /* no dragging -> create a normal note */
Danbooru.Note.TranslationMode.create_note(e);
}
}
}
},

View File

@@ -92,7 +92,7 @@
Danbooru.Post.initialize_shortcuts = function() {
$(document).bind("keydown.q", function(e) {
$("#tags").trigger("focus");
$("#tags").trigger("focus").selectEnd();
e.preventDefault();
});

View File

@@ -21,6 +21,10 @@ div#c-artists {
textarea {
height: 5em;
}
.hint {
display: block;
}
}
div.recent-posts {

View File

@@ -55,6 +55,14 @@ div#note-container {
border: 1px solid red;
}
}
div#note-helper {
position: absolute;
border: 1px solid red;
opacity: 0.6;
display: none;
background: white;
}
}
div.note-edit-dialog {

View File

@@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base
before_filter :set_current_user
after_filter :reset_current_user
before_filter :set_title
before_filter :normalize_search
before_filter :set_started_at_session
before_filter :api_check
layout "default"
@@ -100,4 +101,8 @@ protected
def set_title
@page_title = Danbooru.config.app_name + "/#{params[:controller]}"
end
def normalize_search
params[:search] ||= {}
end
end

View File

@@ -68,6 +68,8 @@ class PoolsController < ApplicationController
@pool = Pool.find(params[:id])
@version = PoolVersion.find(params[:version_id])
@pool.revert_to!(@version)
respond_with(@pool, :notice => "Pool reverted")
respond_with(@pool) do |format|
format.js
end
end
end

View File

@@ -22,13 +22,8 @@ class PostsController < ApplicationController
@post = Post.find(params[:id])
@post_flag = PostFlag.new(:post_id => @post.id)
@post_appeal = PostAppeal.new(:post_id => @post.id)
@children_post_set = PostSets::Post.new("parent:#{@post.id} -id:#{@post.id}", 1, 200)
@children_post_set.posts.reverse!
@parent_post_set = PostSets::Post.new("id:#{@post.parent_id} status:any")
@siblings_post_set = PostSets::Post.new("parent:#{@post.parent_id} -id:#{@post.parent_id}", 1, 200)
@siblings_post_set.posts.reverse!
@parent_post_set = PostSets::PostRelationship.new(@post.parent_id, :include_deleted => @post.is_deleted?)
@children_post_set = PostSets::PostRelationship.new(@post.id, :include_deleted => @post.is_deleted?)
respond_with(@post)
end

View File

@@ -41,16 +41,17 @@ module PostsHelper
end
end
def has_parent_message(post, parent_post_set, siblings_post_set)
def has_parent_message(post, parent_post_set)
html = ""
html << "This post belongs to a "
html << link_to("parent", post_path(post.parent_id))
html << " (deleted)" if parent_post_set.posts.first.is_deleted?
html << " (deleted)" if parent_post_set.parent.first.is_deleted?
if siblings_post_set.posts.count > 1
sibling_count = parent_post_set.children.count - 1
if sibling_count > 0
html << " and has "
text = siblings_post_set.posts.count > 2 ? "#{siblings_post_set.posts.count - 1} siblings" : "a sibling"
text = sibling_count == 1 ? "a sibling" : "#{sibling_count} siblings"
html << link_to(text, posts_path(:tags => "parent:#{post.parent_id}"))
end
@@ -65,7 +66,7 @@ module PostsHelper
html = ""
html << "This post has "
text = children_post_set.posts.count == 1 ? "a child" : "#{children_post_set.posts.count} children"
text = children_post_set.children.count == 1 ? "a child" : "#{children_post_set.children.count} children"
html << link_to(text, posts_path(:tags => "parent:#{post.id}"))
html << " (#{link_to("learn more", wiki_pages_path(:title => "help:post_relationships"))}) "

View File

@@ -0,0 +1,24 @@
module PostSets
class PostRelationship < PostSets::Post
attr_reader :parent, :children
def initialize(parent_id, options = {})
@parent = ::Post.where("id = ?", parent_id)
@children = ::Post.where("parent_id = ?", parent_id).order("id ASC")
if options[:include_deleted]
super("parent:#{parent_id} status:any")
else
@children = @children.where("is_deleted = ?", false)
super("parent:#{parent_id}")
end
end
def posts
@parent + @children
end
def presenter
::PostSetPresenters::Post.new(self)
end
end
end

View File

@@ -25,9 +25,9 @@ class Pool < ActiveRecord::Base
params = {} if params.blank?
if params[:name_matches].present?
params[:name_matches] = params[:name_matches].tr(" ", "_")
params[:name_matches] = "*#{params[:name_matches]}*" unless params[:name_matches] =~ /\*/
q = q.where("name ilike ? escape E'\\\\'", params[:name_matches].to_escaped_for_sql_like)
name_matches = params[:name_matches].tr(" ", "_")
name_matches = "*#{name_matches}*" unless name_matches =~ /\*/
q = q.where("name ilike ? escape E'\\\\'", name_matches.to_escaped_for_sql_like)
end
if params[:description_matches].present?

View File

@@ -31,6 +31,7 @@ class Post < ActiveRecord::Base
has_many :disapprovals, :class_name => "PostDisapproval", :dependent => :destroy
validates_uniqueness_of :md5
validates_presence_of :parent, :if => lambda {|rec| !rec.parent_id.nil?}
validate :post_is_not_its_own_parent
attr_accessible :source, :rating, :tag_string, :old_tag_string, :last_noted_at, :parent_id, :as => [:member, :builder, :gold, :platinum, :contributor, :janitor, :moderator, :admin, :default]
attr_accessible :is_rating_locked, :is_note_locked, :as => [:builder, :contributor, :janitor, :moderator, :admin]
attr_accessible :is_status_locked, :as => [:admin]
@@ -798,6 +799,13 @@ class Post < ActiveRecord::Base
update_column(:score, 0)
end
def post_is_not_its_own_parent
if parent_id.present? && id == parent_id
errors[:base] << "Post cannot have itself as a parent"
false
end
end
end
module DeletionMethods

View File

@@ -554,7 +554,7 @@ class Tag < ActiveRecord::Base
q = q.reorder("name")
else
q = q.reorder("post_count desc")
q = q.reorder("id desc")
end
q

View File

@@ -351,7 +351,7 @@ class User < ActiveRecord::Base
def create_mod_action
if level_changed?
ModAction.create(:description => "#{name} level changed #{level_string(level_was)} -> #{level_string} by #{CurrentUser.name}")
ModAction.create(:description => %{"#{name}":/users/#{id} level changed #{level_string(level_was)} -> #{level_string}})
end
end

View File

@@ -5,7 +5,7 @@
<th><label for="search_name">Name</label>
<td>
<div class="input">
<%= text_field "search", "name" %>
<%= text_field "search", "name", :value => params[:search][:name] %>
<span class="hint">You can search on any name or URL</span>
</div>
</td>
@@ -15,7 +15,7 @@
<th><label for="search_sort">Sort</label>
<td>
<div class="input">
<%= select "search", "sort", [["Date", "date"], ["Name", "name"]] %>
<%= select "search", "sort", [["Date", "date"], ["Name", "name"]], :selected => params[:search][:sort] %>
</div>
</td>
</tr>

View File

@@ -7,8 +7,8 @@
<%= nav_link_to("Posts", posts_path) %>
<%= nav_link_to("Comments", comments_path(:group_by => "post")) %>
<%= nav_link_to("Notes", notes_path(:group_by => "post")) %>
<%= nav_link_to("Artists", artists_path(:search => {:order => "date"})) %>
<%= nav_link_to("Tags", tags_path(:search => {:order => "date"})) %>
<%= nav_link_to("Artists", artists_path) %>
<%= nav_link_to("Tags", tags_path) %>
<% if CurrentUser.is_moderator? %>
<%= nav_link_to("Aliases", tag_aliases_path) %>
<%= nav_link_to("Implications", tag_implications_path) %>

View File

@@ -33,7 +33,7 @@
<td><%= compact_time pool_version.updated_at %></td>
<% if CurrentUser.is_member? %>
<td>
<%= link_to "Revert", revert_pool_path(pool_version.pool_id, :version => pool_version.id) %>
<%= link_to "Revert", revert_pool_path(pool_version.pool_id, :version_id => pool_version.id), :method => :put, :remote => true %>
</td>
<% end %>
</tr>

View File

@@ -5,7 +5,7 @@
<th><label for="search_name_matches">Name</label></th>
<td>
<div class="input">
<%= text_field "search", "name_matches" %>
<%= text_field "search", "name_matches", :value => params[:search][:name_matches] %>
</div>
</td>
</tr>
@@ -14,7 +14,7 @@
<th><label for="search_description_matches">Description</label></th>
<td>
<div class="input">
<%= text_field "search", "description_matches" %>
<%= text_field "search", "description_matches", :value => params[:search][:description_matches] %>
</div>
</td>
</tr>
@@ -23,7 +23,7 @@
<th><label for="search_creator_name">Creator</th>
<td>
<div class="input">
<%= text_field "search", "creator_name" %>
<%= text_field "search", "creator_name", :value => params[:search][:creator_name] %>
</div>
</td>
</tr>
@@ -32,7 +32,7 @@
<th><label for="search_sort">Order</th>
<td>
<div class="input">
<%= select "search", "sort", [["Last updated", "updated_at"], ["Name", "name"]] %>
<%= select "search", "sort", [["Last updated", "updated_at"], ["Name", "name"]], :selected => params[:search][:sort] %>
</div>
</td>
</tr>

View File

@@ -0,0 +1 @@
location.reload();

View File

@@ -26,7 +26,7 @@
<% if post.is_pending? %>
<div class="ui-corner-all ui-state-highlight notice notice-pending" id="pending-approval-notice">
This post is pending approval (<%= link_to "learn more", wiki_pages_path(:title => "help:post_moderation") %>)
This post is pending approval (<%= link_to "learn more", wiki_pages_path(:title => "about:mod_queue") %>)
<% if CurrentUser.is_janitor? && !post.disapproved_by?(CurrentUser.user) %>
<div class="quick-mod">
@@ -48,8 +48,8 @@
<% if post.parent_id %>
<div class="ui-corner-all ui-state-highlight notice notice-child">
<%= has_parent_message(post, @parent_post_set, @siblings_post_set) %>
<div id="has-parent-relationship-preview"><%= @parent_post_set.presenter.post_previews_html(self) %><%= @siblings_post_set.presenter.post_previews_html(self) %></div>
<%= has_parent_message(post, @parent_post_set) %>
<div id="has-parent-relationship-preview"><%= @parent_post_set.presenter.post_previews_html(self) %></div>
</div>
<% end %>

View File

@@ -45,7 +45,7 @@
<%= render_advertisement("horizontal") %>
<section id="image-container" data-tags="<%= @post.tag_string %>" data-user="<%= @post.uploader_name %>" data-rating="<%= @post.rating %>" data-flags="<%= @post.status_flags %>">
<div id="note-container"></div>
<div id="note-container"><div id="note-helper"></div></div>
<%= @post.presenter.image_html(self) %>
</section>

View File

@@ -2,7 +2,7 @@
<div id="a-index">
<div class="search">
<%= form_tag(general_search_tag_aliases_path, :method => :get) do %>
<%= text_field_tag "query", params[:query] %>
<%= text_field_tag "query", params[:query], :value => params[:search][:name_matches] %>
<%= submit_tag "Search Aliases" %>
<%= submit_tag "Search Implications" %>
<% end %>

View File

@@ -2,7 +2,7 @@
<div id="a-index">
<div class="search">
<%= form_tag(general_search_tag_aliases_path, :method => :get) do %>
<%= text_field_tag "query", params[:query] %>
<%= text_field_tag "query", params[:query], :value => params[:search][:name_matches] %>
<%= submit_tag "Search Implications" %>
<%= submit_tag "Search Aliases" %>
<% end %>

View File

@@ -5,7 +5,7 @@
<th><label for="search_name_matches">Name</label></th>
<td>
<div class="input">
<%= text_field "search", "name_matches" %>
<%= text_field "search", "name_matches", :value => params[:search][:name_matches] %>
<span class="hint">Use * for wildcard</span>
</div>
</td>
@@ -15,7 +15,7 @@
<th><label for="search_category">Category</label></th>
<td>
<div class="input">
<%= select "search", "category", [""] + Danbooru.config.canonical_tag_category_mapping.to_a %>
<%= select "search", "category", [""] + Danbooru.config.canonical_tag_category_mapping.to_a, :selected => params[:search][:category] %>
</div>
</td>
</tr>
@@ -24,7 +24,7 @@
<th><label for="search_sort">Sort</label></th>
<td>
<div class="input">
<%= select "search", "sort", %w(count date name) %>
<%= select "search", "sort", %w(count date name), :selected => params[:search][:sort] %>
</div>
</td>
</tr>
@@ -33,7 +33,7 @@
<th><label for="search_hide_empty">Hide Empty</label></th>
<td>
<div class="input">
<%= select "search", "hide_empty", ["yes", "no"] %>
<%= select "search", "hide_empty", ["yes", "no"], :selected => params[:search][:hide_empty] %>
</div>
</td>
</tr>

23
script/testing/dtest Executable file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env ruby
file, line = ARGV[0], nil
test_name_pattern = nil
if file =~ /:\d+/
file, line = file.split(/:/)
end
if line
text = File.read(file).split(/\r\n|\r|\n/)[line.to_i - 1]
if text =~ /(?:context|should) ["'](.+?)["']/
test_name_pattern = Regexp.escape($1)
end
end
env_options = {
"TEST" => file
}
env_options["TESTOPTS"] = "--name='/#{test_name_pattern}/'" if test_name_pattern
exec(env_options, "bundle exec rake test")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -89,3 +89,9 @@ class MockMemcache
end
MEMCACHE = MockMemcache.new
VCR.configure do |c|
c.cassette_library_dir = "test/fixtures/vcr_cassettes"
c.hook_into :webmock
c.allow_http_connections_when_no_cassette = true
end

View File

@@ -7,7 +7,9 @@ module Downloads
@source = "http://img65.pixiv.net/img/kiyoringo/21755794_p2.png"
@tempfile = Tempfile.new("danbooru-test")
@download = Downloads::File.new(@source, @tempfile.path)
@download.download!
VCR.use_cassette("download-pixiv-manga", :record => :new_episodes) do
@download.download!
end
end
should "instead download the big version" do
@@ -21,7 +23,9 @@ module Downloads
@source = "http://www.pixiv.net/member_illust.php?mode=big&illust_id=4348318"
@tempfile = Tempfile.new("danbooru-test")
@download = Downloads::File.new(@source, @tempfile.path)
@download.download!
VCR.use_cassette("download-pixiv-html", :record => :new_episodes) do
@download.download!
end
end
should "work" do
@@ -34,7 +38,9 @@ module Downloads
@source = "http://img02.pixiv.net/img/wanwandoh/4348318_m.jpg"
@tempfile = Tempfile.new("danbooru-test")
@download = Downloads::File.new(@source, @tempfile.path)
@download.download!
VCR.use_cassette("download-pixiv-small", :record => :new_episodes) do
@download.download!
end
end
should "instead download the original version" do

View File

@@ -6,8 +6,9 @@ module Sources
class PixivTest < ActiveSupport::TestCase
context "The source site for pixiv" do
setup do
@site = Sources::Site.new("http://www.pixiv.net/member_illust.php?mode=big&illust_id=9646484")
@site.get
VCR.use_cassette("source-pixiv-unit-test", :record => :new_episodes) do
@site = Sources::Site.new("http://www.pixiv.net/member_illust.php?mode=big&illust_id=9646484")
end
end
should "get the profile" do