Merge remote-tracking branch 'upstream/master'
This commit is contained in:
7
Gemfile
7
Gemfile
@@ -8,7 +8,11 @@ group :test do
|
||||
gem "simplecov", :require => false
|
||||
end
|
||||
|
||||
gem "rails", "3.1.0.rc1"
|
||||
group :assets do
|
||||
|
||||
end
|
||||
|
||||
gem "rails", "3.1.0.rc5"
|
||||
gem "pg"
|
||||
gem "memcache-client", :require => "memcache"
|
||||
gem "imagesize", :require => "image_size"
|
||||
@@ -20,3 +24,4 @@ gem "mechanize"
|
||||
gem "nokogiri"
|
||||
gem "meta_search", :git => "git://github.com/ernie/meta_search.git"
|
||||
gem "silent-postgres"
|
||||
gem "whenever", :require => false
|
||||
95
Gemfile.lock
95
Gemfile.lock
@@ -16,37 +16,37 @@ GIT
|
||||
GEM
|
||||
remote: http://gemcutter.org/
|
||||
specs:
|
||||
actionmailer (3.1.0.rc1)
|
||||
actionpack (= 3.1.0.rc1)
|
||||
aaronh-chronic (0.3.9)
|
||||
actionmailer (3.1.0.rc5)
|
||||
actionpack (= 3.1.0.rc5)
|
||||
mail (~> 2.3.0)
|
||||
actionpack (3.1.0.rc1)
|
||||
activemodel (= 3.1.0.rc1)
|
||||
activesupport (= 3.1.0.rc1)
|
||||
actionpack (3.1.0.rc5)
|
||||
activemodel (= 3.1.0.rc5)
|
||||
activesupport (= 3.1.0.rc5)
|
||||
builder (~> 3.0.0)
|
||||
erubis (~> 2.7.0)
|
||||
i18n (~> 0.6.0beta1)
|
||||
rack (~> 1.3.0.beta2)
|
||||
rack-cache (~> 1.0.1)
|
||||
i18n (~> 0.6)
|
||||
rack (~> 1.3.1)
|
||||
rack-cache (~> 1.0.2)
|
||||
rack-mount (~> 0.8.1)
|
||||
rack-test (~> 0.6.0)
|
||||
sprockets (~> 2.0.0.beta.5)
|
||||
tzinfo (~> 0.3.27)
|
||||
activemodel (3.1.0.rc1)
|
||||
activesupport (= 3.1.0.rc1)
|
||||
sprockets (~> 2.0.0.beta.12)
|
||||
activemodel (3.1.0.rc5)
|
||||
activesupport (= 3.1.0.rc5)
|
||||
bcrypt-ruby (~> 2.1.4)
|
||||
builder (~> 3.0.0)
|
||||
i18n (~> 0.6.0beta1)
|
||||
activerecord (3.1.0.rc1)
|
||||
activemodel (= 3.1.0.rc1)
|
||||
activesupport (= 3.1.0.rc1)
|
||||
arel (~> 2.1.1)
|
||||
tzinfo (~> 0.3.27)
|
||||
activeresource (3.1.0.rc1)
|
||||
activemodel (= 3.1.0.rc1)
|
||||
activesupport (= 3.1.0.rc1)
|
||||
activesupport (3.1.0.rc1)
|
||||
i18n (~> 0.6)
|
||||
activerecord (3.1.0.rc5)
|
||||
activemodel (= 3.1.0.rc5)
|
||||
activesupport (= 3.1.0.rc5)
|
||||
arel (~> 2.1.4)
|
||||
tzinfo (~> 0.3.29)
|
||||
activeresource (3.1.0.rc5)
|
||||
activemodel (= 3.1.0.rc5)
|
||||
activesupport (= 3.1.0.rc5)
|
||||
activesupport (3.1.0.rc5)
|
||||
multi_json (~> 1.0)
|
||||
arel (2.1.3)
|
||||
arel (2.1.4)
|
||||
bcrypt-ruby (2.1.4)
|
||||
builder (3.0.0)
|
||||
daemons (1.1.4)
|
||||
@@ -54,9 +54,9 @@ GEM
|
||||
activesupport (~> 3.0)
|
||||
daemons
|
||||
erubis (2.7.0)
|
||||
factory_girl (1.3.3)
|
||||
factory_girl (2.0.3)
|
||||
haml (3.1.2)
|
||||
hike (1.1.0)
|
||||
hike (1.2.0)
|
||||
i18n (0.6.0)
|
||||
imagesize (0.1.1)
|
||||
mail (2.3.0)
|
||||
@@ -64,10 +64,10 @@ GEM
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mechanize (2.0.1)
|
||||
net-http-digest_auth (~> 1.1, >= 1.1.1)
|
||||
net-http-digest_auth (>= 1.1.1, ~> 1.1)
|
||||
net-http-persistent (~> 1.8)
|
||||
nokogiri (~> 1.4)
|
||||
webrobots (~> 0.0, >= 0.0.9)
|
||||
webrobots (>= 0.0.9, ~> 0.0)
|
||||
memcache-client (1.8.5)
|
||||
mime-types (1.16)
|
||||
mocha (0.9.12)
|
||||
@@ -76,31 +76,33 @@ GEM
|
||||
net-http-persistent (1.8)
|
||||
nokogiri (1.5.0)
|
||||
pg (0.11.0)
|
||||
polyglot (0.3.1)
|
||||
rack (1.3.1)
|
||||
polyglot (0.3.2)
|
||||
rack (1.3.2)
|
||||
rack-cache (1.0.2)
|
||||
rack (>= 0.4)
|
||||
rack-mount (0.8.1)
|
||||
rack (>= 1.0.0)
|
||||
rack-ssl (1.3.2)
|
||||
rack
|
||||
rack-test (0.6.0)
|
||||
rack-test (0.6.1)
|
||||
rack (>= 1.0)
|
||||
rails (3.1.0.rc1)
|
||||
actionmailer (= 3.1.0.rc1)
|
||||
actionpack (= 3.1.0.rc1)
|
||||
activerecord (= 3.1.0.rc1)
|
||||
activeresource (= 3.1.0.rc1)
|
||||
activesupport (= 3.1.0.rc1)
|
||||
rails (3.1.0.rc5)
|
||||
actionmailer (= 3.1.0.rc5)
|
||||
actionpack (= 3.1.0.rc5)
|
||||
activerecord (= 3.1.0.rc5)
|
||||
activeresource (= 3.1.0.rc5)
|
||||
activesupport (= 3.1.0.rc5)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.1.0.rc1)
|
||||
railties (3.1.0.rc1)
|
||||
actionpack (= 3.1.0.rc1)
|
||||
activesupport (= 3.1.0.rc1)
|
||||
railties (= 3.1.0.rc5)
|
||||
railties (3.1.0.rc5)
|
||||
actionpack (= 3.1.0.rc5)
|
||||
activesupport (= 3.1.0.rc5)
|
||||
rack-ssl (~> 1.3.2)
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (~> 0.14.6)
|
||||
rake (0.9.2)
|
||||
rdoc (3.9.1)
|
||||
shoulda (2.11.3)
|
||||
silent-postgres (0.0.8)
|
||||
simple_form (1.4.2)
|
||||
@@ -109,8 +111,8 @@ GEM
|
||||
simplecov (0.4.2)
|
||||
simplecov-html (~> 0.4.4)
|
||||
simplecov-html (0.4.5)
|
||||
sprockets (2.0.0.beta.10)
|
||||
hike (~> 1.0)
|
||||
sprockets (2.0.0.beta.13)
|
||||
hike (~> 1.2)
|
||||
rack (~> 1.0)
|
||||
tilt (!= 1.3.0, ~> 1.1)
|
||||
super_exception_notifier (3.0.13)
|
||||
@@ -118,11 +120,15 @@ GEM
|
||||
rake
|
||||
thor (0.14.6)
|
||||
tilt (1.3.2)
|
||||
treetop (1.4.9)
|
||||
treetop (1.4.10)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
tzinfo (0.3.29)
|
||||
webrobots (0.0.10)
|
||||
nokogiri (>= 1.4.4)
|
||||
whenever (0.6.8)
|
||||
aaronh-chronic (>= 0.3.9)
|
||||
activesupport (>= 2.3.4)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
@@ -139,9 +145,10 @@ DEPENDENCIES
|
||||
mocha
|
||||
nokogiri
|
||||
pg
|
||||
rails (= 3.1.0.rc1)
|
||||
rails (= 3.1.0.rc5)
|
||||
shoulda
|
||||
silent-postgres
|
||||
simple_form
|
||||
simplecov
|
||||
super_exception_notifier
|
||||
whenever
|
||||
|
||||
118
app/assets/javascripts/blacklists.js
Normal file
118
app/assets/javascripts/blacklists.js
Normal file
@@ -0,0 +1,118 @@
|
||||
(function() {
|
||||
Danbooru.Blacklist = {};
|
||||
|
||||
Danbooru.Blacklist.blacklists = [];
|
||||
|
||||
Danbooru.Blacklist.parse_entries = function() {
|
||||
var entries = (Danbooru.meta("blacklisted-tags") || "").replace(/(rating:[qes])\w+/, "$1").split(/,/);
|
||||
$.each(entries, function(i, tags) {
|
||||
var blacklist = {
|
||||
"tags": tags,
|
||||
"require": [],
|
||||
"exclude": [],
|
||||
"disabled": false,
|
||||
"hits": 0
|
||||
};
|
||||
var matches = tags.match(/\S+/g) || [];
|
||||
$.each(matches, function(i, tag) {
|
||||
if (tag.charAt(0) === '-') {
|
||||
blacklist.exclude.push(tag.slice(1));
|
||||
} else {
|
||||
blacklist.require.push(tag);
|
||||
}
|
||||
})
|
||||
Danbooru.Blacklist.blacklists.push(blacklist);
|
||||
});
|
||||
}
|
||||
|
||||
Danbooru.Blacklist.toggle = function(e) {
|
||||
$(".blacklisted").each(function(i, element) {
|
||||
var $element = $(element);
|
||||
if ($element.hasClass("blacklisted-active")) {
|
||||
$element.removeClass("blacklisted-active");
|
||||
} else {
|
||||
$element.addClass("blacklisted-active");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Danbooru.Blacklist.update_sidebar = function() {
|
||||
$.each(this.blacklists, function(i, blacklist) {
|
||||
if (blacklist.hits === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var item = $("<li/>");
|
||||
var link = $("<a/>");
|
||||
var count = $("<span/>");
|
||||
link.html(blacklist.tags);
|
||||
link.click(Danbooru.Blacklist.toggle);
|
||||
count.html(blacklist.hits);
|
||||
item.append(link);
|
||||
item.append(" ");
|
||||
item.append(count);
|
||||
$("#blacklist-list").append(item);
|
||||
});
|
||||
|
||||
$("#blacklist-box").show();
|
||||
}
|
||||
|
||||
Danbooru.Blacklist.apply = function() {
|
||||
$.each(this.blacklists, function(i, blacklist) {
|
||||
blacklist.hits = 0;
|
||||
});
|
||||
|
||||
var count = 0
|
||||
|
||||
$.each(this.posts(), function(i, post) {
|
||||
$.each(Danbooru.Blacklist.blacklists, function(i, blacklist) {
|
||||
if (Danbooru.Blacklist.post_match(post, blacklist)) {
|
||||
Danbooru.Blacklist.post_hide(post);
|
||||
blacklist.hits += 1;
|
||||
count += 1;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
Danbooru.Blacklist.posts = function() {
|
||||
return $("article.post-preview");
|
||||
}
|
||||
|
||||
Danbooru.Blacklist.post_match = function(post, blacklist) {
|
||||
var $post = $(post);
|
||||
var tags = $post.data("tags").match(/\S+/g) || [];
|
||||
tags.push("rating:" + $post.data("rating"));
|
||||
tags.push("uploader:" + $post.data("uploader"));
|
||||
|
||||
if (blacklist.require.length > 0 || blacklist.exclude.length > 0) {
|
||||
if (blacklist.require.length === 0 || Danbooru.is_subset(tags, blacklist.require)) {
|
||||
if (blacklist.exclude.length === 0 || (!Danbooru.is_subset(tags, blacklist.exclude))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Danbooru.Blacklist.post_hide = function(post) {
|
||||
var $post = $(post);
|
||||
$post.addClass("blacklisted").addClass("blacklisted-active");
|
||||
}
|
||||
|
||||
Danbooru.Blacklist.initialize = function() {
|
||||
Danbooru.Blacklist.parse_entries();
|
||||
if (Danbooru.Blacklist.apply() > 0) {
|
||||
Danbooru.Blacklist.update_sidebar();
|
||||
} else {
|
||||
$("#blacklist-box").hide();
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
$(document).ready(function() {
|
||||
Danbooru.Blacklist.initialize();
|
||||
});
|
||||
@@ -51,15 +51,23 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.get("hide-news-ticker") == "1") {
|
||||
$("#news-ticker").hide();
|
||||
} else {
|
||||
$("#close-news-ticker-link").click(function(e) {
|
||||
$("#news-ticker").hide();
|
||||
Danbooru.Cookie.put("hide-news-ticker", "1", 1);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
if (this.get("hide-upgrade-account") != "1") {
|
||||
if ($("upgrade-account")) {
|
||||
$("upgrade-account").show();
|
||||
}
|
||||
$("#upgrade-account").show();
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
$(document).ready(function() {
|
||||
$(function() {
|
||||
Danbooru.Cookie.initialize();
|
||||
});
|
||||
|
||||
|
||||
@@ -18,4 +18,16 @@
|
||||
Danbooru.ajax_stop = function(target) {
|
||||
$(target).next("img.wait").remove();
|
||||
}
|
||||
|
||||
Danbooru.is_subset = function(array, subarray) {
|
||||
var all = true;
|
||||
|
||||
$.each(subarray, function(i, val) {
|
||||
if ($.inArray(val, array) === -1) {
|
||||
all = false;
|
||||
}
|
||||
});
|
||||
|
||||
return all;
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -334,6 +334,7 @@ div#page {
|
||||
width: 75%;
|
||||
float: left;
|
||||
margin-left: 2em;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,6 +627,10 @@ article.post-preview {
|
||||
float: left;
|
||||
}
|
||||
|
||||
article.post-preview.blacklisted-active {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div#c-posts {
|
||||
div.notice {
|
||||
font-size: 0.8em;
|
||||
@@ -650,6 +655,23 @@ div#c-posts {
|
||||
aside#sidebar > section > ul ul li {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
aside#sidebar > section#blacklist-box ul {
|
||||
margin-left: 1em;
|
||||
|
||||
li {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $link_color;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #AAA;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: $h3_size;
|
||||
@@ -693,6 +715,9 @@ div#c-posts {
|
||||
}
|
||||
}
|
||||
|
||||
div#c-explore-posts {
|
||||
}
|
||||
|
||||
|
||||
/*** Post Histories ***/
|
||||
div.post_histories {
|
||||
@@ -1046,3 +1071,40 @@ div#moderator-dashboard {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*** page footer ***/
|
||||
footer#page-footer {
|
||||
clear: both;
|
||||
margin: 1em;
|
||||
text-align: center;
|
||||
padding-top: 1em;
|
||||
border-top: 2px solid #CCC;
|
||||
}
|
||||
|
||||
/*** news ticker ***/
|
||||
|
||||
div#news-ticker {
|
||||
padding: 5px;
|
||||
background: #EEE;
|
||||
border-bottom: 2px solid #666;
|
||||
overflow: hidden;
|
||||
font-size: 0.8em;
|
||||
|
||||
ul {
|
||||
float: left;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
float: left;
|
||||
margin: 0 2em 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a#close-news-ticker-link {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
module Admin
|
||||
class PostsController
|
||||
def edit
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,7 +0,0 @@
|
||||
class Admin::UsersController < ApplicationController
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
end
|
||||
end
|
||||
11
app/controllers/explore/posts_controller.rb
Normal file
11
app/controllers/explore/posts_controller.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
module Explore
|
||||
class PostsController < ApplicationController
|
||||
respond_to :html, :xml, :json
|
||||
|
||||
def popular
|
||||
@post_set = PostSets::Popular.new(params[:date], params[:scale])
|
||||
@posts = @post_set.posts
|
||||
respond_with(@posts)
|
||||
end
|
||||
end
|
||||
end
|
||||
19
app/controllers/moderator/tags_controller.rb
Normal file
19
app/controllers/moderator/tags_controller.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
module Moderator
|
||||
class TagsController < ApplicationController
|
||||
before_filter :moderator_only
|
||||
rescue_from TagBatchChange::Error, :with => :error
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
def update
|
||||
tag_batch_change = TagBatchChange.new(params[:tag][:predicate], params[:tag][:consequent])
|
||||
tag_batch_change.execute
|
||||
redirect_to edit_moderator_tag_path, :notice => "Posts updated"
|
||||
end
|
||||
|
||||
def error
|
||||
redirect_to edit_moderator_tag_path, :notice => "Error"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -15,6 +15,7 @@ class TagAliasesController < ApplicationController
|
||||
|
||||
def create
|
||||
@tag_alias = TagAlias.create(params[:tag_alias])
|
||||
@tag_alias.delay.process!
|
||||
respond_with(@tag_alias, :location => tag_aliases_path(:search => {:id_eq => @tag_alias.id}))
|
||||
end
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ class TagImplicationsController < ApplicationController
|
||||
|
||||
def create
|
||||
@tag_implication = TagImplication.create(params[:tag_implication])
|
||||
@tag_implication.delay.process!
|
||||
respond_with(@tag_implication, :location => tag_implications_path(:search => {:id_eq => @tag_implication.id}))
|
||||
end
|
||||
|
||||
|
||||
24
app/logical/moderator/tag_batch_change.rb
Normal file
24
app/logical/moderator/tag_batch_change.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
module Moderator
|
||||
class TagBatchChange
|
||||
class Error < Exception ; end
|
||||
|
||||
attr_reader :predicate, :consequent
|
||||
|
||||
def initialize(predicate, consequent)
|
||||
@predicate = predicate
|
||||
@consequent = consequent
|
||||
end
|
||||
|
||||
def execute
|
||||
raise Error.new("Predicate is missing") if predicate.blank?
|
||||
|
||||
normalized_predicate = TagAlias.to_aliased(::Tag.scan_tags(predicate))
|
||||
normalized_consequent = TagAlias.to_aliased(::Tag.scan_tags(consequent))
|
||||
|
||||
::Post.tag_match(predicate).each do |post|
|
||||
tags = (post.tag_array - normalized_predicate + normalized_consequent).join(" ")
|
||||
post.update_attributes(:tag_string => tags)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -4,7 +4,7 @@ class PixivProxy
|
||||
end
|
||||
|
||||
def self.get(url)
|
||||
if url =~ /\/(\d+)(_m)?\.(jpg|jpeg|png|gif)/i
|
||||
if url =~ /\/(\d+)(_m|_p\d+)?\.(jpg|jpeg|png|gif)/i
|
||||
url = "http://www.pixiv.net/member_illust.php?mode=medium&illust_id=#{$1}"
|
||||
get_single(url)
|
||||
elsif url =~ /member_illust\.php/ && url =~ /illust_id=/
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
module PostSets
|
||||
class Artist < Post
|
||||
class Artist < PostSets::Post
|
||||
attr_reader :artist
|
||||
|
||||
def initialize(artist)
|
||||
super(:tags => artist.name)
|
||||
super(artist.name)
|
||||
@artist = artist
|
||||
end
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ module PostSets
|
||||
end
|
||||
|
||||
def artist
|
||||
nil
|
||||
end
|
||||
|
||||
def is_single_tag?
|
||||
|
||||
48
app/logical/post_sets/popular.rb
Normal file
48
app/logical/post_sets/popular.rb
Normal file
@@ -0,0 +1,48 @@
|
||||
module PostSets
|
||||
class Popular < Base
|
||||
attr_reader :date, :scale
|
||||
|
||||
def initialize(date, scale)
|
||||
@date = date.blank? ? Date.today : date.to_date
|
||||
@scale = scale
|
||||
end
|
||||
|
||||
def posts
|
||||
::Post.where("created_at between ? and ?", min_date, max_date + 1).order("score desc").limit(limit)
|
||||
end
|
||||
|
||||
def limit
|
||||
25
|
||||
end
|
||||
|
||||
def min_date
|
||||
case scale
|
||||
when "week"
|
||||
date.beginning_of_week
|
||||
|
||||
when "month"
|
||||
date.beginning_of_month
|
||||
|
||||
else
|
||||
date
|
||||
end
|
||||
end
|
||||
|
||||
def max_date
|
||||
case scale
|
||||
when "week"
|
||||
date.end_of_week
|
||||
|
||||
when "month"
|
||||
date.end_of_month
|
||||
|
||||
else
|
||||
date
|
||||
end
|
||||
end
|
||||
|
||||
def presenter
|
||||
::PostSetPresenters::Popular.new(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -13,6 +13,7 @@ class Comment < ActiveRecord::Base
|
||||
scope :body_matches, lambda {|query| where("body_index @@ plainto_tsquery(?)", query).order("comments.id DESC")}
|
||||
scope :hidden, lambda {|user| where("score < ?", user.comment_threshold)}
|
||||
scope :post_tag_match, lambda {|query| joins(:post).where("posts.tag_index @@ to_tsquery('danbooru', ?)", query)}
|
||||
scope :for_user, lambda {|user_id| where("creator_id = ?", user_id)}
|
||||
|
||||
search_methods :body_matches, :post_tag_match
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
class Favorite < ActiveRecord::Base
|
||||
belongs_to :post
|
||||
scope :for_user, lambda {|user_id| where("user_id = ?", user_id)}
|
||||
scope :for_user, lambda {|user_id| where("user_id = #{user_id}")}
|
||||
end
|
||||
|
||||
@@ -8,6 +8,7 @@ class ForumPost < ActiveRecord::Base
|
||||
validates_presence_of :body, :creator_id
|
||||
validate :validate_topic_is_unlocked
|
||||
scope :body_matches, lambda {|body| where(["text_index @@ plainto_tsquery(?)", body])}
|
||||
scope :for_user, lambda {|user_id| where("creator_id = ?", user_id)}
|
||||
search_methods :body_matches
|
||||
|
||||
def self.new_reply(params)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
class NoteVersion < ActiveRecord::Base
|
||||
before_validation :initialize_updater
|
||||
belongs_to :updater, :class_name => "User"
|
||||
scope :for_user, lambda {|user_id| where("updater_id = ?", user_id)}
|
||||
|
||||
def initialize_updater
|
||||
self.updater_id = CurrentUser.id
|
||||
|
||||
@@ -5,6 +5,7 @@ class PoolVersion < ActiveRecord::Base
|
||||
belongs_to :pool
|
||||
belongs_to :updater, :class_name => "User"
|
||||
before_validation :initialize_updater
|
||||
scope :for_user, lambda {|user_id| where("updater_id = ?", user_id)}
|
||||
|
||||
def initialize_updater
|
||||
self.updater_id = CurrentUser.id
|
||||
|
||||
@@ -41,6 +41,7 @@ class Post < ActiveRecord::Base
|
||||
scope :available_for_moderation, lambda {where(["id NOT IN (SELECT pd.post_id FROM post_disapprovals pd WHERE pd.user_id = ?)", CurrentUser.id])}
|
||||
scope :hidden_from_moderation, lambda {where(["id IN (SELECT pd.post_id FROM post_disapprovals pd WHERE pd.user_id = ?)", CurrentUser.id])}
|
||||
scope :tag_match, lambda {|query| Post.tag_match_helper(query)}
|
||||
scope :exact_tag_match, lambda {|query| Post.exact_tag_match_helper(query)}
|
||||
scope :positive, where("score > 1")
|
||||
scope :negative, where("score < -1")
|
||||
search_methods :tag_match
|
||||
@@ -487,20 +488,29 @@ class Post < ActiveRecord::Base
|
||||
|
||||
def add_tag_subscription_relation(subscriptions, relation)
|
||||
subscriptions.each do |subscription|
|
||||
subscription =~ /^(.+?):(.+)$/
|
||||
user_name = $1 || subscription
|
||||
subscription_name = $2
|
||||
|
||||
user = User.find_by_name(user_name)
|
||||
|
||||
if user
|
||||
if subscription =~ /^(.+?):(.+)$/
|
||||
user_name = $1
|
||||
subscription_name = $2
|
||||
user = User.find_by_name(user_name)
|
||||
return relation if user.nil?
|
||||
post_ids = TagSubscription.find_post_ids(user.id, subscription_name)
|
||||
relation = relation.where(["posts.id IN (?)", post_ids])
|
||||
else
|
||||
user = User.find_by_name(subscription)
|
||||
return relation if user.nil?
|
||||
post_ids = TagSubscription.find_post_ids(user.id)
|
||||
end
|
||||
|
||||
post_ids = [0] if post_ids.empty?
|
||||
relation = relation.where(["posts.id IN (?)", post_ids])
|
||||
end
|
||||
|
||||
relation
|
||||
end
|
||||
|
||||
def exact_tag_match_helper(q)
|
||||
arel = Post.scoped
|
||||
add_tag_string_search_relation({:related => [q].flatten, :include => [], :exclude => []}, arel)
|
||||
end
|
||||
|
||||
def tag_match_helper(q)
|
||||
unless q.is_a?(Hash)
|
||||
@@ -576,6 +586,10 @@ class Post < ActiveRecord::Base
|
||||
relation = relation.where("posts.rating <> 'e'")
|
||||
end
|
||||
|
||||
if q[:order] == "rank"
|
||||
relation = relation.where("p.score > 0 and p.created_at >= ?", 0, 3.days.ago)
|
||||
end
|
||||
|
||||
case q[:order]
|
||||
when "id", "id_asc"
|
||||
relation = relation.order("posts.id")
|
||||
@@ -609,6 +623,9 @@ class Post < ActiveRecord::Base
|
||||
when "filesize_asc"
|
||||
relation = relation.order("posts.file_size")
|
||||
|
||||
when "rank"
|
||||
sql << " ORDER BY log(3, p.score) + (extract(epoch from p.created_at) - extract(epoch from timestamp '2005-05-24')) / 45000 DESC"
|
||||
|
||||
else
|
||||
relation = relation.order("posts.id DESC")
|
||||
end
|
||||
|
||||
@@ -2,6 +2,7 @@ class PostVersion < ActiveRecord::Base
|
||||
belongs_to :post
|
||||
belongs_to :updater, :class_name => "User"
|
||||
before_validation :initialize_updater
|
||||
scope :for_user, lambda {|user_id| where("updater_id = ?", user_id)}
|
||||
|
||||
def self.create_from_post(post)
|
||||
if post.created_at == post.updated_at
|
||||
|
||||
@@ -106,21 +106,7 @@ class Tag < ActiveRecord::Base
|
||||
m.extend(ClassMethods)
|
||||
end
|
||||
end
|
||||
|
||||
module UpdateMethods
|
||||
def mass_edit(start_tags, result_tags, updater_id, updater_ip_addr)
|
||||
updater = User.find(updater_id)
|
||||
Post.tag_match(start_tags).each do |p|
|
||||
start = TagAlias.to_aliased(scan_tags(start_tags))
|
||||
result = TagAlias.to_aliased(scan_tags(result_tags))
|
||||
tags = (p.tag_array - start + result).join(" ")
|
||||
CurrentUser.scoped(updater, updater_ip_addr) do
|
||||
p.update_attributes(:tag_string => tags)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module ParseMethods
|
||||
def normalize(query)
|
||||
query.to_s.downcase.strip
|
||||
@@ -323,12 +309,13 @@ class Tag < ActiveRecord::Base
|
||||
|
||||
module RelationMethods
|
||||
def update_related
|
||||
return unless should_update_related?
|
||||
counts = RelatedTagCalculator.calculate_from_sample(Danbooru.config.post_sample_size, name)
|
||||
self.related_tags = RelatedTagCalculator.convert_hash_to_string(counts)
|
||||
update_attributes(:related_tags => RelatedTagCalculator.convert_hash_to_string(counts), :related_tags_updated_at => Time.now)
|
||||
end
|
||||
|
||||
def update_related_if_outdated
|
||||
updated_related if should_update_related?
|
||||
delay.update_related if should_update_related?
|
||||
end
|
||||
|
||||
def related_cache_expiry
|
||||
@@ -345,7 +332,8 @@ class Tag < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def related_tag_array
|
||||
related_tags.split(/ /).in_groups_of(2)
|
||||
update_related_if_outdated
|
||||
related_tags.to_s.split(/ /).in_groups_of(2)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -367,7 +355,7 @@ class Tag < ActiveRecord::Base
|
||||
include CategoryMethods
|
||||
extend StatisticsMethods
|
||||
include NameMethods
|
||||
extend UpdateMethods
|
||||
extend ParseMethods
|
||||
include RelationMethods
|
||||
extend SuggestionMethods
|
||||
end
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
class TagAlias < ActiveRecord::Base
|
||||
attr_accessor :creator_ip_addr
|
||||
after_save :update_posts
|
||||
after_save :clear_cache
|
||||
after_save :clear_remote_cache
|
||||
before_save :clear_all_cache
|
||||
after_save :update_cache
|
||||
after_destroy :clear_cache
|
||||
after_destroy :clear_remote_cache
|
||||
after_destroy :clear_all_cache
|
||||
before_validation :initialize_creator, :on => :create
|
||||
validates_presence_of :creator_id
|
||||
validates_uniqueness_of :antecedent_name
|
||||
@@ -25,8 +21,17 @@ class TagAlias < ActiveRecord::Base
|
||||
alias_hash.values.flatten.uniq
|
||||
end
|
||||
|
||||
def process!
|
||||
update_column(:status, "processing")
|
||||
update_posts
|
||||
update_column(:status, "active")
|
||||
rescue Exception => e
|
||||
update_column(:status, "error: #{e}")
|
||||
end
|
||||
|
||||
def initialize_creator
|
||||
self.creator_id = CurrentUser.user.id
|
||||
self.creator_ip_addr = CurrentUser.ip_addr
|
||||
end
|
||||
|
||||
def antecedent_tag
|
||||
@@ -44,6 +49,11 @@ class TagAlias < ActiveRecord::Base
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def clear_all_cache
|
||||
clear_cache
|
||||
clear_remote_cache
|
||||
end
|
||||
|
||||
def clear_cache
|
||||
Cache.delete("ta:#{Cache.sanitize(antecedent_name)}")
|
||||
@@ -60,13 +70,15 @@ class TagAlias < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def update_posts
|
||||
Post.tag_match(antecedent_name).find_each do |post|
|
||||
Post.exact_tag_match(antecedent_name).find_each do |post|
|
||||
escaped_antecedent_name = Regexp.escape(antecedent_name)
|
||||
fixed_tags = post.tag_string.sub(/(?:\A| )#{escaped_antecedent_name}(?:\Z| )/, " #{consequent_name} ").strip
|
||||
|
||||
post.update_attributes(
|
||||
:tag_string => fixed_tags
|
||||
)
|
||||
CurrentUser.scoped(creator, creator_ip_addr) do
|
||||
post.update_attributes(
|
||||
:tag_string => fixed_tags
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,43 +1,19 @@
|
||||
class TagImplication < ActiveRecord::Base
|
||||
before_save :clear_cache
|
||||
before_save :update_descendant_names
|
||||
after_save :update_descendant_names_for_parent
|
||||
after_save :update_cache
|
||||
after_save :update_posts
|
||||
after_destroy :clear_cache
|
||||
after_destroy :clear_remote_cache
|
||||
belongs_to :creator, :class_name => "User"
|
||||
before_validation :initialize_creator, :on => :create
|
||||
validates_presence_of :creator_id
|
||||
validates_uniqueness_of :antecedent_name, :scope => :consequent_name
|
||||
validate :absence_of_circular_relation
|
||||
|
||||
module CacheMethods
|
||||
def clear_cache
|
||||
Cache.delete("ti:#{Cache.sanitize(antecedent_name)}")
|
||||
@descendants = nil
|
||||
end
|
||||
|
||||
def clear_remote_cache
|
||||
Danbooru.config.other_server_hosts.each do |server|
|
||||
Net::HTTP.delete(URI.parse("http://#{server}/tag_implications/#{id}/cache"))
|
||||
end
|
||||
end
|
||||
|
||||
def update_cache
|
||||
descendant_names_array
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
module DescendantMethods
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
module ClassMethods
|
||||
# assumes names are normalized
|
||||
def with_descendants(names)
|
||||
names + Cache.get_multi(names.flatten, "ti") do |name|
|
||||
([name] + where(["antecedent_name = ?", name]).all.map {|x| x.descendant_names_array}).flatten
|
||||
end.values.flatten.uniq
|
||||
(names + where("antecedent_name in (?)", names).map(&:descendant_names_array)).flatten.uniq
|
||||
end
|
||||
end
|
||||
|
||||
@@ -55,9 +31,7 @@ class TagImplication < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def descendant_names_array
|
||||
Cache.get("ti:#{Cache.sanitize(antecedent_name)}") do
|
||||
descendant_names.split(/ /)
|
||||
end
|
||||
descendant_names.split(/ /)
|
||||
end
|
||||
|
||||
def update_descendant_names
|
||||
@@ -93,12 +67,20 @@ class TagImplication < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
include CacheMethods
|
||||
include DescendantMethods
|
||||
include ParentMethods
|
||||
|
||||
def initialize_creator
|
||||
self.creator_id = CurrentUser.user.id
|
||||
self.creator_ip_addr = CurrentUser.ip_addr
|
||||
end
|
||||
|
||||
def process!
|
||||
update_column(:status, "processing")
|
||||
update_posts
|
||||
update_column(:status, "active")
|
||||
rescue Exception => e
|
||||
update_column(:status, "error: #{e}")
|
||||
end
|
||||
|
||||
def absence_of_circular_relation
|
||||
@@ -110,12 +92,14 @@ class TagImplication < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def update_posts
|
||||
Post.tag_match(antecedent_name).find_each do |post|
|
||||
Post.exact_tag_match(antecedent_name).find_each do |post|
|
||||
escaped_antecedent_name = Regexp.escape(antecedent_name)
|
||||
fixed_tags = post.tag_string.sub(/(?:\A| )#{escaped_antecedent_name}(?:\Z| )/, " #{antecedent_name} #{descendant_names} ").strip
|
||||
post.update_attributes(
|
||||
:tag_string => fixed_tags
|
||||
)
|
||||
CurrentUser.scoped(creator, creator_ip_addr) do
|
||||
post.update_attributes(
|
||||
:tag_string => fixed_tags
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ class UserFeedback < ActiveRecord::Base
|
||||
scope :positive, where("category = ?", "positive")
|
||||
scope :neutral, where("category = ?", "neutral")
|
||||
scope :negative, where("category = ?", "negative")
|
||||
scope :for_user, lambda {|user_id| where("user_id = ?", user_id)}
|
||||
|
||||
def initialize_creator
|
||||
self.creator_id = CurrentUser.id
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
class WikiPageVersion < ActiveRecord::Base
|
||||
belongs_to :wiki_page
|
||||
belongs_to :updater, :class_name => "User"
|
||||
scope :for_user, lambda {|user_id| where("updater_id = ?", user_id)}
|
||||
|
||||
def updater_name
|
||||
User.id_to_name(updater_id)
|
||||
|
||||
21
app/presenters/post_set_presenters/base.rb
Normal file
21
app/presenters/post_set_presenters/base.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
module PostSetPresenters
|
||||
class Base
|
||||
def posts
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def post_previews_html(template)
|
||||
html = ""
|
||||
|
||||
if posts.empty?
|
||||
return template.render(:partial => "post_sets/blank")
|
||||
end
|
||||
|
||||
posts.each do |post|
|
||||
html << PostPresenter.preview(post)
|
||||
end
|
||||
|
||||
html.html_safe
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,7 @@
|
||||
module PostSetPresenters
|
||||
class Favorite
|
||||
class Favorite < Base
|
||||
attr_accessor :favorite_set, :tag_set_presenter
|
||||
delegate :favorites, :posts, :to => :favorite_set
|
||||
delegate :favorites, :to => :favorite_set
|
||||
|
||||
def initialize(favorite_set)
|
||||
@favorite_set = favorite_set
|
||||
@@ -15,19 +15,9 @@ module PostSetPresenters
|
||||
def tag_list_html(template)
|
||||
tag_set_presenter.tag_list_html(template)
|
||||
end
|
||||
|
||||
def post_previews_html(template)
|
||||
html = ""
|
||||
|
||||
if favorites.empty?
|
||||
return template.render(:partial => "post_sets/blank")
|
||||
end
|
||||
|
||||
favorites.each do |favorite|
|
||||
html << PostPresenter.preview(favorite.post)
|
||||
end
|
||||
|
||||
html.html_safe
|
||||
|
||||
def posts
|
||||
favorites.map(&:post)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
module PostSetPresenters
|
||||
class Pool
|
||||
attr_reader :tag_set_presenter, :pool_set
|
||||
class Pool < Base
|
||||
attr_reader :tag_set_presenter, :post_set
|
||||
delegate :posts, :to => :post_set
|
||||
|
||||
def initialize(pool_set)
|
||||
@pool_set = pool_set
|
||||
def initialize(post_set)
|
||||
@post_set = post_set
|
||||
@tag_set_presenter = TagSetPresenter.new(
|
||||
RelatedTagCalculator.calculate_from_sample_to_array(
|
||||
pool_set.tag_string
|
||||
post_set.tag_string
|
||||
).map {|x| x[0]}
|
||||
)
|
||||
end
|
||||
@@ -14,19 +15,5 @@ module PostSetPresenters
|
||||
def tag_list_html(template)
|
||||
tag_set_presenter.tag_list_html(template)
|
||||
end
|
||||
|
||||
def post_previews_html(template)
|
||||
html = ""
|
||||
|
||||
if pool_set.posts.empty?
|
||||
return template.render(:partial => "post_sets/blank")
|
||||
end
|
||||
|
||||
pool_set.posts.each do |post|
|
||||
html << PostPresenter.preview(post)
|
||||
end
|
||||
|
||||
html.html_safe
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
34
app/presenters/post_set_presenters/popular.rb
Normal file
34
app/presenters/post_set_presenters/popular.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
module PostSetPresenters
|
||||
class Popular < Base
|
||||
attr_accessor :post_set, :tag_set_presenter
|
||||
delegate :posts, :date, :to => :post_set
|
||||
|
||||
def initialize(post_set)
|
||||
@post_set = post_set
|
||||
end
|
||||
|
||||
def prev_day
|
||||
date - 1
|
||||
end
|
||||
|
||||
def next_day
|
||||
date + 1
|
||||
end
|
||||
|
||||
def prev_week
|
||||
date - 7
|
||||
end
|
||||
|
||||
def next_week
|
||||
date + 7
|
||||
end
|
||||
|
||||
def prev_month
|
||||
1.month.ago(date)
|
||||
end
|
||||
|
||||
def next_month
|
||||
1.month.since(date)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,36 +1,26 @@
|
||||
module PostSetPresenters
|
||||
class Post
|
||||
class Post < Base
|
||||
attr_accessor :post_set, :tag_set_presenter
|
||||
delegate :posts, :to => :post_set
|
||||
|
||||
def initialize(post_set)
|
||||
@post_set = post_set
|
||||
@tag_set_presenter = TagSetPresenter.new(
|
||||
RelatedTagCalculator.calculate_from_sample_to_array(
|
||||
post_set.tag_string
|
||||
).map {|x| x[0]}
|
||||
)
|
||||
@tag_set_presenter = TagSetPresenter.new(related_tags)
|
||||
end
|
||||
|
||||
def posts
|
||||
post_set.posts
|
||||
|
||||
def related_tags
|
||||
if post_set.is_single_tag?
|
||||
tag = Tag.find_by_name(post_set.tag_string)
|
||||
if tag
|
||||
return tag.related_tag_array.map(&:first)
|
||||
end
|
||||
end
|
||||
|
||||
RelatedTagCalculator.calculate_from_sample_to_array(post_set.tag_string).map(&:first)
|
||||
end
|
||||
|
||||
def tag_list_html(template)
|
||||
tag_set_presenter.tag_list_html(template)
|
||||
end
|
||||
|
||||
def post_previews_html(template)
|
||||
html = ""
|
||||
|
||||
if posts.empty?
|
||||
return template.render(:partial => "post_sets/blank")
|
||||
end
|
||||
|
||||
posts.each do |post|
|
||||
html << PostPresenter.preview(post)
|
||||
end
|
||||
|
||||
html.html_safe
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
107
app/presenters/user_presenter.rb
Normal file
107
app/presenters/user_presenter.rb
Normal file
@@ -0,0 +1,107 @@
|
||||
class UserPresenter
|
||||
attr_reader :user
|
||||
|
||||
def initialize(user)
|
||||
@user = user
|
||||
end
|
||||
|
||||
def level
|
||||
user.level_string
|
||||
end
|
||||
|
||||
def ban_reason
|
||||
if user.is_banned?
|
||||
"#{user.ban.reason}; expires #{user.ban.expires_at}"
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def tag_subscriptions(template)
|
||||
user.subscriptions.map do |subscription|
|
||||
template.link_to(subscription.name, template.tag_subscription_path(subscription))
|
||||
end.join("; ")
|
||||
end
|
||||
|
||||
def upload_limit
|
||||
deleted_count = Post.for_user(user.id).deleted.count
|
||||
pending_count = Post.for_user(user.id).pending.count
|
||||
approved_count = Post.where("is_flagged = false and is_pending = false and user_id = ?", user.id).count
|
||||
|
||||
if user.base_upload_limit
|
||||
limit = user.base_upload_limit - pending_count
|
||||
string = "base:#{user.base_upload_limit} - pending:#{pending_count}"
|
||||
else
|
||||
limit = 10 + (approved_count / 10) - (deleted_count / 4) - pending_count
|
||||
string = "base:10 + approved:(#{approved_count} / 10) - deleted:(#{deleted_count}) / 4 - pending:#{pending_count}"
|
||||
end
|
||||
|
||||
if limit > 20
|
||||
limit = 20
|
||||
string += " = capped:20"
|
||||
elsif limit < 0
|
||||
limit = 0
|
||||
string += " = capped:0"
|
||||
else
|
||||
string += " = #{limit}"
|
||||
end
|
||||
|
||||
return string
|
||||
end
|
||||
|
||||
def uploads(template)
|
||||
template.link_to(Post.for_user(user.id).count, template.posts_path(:tags => "uploader:#{user.name}"))
|
||||
end
|
||||
|
||||
def deleted_uploads(template)
|
||||
template.link_to(Post.for_user(user.id).deleted.count, template.posts_path(:tags => "status:deleted uploader:#{user.name}"))
|
||||
end
|
||||
|
||||
def favorites(template)
|
||||
template.link_to(Favorite.for_user(user.id).count, template.favorites_path(:user_id => user.id))
|
||||
end
|
||||
|
||||
def comments(template)
|
||||
template.link_to(Comment.for_user(user.id).count, template.comments_path(:search => {:creator_id_eq => user.id}))
|
||||
end
|
||||
|
||||
def post_versions(template)
|
||||
template.link_to(PostVersion.for_user(user.id).count, template.post_versions_path(:search => {:updater_id_eq => user.id}))
|
||||
end
|
||||
|
||||
def note_versions(template)
|
||||
template.link_to(NoteVersion.for_user(user.id).count, template.note_versions_path(:search => {:updater_id_eq => user.id}))
|
||||
end
|
||||
|
||||
def wiki_page_versions(template)
|
||||
template.link_to(WikiPageVersion.for_user(user.id).count, template.wiki_page_versions_path(:search => {:updater_id_eq => user.id}))
|
||||
end
|
||||
|
||||
def forum_posts(template)
|
||||
template.link_to(ForumPost.for_user(user.id).count, template.forum_posts_path(:search => {:creator_id_eq => user.id}))
|
||||
end
|
||||
|
||||
def pool_versions(template)
|
||||
template.link_to(PoolVersion.for_user(user.id).count, template.pool_versions_path(:search => {:updater_id_eq => user.id}))
|
||||
end
|
||||
|
||||
def inviter(template)
|
||||
if user.inviter_id
|
||||
template.link_to(user.inviter.name, template.user_path(user.inviter_id))
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def approvals(template)
|
||||
template.link_to(Post.where("approver_id = ?", user.id).count, template.posts_path(:tags => "approver:#{user.name}"))
|
||||
end
|
||||
|
||||
def feedbacks(template)
|
||||
positive = UserFeedback.for_user(user.id).positive.count
|
||||
neutral = UserFeedback.for_user(user.id).neutral.count
|
||||
negative = UserFeedback.for_user(user.id).negative.count
|
||||
|
||||
template.link_to("positive:#{positive} neutral:#{neutral} negative:#{negative}", user_feedbacks_path(:search => {:user_id_rq => user.id}))
|
||||
end
|
||||
end
|
||||
@@ -1,10 +0,0 @@
|
||||
<% form_tag({:action => "mass_edit"}, :onsubmit => "return confirm('Are you sure you wish to perform this tag edit?')") do %>
|
||||
<%= text_field_tag "start", params[:source], :size => 60 %>
|
||||
<%= text_field_tag "result", params[:name], :size => 60 %>
|
||||
<%= button_to_function "Preview", "$('preview').innerHTML = 'Loading...'; new Ajax.Updater('preview', '#{url_for(:controller=>"tag",:action=>"edit_preview")}', {method: 'get', parameters: 'tags=' + $F('start')})" %><%= submit_tag "Save" %>
|
||||
<% end %>
|
||||
|
||||
<%= render :partial => "footer" %>
|
||||
|
||||
<div id="preview">
|
||||
</div>
|
||||
19
app/views/explore/posts/_date_explore.html.erb
Normal file
19
app/views/explore/posts/_date_explore.html.erb
Normal file
@@ -0,0 +1,19 @@
|
||||
<aside id="sidebar">
|
||||
<ul>
|
||||
<li>
|
||||
<%= link_to "«".html_safe, popular_explore_posts_path(:date => post_set.presenter.prev_day, :scale => "day") %>
|
||||
<%= link_to "»".html_safe, popular_explore_posts_path(:date => post_set.presenter.next_day, :scale => "day") %>
|
||||
<%= link_to "Day", popular_explore_posts_path(:date => post_set.presenter.date, :scale => "day") %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to "«".html_safe, popular_explore_posts_path(:date => post_set.presenter.prev_week, :scale => "week") %>
|
||||
<%= link_to "»".html_safe, popular_explore_posts_path(:date => post_set.presenter.next_week, :scale => "week") %>
|
||||
<%= link_to "Week", popular_explore_posts_path(:date => post_set.presenter.date, :scale => "week") %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to "«".html_safe, popular_explore_posts_path(:date => post_set.presenter.prev_month, :scale => "month") %>
|
||||
<%= link_to "»".html_safe, popular_explore_posts_path(:date => post_set.presenter.next_month, :scale => "month") %>
|
||||
<%= link_to "Month", popular_explore_posts_path(:date => post_set.presenter.date, :scale => "month") %>
|
||||
</li>
|
||||
</ul>
|
||||
</aside>
|
||||
14
app/views/explore/posts/popular.html.erb
Normal file
14
app/views/explore/posts/popular.html.erb
Normal file
@@ -0,0 +1,14 @@
|
||||
<div id="c-explore-posts">
|
||||
<div id="a-index">
|
||||
<h1>Explore: <%= @post_set.min_date %> – <%= @post_set.max_date %></h1>
|
||||
|
||||
<%= render "date_explore", :post_set => @post_set %>
|
||||
|
||||
<section id="content">
|
||||
<%= @post_set.presenter.post_previews_html(self) %>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "posts/partials/common/secondary_links" %>
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<header id="top">
|
||||
<%= render "news/listing" %>
|
||||
|
||||
<h1><%= link_to Danbooru.config.app_name, "/" %></h1>
|
||||
<nav>
|
||||
<menu class="main">
|
||||
@@ -64,5 +66,7 @@
|
||||
<footer>
|
||||
<%= yield :page_footer_content %>
|
||||
</footer>
|
||||
|
||||
<%= render "static/footer" %>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
21
app/views/moderator/tags/edit.html.erb
Normal file
21
app/views/moderator/tags/edit.html.erb
Normal file
@@ -0,0 +1,21 @@
|
||||
<div id="c-moderator-tags">
|
||||
<div id="a-edit">
|
||||
<h1>Edit Tags</h1>
|
||||
|
||||
<%= form_tag(moderator_tag_path, :method => :put) do %>
|
||||
<div class="input">
|
||||
<label>Predicate</label>
|
||||
<%= text_field :tag, :predicate %>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<label>Consequent</label>
|
||||
<%= text_field :tag, :consequent %>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<%= submit_tag %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
6
app/views/news/_listing.html.erb
Normal file
6
app/views/news/_listing.html.erb
Normal file
@@ -0,0 +1,6 @@
|
||||
<div id="news-ticker">
|
||||
<ul>
|
||||
</ul>
|
||||
|
||||
<a href="#" id="close-news-ticker-link">close</a>
|
||||
</div>
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<%= render :partial => "posts/partials/index/mode_menu" %>
|
||||
|
||||
<%= render :partial => "posts/partials/index/blacklist" %>
|
||||
|
||||
<section id="tag-box">
|
||||
<h1>Tags</h1>
|
||||
<%= @post_set.presenter.tag_list_html(self) %>
|
||||
</section>
|
||||
|
||||
<%= render :partial => "posts/partials/index/blacklist" %>
|
||||
</aside>
|
||||
|
||||
<section id="content">
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<menu>
|
||||
<li><%= link_to "Listing", posts_path %></li>
|
||||
<li><%= link_to "Upload", new_upload_path %></li>
|
||||
<li><%= link_to "Popular", explore_post_popular_path %></li>
|
||||
<li><%= link_to "Hot", explore_post_hot_path %></li>
|
||||
<li><%= link_to "Popular", popular_explore_posts_path %></li>
|
||||
<li><%= link_to "Hot", posts_path(:tags => "order:rank") %></li>
|
||||
<% unless CurrentUser.is_anonymous? %>
|
||||
<li><%= link_to "Favorites", favorites_path %></li>
|
||||
<li><%= link_to "Subscriptions", posts_tag_subscription_path(CurrentUser.id) %></li>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<section id="blacklist-box">
|
||||
<h1>Blacklisted</h1>
|
||||
<%= link_to "Hidden", "#" %>
|
||||
<ul>
|
||||
<ul id="blacklist-list">
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
<li><%= link_to "Flag", new_post_flag_path(:post_id => post.id), :id => "flag" %></li>
|
||||
<li><%= link_to "Appeal", new_post_appeal_path(:post_id => post.id), :id => "appeal" %></li>
|
||||
<% if CurrentUser.is_janitor? %>
|
||||
<li><%= link_to "Approve", moderation_post_approval_path(:post_id => post.id), :remote => true, :method => :post, :id => "approve" %></li>
|
||||
<li><%= link_to "Disapprove", moderation_post_approval_path(:post_id => post.id), :remote => true, :method => :destroy, :id => "disapprove" %></li>
|
||||
<li><%= link_to "Approve", moderator_post_approval_path(:post_id => post.id), :remote => true, :method => :post, :id => "approve" %></li>
|
||||
<li><%= link_to "Disapprove", moderator_post_disapproval_path(:post_id => post.id), :remote => true, :method => :post, :id => "disapprove" %></li>
|
||||
<% end %>
|
||||
<% if CurrentUser.is_moderator? %>
|
||||
<li><%= link_to "Undelete", moderation_post_deletion_path(:post_id => post.id), :remote => true, :method => :destroy, :id => "undelete" %></li>
|
||||
<li><%= link_to "Delete", moderation_post_deletion_path(:post_id => post.id), :remote => true, :method => :post, :id => "delete" %></li>
|
||||
<li><%= link_to "Undelete", undelete_moderator_post_post_path(:post_id => post.id), :remote => true, :method => :post, :id => "undelete" %></li>
|
||||
<li><%= link_to "Delete", delete_moderator_post_post_path(:post_id => post.id), :remote => true, :method => :post, :id => "delete" %></li>
|
||||
<% end %>
|
||||
<li><%= link_to "Pool", "#", :id => "pool" %></li>
|
||||
</ul>
|
||||
3
app/views/static/_footer.html.erb
Normal file
3
app/views/static/_footer.html.erb
Normal file
@@ -0,0 +1,3 @@
|
||||
<footer id="page-footer">
|
||||
Running Danbooru v<%= Danbooru.config.version %>. <%= mail_to Danbooru.config.contact_email, "Contact", :encode => :hex %>.
|
||||
</footer>
|
||||
@@ -1,40 +0,0 @@
|
||||
<div id="jquery-test">
|
||||
<div class="note" id="lots-of-text-1">
|
||||
Lorem ipsum
|
||||
</div>
|
||||
|
||||
<div class="note" id="lots-of-text-2" style="left: 400px;">
|
||||
Lorem ipsum
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var body = $("#lots-of-text-2");
|
||||
body.css({height: "auto", minWidth: 140});
|
||||
|
||||
var w = body[0].offsetWidth;
|
||||
var h = body[0].offsetHeight;
|
||||
var lo = null;
|
||||
var hi = null;
|
||||
var x = null;
|
||||
var last = null;
|
||||
|
||||
if (body[0].scrollWidth <= body[0].clientWidth) {
|
||||
lo = 20, hi = w
|
||||
|
||||
do {
|
||||
x = (lo+hi)/2
|
||||
body.css({minWidth: x});
|
||||
|
||||
if (body[0].offsetHeight > h) {
|
||||
lo = x;
|
||||
} else {
|
||||
hi = x;
|
||||
}
|
||||
} while ((hi - lo) > 4);
|
||||
|
||||
if (body[0].offsetHeight > h) {
|
||||
body.css({minWidth: hi});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
<div style="width: 40em; margin: 5em auto; overflow: scroll;">
|
||||
<div class="section">
|
||||
<h4>Terms of Service</h4>
|
||||
<h1>Terms of Service</h1>
|
||||
<p>By accessing the "<%= Danbooru.config.app_name %>" website ("Site") you agree to the following terms of service. If you do not agree to these terms, then please do not access the Site.</p>
|
||||
|
||||
<ul>
|
||||
@@ -13,13 +13,13 @@
|
||||
</ul>
|
||||
|
||||
<div class="section">
|
||||
<h6>Post/Comment Limiting</h6>
|
||||
<h1>Post/Comment Limiting</h1>
|
||||
<p>You cannot upload a post or comment during the first week of signing up.</p>
|
||||
<p>After the initial period, you can post up to one comment an hour and a variable number of posts based on how many of your previous uploads were approved or deleted.</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h6>Prohibited Content</h6>
|
||||
<h1>Prohibited Content</h1>
|
||||
<p>In addition, you may not use the Site to upload any of the following:</p>
|
||||
<ul>
|
||||
<li>Non-anime: Photographs of American porn actresses, for example, are prohibited. Photographs of cosplayers, figures, or prominent figures in the industry are acceptable.</li>
|
||||
@@ -34,7 +34,7 @@
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h4>Copyright Infringement</h4>
|
||||
<h1>Copyright Infringement</h1>
|
||||
|
||||
<p>If you believe a post infringes upon your copyright, please send an email to the <%= mail_to Danbooru.config.contact_email, "webmaster", :encode => "hex" %> with the following pieces of information:</p>
|
||||
<ul>
|
||||
@@ -45,14 +45,14 @@
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h4>Privacy Policy</h4>
|
||||
<h1>Privacy Policy</h1>
|
||||
|
||||
<p>The Site will not disclose the IP address, email address, password, or DMails of any user except to the staff.</p>
|
||||
<p>The Site is allowed to make public everything else, including but not limited to: uploaded posts, favorited posts, comments, forum posts, wiki edits, and note edits.</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4>Agreement</h4>
|
||||
<h1>Agreement</h1>
|
||||
<p>By clicking on the "I Agree" link, you have read all the terms and have agreed to them.</p>
|
||||
<p><%= link_to("I Agree", params[:url] || "/", :onclick => "Cookie.put('tos', '1')") %> | <%= link_to("Cancel", "/") %></p>
|
||||
</div>
|
||||
|
||||
@@ -2,9 +2,10 @@ require File.expand_path('../boot', __FILE__)
|
||||
|
||||
require 'rails/all'
|
||||
|
||||
# If you have a Gemfile, require the gems listed there, including any gems
|
||||
# you've limited to :test, :development, or :production.
|
||||
Bundler.require(:default, Rails.env) if defined?(Bundler)
|
||||
# If you have a Gemfile, require the default gems, the ones in the
|
||||
# current environment and also include :assets gems if in development
|
||||
# or test environments.
|
||||
Bundler.require *Rails.groups(:assets) if defined?(Bundler)
|
||||
|
||||
module Danbooru
|
||||
class Application < Rails::Application
|
||||
|
||||
@@ -12,7 +12,7 @@ module Danbooru
|
||||
|
||||
# Contact email address of the admin.
|
||||
def contact_email
|
||||
"webmaster#{server_host}"
|
||||
"webmaster@#{server_host}"
|
||||
end
|
||||
|
||||
# Stripped of any special characters.
|
||||
|
||||
@@ -21,4 +21,7 @@ Danbooru::Application.configure do
|
||||
|
||||
# Only use best-standards-support built into browsers
|
||||
config.action_dispatch.best_standards_support = :builtin
|
||||
|
||||
# Do not compress assets
|
||||
config.assets.compress = false
|
||||
end
|
||||
|
||||
@@ -11,9 +11,8 @@ Danbooru::Application.configure do
|
||||
# Disable Rails's static asset server (Apache or nginx will already do this)
|
||||
config.serve_static_assets = false
|
||||
|
||||
# Compress both stylesheets and JavaScripts
|
||||
config.assets.js_compressor = :uglifier
|
||||
config.assets.css_compressor = :scss
|
||||
# Compress JavaScripts and CSS
|
||||
config.assets.compress = true
|
||||
|
||||
# Specifies the header that your server uses for sending files
|
||||
# (comment out if your front-end server doesn't support this)
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
ActiveSupport::Inflector.inflections do |inflect|
|
||||
# inflect.plural /^(ox)$/i, '\1en'
|
||||
# inflect.singular /^(ox)en/i, '\1'
|
||||
# inflect.irregular 'person', 'people'
|
||||
end
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Add new inflection rules using the following format
|
||||
# (all these examples are active by default):
|
||||
# ActiveSupport::Inflector.inflections do |inflect|
|
||||
# inflect.plural /^(ox)$/i, '\1en'
|
||||
# inflect.singular /^(ox)en/i, '\1'
|
||||
# inflect.irregular 'person', 'people'
|
||||
# inflect.uncountable %w( fish sheep )
|
||||
# end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Be sure to restart your server when you modify this file.
|
||||
#
|
||||
# This file contains the settings for ActionController::ParametersWrapper
|
||||
# which will be enabled by default in the upcoming version of Ruby on Rails.
|
||||
# This file contains settings for ActionController::ParamsWrapper which
|
||||
# is enabled by default.
|
||||
|
||||
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
|
||||
ActionController::Base.wrap_parameters format: [:json]
|
||||
|
||||
@@ -10,7 +10,7 @@ Danbooru::Application.routes.draw do
|
||||
end
|
||||
end
|
||||
resources :invitations, :only => [:new, :create, :index]
|
||||
resource :tag
|
||||
resource :tag, :only => [:edit, :update]
|
||||
namespace :post do
|
||||
resource :dashboard, :only => [:show]
|
||||
resource :approval, :only => [:create]
|
||||
@@ -125,9 +125,11 @@ Danbooru::Application.routes.draw do
|
||||
resources :wiki_page_versions, :only => [:index, :show]
|
||||
|
||||
namespace :explore do
|
||||
namespace :post do
|
||||
resource :popular, :only => [:show]
|
||||
resource :hot, :only => [:show]
|
||||
resources :posts, :only => [:popular, :hot] do
|
||||
collection do
|
||||
get :popular
|
||||
get :hot
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
5
config/schedule.rb
Normal file
5
config/schedule.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
set :output, "/var/log/whenever.log"
|
||||
|
||||
every 1.hour do
|
||||
TagSubscription.process_all
|
||||
end
|
||||
@@ -2250,7 +2250,9 @@ CREATE TABLE tag_aliases (
|
||||
antecedent_name character varying(255) NOT NULL,
|
||||
consequent_name character varying(255) NOT NULL,
|
||||
creator_id integer NOT NULL,
|
||||
creator_ip_addr inet NOT NULL,
|
||||
forum_topic_id integer,
|
||||
status character varying(255) DEFAULT 'pending'::character varying NOT NULL,
|
||||
created_at timestamp without time zone,
|
||||
updated_at timestamp without time zone
|
||||
);
|
||||
@@ -2285,7 +2287,9 @@ CREATE TABLE tag_implications (
|
||||
consequent_name character varying(255) NOT NULL,
|
||||
descendant_names text NOT NULL,
|
||||
creator_id integer NOT NULL,
|
||||
creator_ip_addr inet NOT NULL,
|
||||
forum_topic_id integer,
|
||||
status character varying(255) DEFAULT 'pending'::character varying NOT NULL,
|
||||
created_at timestamp without time zone,
|
||||
updated_at timestamp without time zone
|
||||
);
|
||||
|
||||
@@ -4,7 +4,9 @@ class CreateTagAliases < ActiveRecord::Migration
|
||||
t.column :antecedent_name, :string, :null => false
|
||||
t.column :consequent_name, :string, :null => false
|
||||
t.column :creator_id, :integer, :null => false
|
||||
t.column :creator_ip_addr, :inet, :null => false
|
||||
t.column :forum_topic_id, :integer
|
||||
t.column :status, :text, :null => false, :default => "pending"
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
|
||||
@@ -5,7 +5,9 @@ class CreateTagImplications < ActiveRecord::Migration
|
||||
t.column :consequent_name, :string, :null => false
|
||||
t.column :descendant_names, :text, :null => false
|
||||
t.column :creator_id, :integer, :null => false
|
||||
t.column :creator_ip_addr, :inet, :null => false
|
||||
t.column :forum_topic_id, :integer
|
||||
t.column :status, :text, :null => false, :default => "pending"
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
|
||||
@@ -1,550 +0,0 @@
|
||||
.blacklisted {
|
||||
display: none !important; }
|
||||
|
||||
body, div, h1, h2, h3, h4, h5, h6, p, ul, li, dd, dt, header, aside {
|
||||
font-family: Verdana, Geneva, sans-serif;
|
||||
line-height: 1.25em; }
|
||||
|
||||
body {
|
||||
font-size: 87.5%; }
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-family: Tahoma;
|
||||
line-height: 1em; }
|
||||
|
||||
body {
|
||||
padding: 1em 2em;
|
||||
margin: 0; }
|
||||
|
||||
article, section {
|
||||
display: block; }
|
||||
|
||||
a:link {
|
||||
color: #006ffa;
|
||||
text-decoration: none; }
|
||||
|
||||
a:visited {
|
||||
color: #006ffa;
|
||||
text-decoration: none; }
|
||||
|
||||
a:hover {
|
||||
color: #9093ff;
|
||||
text-decoration: none; }
|
||||
|
||||
a:active {
|
||||
color: #006ffa;
|
||||
text-decoration: none; }
|
||||
|
||||
abbr[title=required] {
|
||||
display: none; }
|
||||
|
||||
blockquote {
|
||||
margin: 0 0 1em 0;
|
||||
padding: 1em;
|
||||
border: 1px solid #666;
|
||||
background: #EEE; }
|
||||
|
||||
code {
|
||||
font-family: monospace;
|
||||
font-size: 1.2em; }
|
||||
|
||||
dd {
|
||||
margin-bottom: 1em; }
|
||||
|
||||
dt {
|
||||
font-weight: bold; }
|
||||
|
||||
h1 {
|
||||
font-size: 2.1818em; }
|
||||
|
||||
h2 {
|
||||
font-size: 1.9091em; }
|
||||
|
||||
h3 {
|
||||
font-size: 1.6364em; }
|
||||
|
||||
h4 {
|
||||
font-size: 1.4545em; }
|
||||
|
||||
h5 {
|
||||
font-size: 1.2727em; }
|
||||
|
||||
h6 {
|
||||
font-size: 1.090em; }
|
||||
|
||||
header {
|
||||
margin: 0 0 1em 0;
|
||||
padding: 0;
|
||||
display: block; }
|
||||
|
||||
img {
|
||||
border: none;
|
||||
vertical-align: middle; }
|
||||
|
||||
input[type=text], input[type=password], input[type=url], textarea, button {
|
||||
/* border: 1px solid #AAA;*/
|
||||
font-size: 1em;
|
||||
/* -moz-border-radius: 4px;*/
|
||||
/* -webkit-border-radius: 4px;*/ }
|
||||
|
||||
input[type=submit] {
|
||||
padding: 1px 4px;
|
||||
/* border: 1px solid #AAA;*/
|
||||
/* background-color: #EEE;*/
|
||||
/* -moz-border-radius: 4px;*/
|
||||
/* -webkit-border-radius: 4px;*/
|
||||
font-size: 1em;
|
||||
cursor: pointer; }
|
||||
|
||||
input:focus, textarea:focus {
|
||||
/* background-color: #FFD;*/ }
|
||||
|
||||
input[type=submit]:hover {
|
||||
/* background-color: #F6F6F6;*/ }
|
||||
|
||||
menu {
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
menu ul {
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
menu li {
|
||||
margin: 0 1em 0 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
display: inline; }
|
||||
|
||||
p {
|
||||
margin-bottom: 1em; }
|
||||
|
||||
section {
|
||||
display: block; }
|
||||
|
||||
span.error {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
color: red; }
|
||||
|
||||
span.link {
|
||||
color: #006ffa;
|
||||
cursor: pointer; }
|
||||
|
||||
span.wait {
|
||||
color: #CCC; }
|
||||
|
||||
span.ui-icon {
|
||||
float: left;
|
||||
margin-right: 0.25em; }
|
||||
|
||||
table tfoot {
|
||||
margin-top: 2em; }
|
||||
|
||||
table.striped tbody tr:hover {
|
||||
background-color: #FFE; }
|
||||
table.striped tr.even {
|
||||
background-color: #EEE; }
|
||||
|
||||
div.error-messages {
|
||||
margin: 1em 0;
|
||||
padding: 1em; }
|
||||
div.error-messages span.ui-icon {
|
||||
float: left;
|
||||
margin-right: 0.5em; }
|
||||
div.error-messages h1 {
|
||||
font-size: 1em;
|
||||
color: #A00; }
|
||||
|
||||
div#search {
|
||||
margin-bottom: 1em; }
|
||||
|
||||
div#notice {
|
||||
margin: 1em 0;
|
||||
padding: 1em; }
|
||||
div#notice span.ui-icon {
|
||||
float: left;
|
||||
margin-right: 0.5em; }
|
||||
|
||||
div#page aside#sidebar {
|
||||
width: 20%;
|
||||
float: left; }
|
||||
div#page aside#sidebar h1 {
|
||||
font-size: 1.2em; }
|
||||
div#page aside#sidebar ul {
|
||||
list-style-type: none; }
|
||||
div#page aside#sidebar > section {
|
||||
margin-bottom: 1em; }
|
||||
div#page section#content {
|
||||
width: 75%;
|
||||
float: left;
|
||||
margin-left: 2em; }
|
||||
|
||||
div.clearfix {
|
||||
clear: both; }
|
||||
|
||||
/*** Paginator ***/
|
||||
div.paginator {
|
||||
display: block;
|
||||
padding: 2em 0 1em 0;
|
||||
font-size: 1em;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
clear: both; }
|
||||
div.paginator a {
|
||||
margin: 0 3px;
|
||||
padding: 2px 6px;
|
||||
font-weight: normal;
|
||||
border: 1px solid #EAEAEA; }
|
||||
div.paginator a.arrow {
|
||||
border: none; }
|
||||
div.paginator a.arrow:hover {
|
||||
background: white;
|
||||
color: #9093FF; }
|
||||
div.paginator a.current {
|
||||
border: 1px solid #AAA; }
|
||||
div.paginator a:hover {
|
||||
background: #3c3cdc;
|
||||
color: white; }
|
||||
div.paginator span {
|
||||
margin: 0 3px;
|
||||
padding: 2px 6px; }
|
||||
|
||||
/*** Header ***/
|
||||
body > header > h1 {
|
||||
font-size: 3em;
|
||||
font-family: Tahoma, Helvetica, sans-serif; }
|
||||
|
||||
/*** Dialog Boxes ***/
|
||||
div.ui-dialog ul {
|
||||
margin-left: 1em;
|
||||
margin-bottom: 1em; }
|
||||
|
||||
/*** Simple Form ***/
|
||||
form.simple_form {
|
||||
margin: 0 0 1em 0; }
|
||||
form.simple_form div.input.boolean label {
|
||||
display: inline; }
|
||||
form.simple_form div.input {
|
||||
margin-bottom: 1em; }
|
||||
form.simple_form div.input input[type=text], form.simple_form div.input input[type=file] {
|
||||
width: 20em; }
|
||||
form.simple_form div.input textarea {
|
||||
width: 30em; }
|
||||
form.simple_form div.input label {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
font-weight: bold; }
|
||||
form.simple_form div.input span.hint {
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
display: block; }
|
||||
form.simple_form div.input fieldset {
|
||||
border: none;
|
||||
display: inline;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
form.simple_form div.input fieldset label {
|
||||
font-weight: normal;
|
||||
width: auto;
|
||||
margin-right: 2em; }
|
||||
|
||||
/*** DText Preview ***/
|
||||
div.dtext {
|
||||
width: 30em; }
|
||||
div.dtext ul {
|
||||
margin-left: 1em; }
|
||||
|
||||
/*** Pools Posts ***/
|
||||
div#c-pools-posts div#a-new form {
|
||||
margin-bottom: 1em; }
|
||||
div#c-pools-posts div#a-new li {
|
||||
margin-left: 1em;
|
||||
cursor: pointer; }
|
||||
|
||||
/*** Pools ***/
|
||||
div#c-pools div#a-edit p {
|
||||
width: 30em; }
|
||||
div#c-pools div#a-edit ul.ui-sortable {
|
||||
list-style-type: none; }
|
||||
div#c-pools div#a-edit ul.ui-sortable span {
|
||||
margin: 0;
|
||||
float: right;
|
||||
cursor: pointer; }
|
||||
div#c-pools div#a-edit ul.ui-sortable li {
|
||||
padding: 0.5em; }
|
||||
div#c-pools div#a-edit ul.ui-sortable li.ui-state-default {
|
||||
margin-bottom: 20px;
|
||||
width: 180px;
|
||||
background: none; }
|
||||
div#c-pools div#a-edit ul.ui-sortable li.ui-state-placeholder {
|
||||
margin-bottom: 20px;
|
||||
width: 180px;
|
||||
height: 150px;
|
||||
background: none; }
|
||||
|
||||
/*** Comments ***/
|
||||
div.comments-for-post div.list-of-comments article {
|
||||
margin-bottom: 2em; }
|
||||
div.comments-for-post div.list-of-comments article div.author {
|
||||
width: 20%;
|
||||
float: left; }
|
||||
div.comments-for-post div.list-of-comments article div.content {
|
||||
margin-left: 2em;
|
||||
width: 30em;
|
||||
float: left; }
|
||||
div.comments-for-post div.comment-preview {
|
||||
margin-bottom: 2em; }
|
||||
|
||||
div.dtext-preview {
|
||||
border: 2px dashed #AAA;
|
||||
padding: 1em;
|
||||
margin: 1em;
|
||||
width: 30em; }
|
||||
|
||||
div#c-comments div#a-index div.header span.info {
|
||||
margin-right: 1.5em; }
|
||||
div#c-comments div#a-index div.header strong, div#c-comments div#a-index div.header time {
|
||||
margin-right: 0.3em; }
|
||||
div#c-comments div#a-index div.header time {
|
||||
font-weight: bold; }
|
||||
div#c-comments div#a-index div.header div.list-of-tags a {
|
||||
margin-right: 0.5em; }
|
||||
div#c-comments div#a-index div.header div.notices {
|
||||
margin: 1em 0; }
|
||||
div#c-comments div#a-index div.preview {
|
||||
float: left;
|
||||
width: 180px; }
|
||||
div#c-comments div#a-index div.post {
|
||||
margin-bottom: 4em; }
|
||||
div#c-comments div#a-index div.post div.comments-for-post {
|
||||
float: left;
|
||||
width: 55em; }
|
||||
|
||||
/*** Favorites ***/
|
||||
div#c-favorites section#content > h1 {
|
||||
display: none; }
|
||||
|
||||
/*** Posts ***/
|
||||
article.post-preview {
|
||||
margin-right: 4em;
|
||||
margin-bottom: 4em;
|
||||
float: left; }
|
||||
|
||||
div#c-posts div.notice {
|
||||
font-size: 80%;
|
||||
padding: 1em;
|
||||
margin-bottom: 1em; }
|
||||
div#c-posts div.notice ul {
|
||||
margin-left: 1em; }
|
||||
div#c-posts aside#sidebar > section#pool-sidebar span.ui-icon {
|
||||
color: #666; }
|
||||
div#c-posts aside#sidebar > section > ul li {
|
||||
list-style-type: none; }
|
||||
div#c-posts aside#sidebar > section > ul ul li {
|
||||
margin-left: 1em; }
|
||||
div#c-posts section#tag-and-wiki-box {
|
||||
padding: 0; }
|
||||
div#c-posts section#tag-and-wiki-box menu li {
|
||||
display: inline-block; }
|
||||
div#c-posts section#tag-and-wiki-box menu li.active a {
|
||||
color: #000; }
|
||||
div#c-posts section#tag-and-wiki-box div#tag-box h2 {
|
||||
display: none; }
|
||||
div#c-posts section#tag-and-wiki-box div#tag-box li {
|
||||
list-style-type: none; }
|
||||
div#c-posts section#tag-and-wiki-box div#wiki-box h2 {
|
||||
display: none; }
|
||||
div#c-posts section#content > h1 {
|
||||
display: none; }
|
||||
div#c-posts section#content section > h2 {
|
||||
display: none; }
|
||||
div#c-posts section#content menu#post-sections {
|
||||
margin-bottom: 1em; }
|
||||
div#c-posts section#content menu#post-sections li {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold; }
|
||||
div#c-posts section#content menu#post-sections li.active a {
|
||||
color: black; }
|
||||
div#c-posts section#content section#edit fieldset label {
|
||||
display: inline; }
|
||||
|
||||
/*** Post Histories ***/
|
||||
div.post_histories div.index div.post {
|
||||
margin-bottom: 2em; }
|
||||
div.post_histories div.index div.post div.preview {
|
||||
width: 20%;
|
||||
float: left; }
|
||||
div.post_histories div.index div.post div.history {
|
||||
width: 70%;
|
||||
float: left; }
|
||||
div.post_histories div.index div.post div.history table {
|
||||
width: 100%; }
|
||||
div.post_histories div.index div.post div.history ins {
|
||||
color: green;
|
||||
text-decoration: none; }
|
||||
div.post_histories div.index div.post div.history del {
|
||||
color: red;
|
||||
text-decoration: line-through; }
|
||||
|
||||
/*** Post Unapprovals ***/
|
||||
div#unapprove-dialog p {
|
||||
margin-bottom: 1em; }
|
||||
|
||||
/*** Sessions ***/
|
||||
div#sessions div#new section {
|
||||
width: 30em;
|
||||
float: left; }
|
||||
div#sessions div#new aside {
|
||||
width: 20em;
|
||||
float: left; }
|
||||
div#sessions div#new aside li {
|
||||
display: list-item;
|
||||
margin-bottom: 0.5em;
|
||||
list-style-type: square;
|
||||
margin-left: 1em; }
|
||||
div#sessions div#new h2 {
|
||||
margin-bottom: 5px; }
|
||||
|
||||
/*** Artists ***/
|
||||
div#c-artists span.new-artist {
|
||||
font-weight: bold;
|
||||
color: #A00; }
|
||||
div#c-artists div#a-show {
|
||||
max-width: 60em; }
|
||||
div#c-artists div#a-show p.legend {
|
||||
margin-bottom: 2em;
|
||||
font-size: 0.8em;
|
||||
font-style: italic; }
|
||||
div#c-artists div#a-edit textarea, div#c-artists div#a-new textarea {
|
||||
height: 5em; }
|
||||
|
||||
/*** Users ***/
|
||||
div.users div.new {
|
||||
max-width: 60em; }
|
||||
div.users div.new p {
|
||||
margin-bottom: 1em; }
|
||||
div.users div.new li {
|
||||
margin-left: 1em; }
|
||||
div.users div.new div#account-comparison li {
|
||||
font-size: 0.9em;
|
||||
line-height: 1.5em; }
|
||||
div.users div.new div#account-comparison section {
|
||||
width: 18em;
|
||||
float: left;
|
||||
padding: 1em; }
|
||||
div.users div.new footer.nav-links {
|
||||
font-size: 1.4545em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
display: block; }
|
||||
div.users div.new div#p2 ul {
|
||||
margin-bottom: 2em; }
|
||||
|
||||
/*** Uploads ***/
|
||||
div#c-uploads div#a-new div#upload-guide-notice {
|
||||
margin-bottom: 2em; }
|
||||
div#c-uploads div#a-new fieldset.ratings label {
|
||||
display: inline; }
|
||||
|
||||
/*** Forum ***/
|
||||
div.list-of-forum-posts article {
|
||||
margin-bottom: 3em; }
|
||||
div.list-of-forum-posts article div.author {
|
||||
width: 20%;
|
||||
float: left; }
|
||||
div.list-of-forum-posts article div.content {
|
||||
margin-left: 2em;
|
||||
width: 30em;
|
||||
float: left; }
|
||||
div.list-of-forum-posts article div.content menu {
|
||||
margin-top: 0.5em; }
|
||||
|
||||
div#c-forum-topics div.single-forum-post {
|
||||
width: 60em; }
|
||||
div#c-forum-topics div#a-show h1#forum-topic-title {
|
||||
font-size: 2.1818em; }
|
||||
div#c-forum-topics span.info {
|
||||
color: #AAA; }
|
||||
div#c-forum-topics div#form-content {
|
||||
float: left;
|
||||
width: 450px;
|
||||
padding-right: 1em; }
|
||||
div#c-forum-topics div#form-aside {
|
||||
float: left;
|
||||
width: 400px; }
|
||||
div#c-forum-topics div#form-aside div#preview > p {
|
||||
margin-top: 0.5em;
|
||||
padding-top: 0.5em;
|
||||
border-top: 1px solid #AAA; }
|
||||
|
||||
/*** Wiki Pages ***/
|
||||
div#c-wiki-pages span.version {
|
||||
color: #AAA; }
|
||||
div#c-wiki-pages div#form-content {
|
||||
float: left;
|
||||
width: 30em;
|
||||
padding-right: 1em; }
|
||||
div#c-wiki-pages div#form-aside {
|
||||
float: left;
|
||||
width: 20em; }
|
||||
div#c-wiki-pages div#form-aside div#preview > p {
|
||||
margin-top: 0.5em;
|
||||
padding-top: 0.5em;
|
||||
border-top: 1px solid #AAA; }
|
||||
|
||||
/*** Post Moderation ***/
|
||||
div#c-post-moderation article {
|
||||
margin-bottom: 4em; }
|
||||
div#c-post-moderation aside {
|
||||
float: left;
|
||||
width: 520px; }
|
||||
div#c-post-moderation section {
|
||||
float: left;
|
||||
width: 300px; }
|
||||
|
||||
/*** Note Container ***/
|
||||
div#note-container {
|
||||
position: absolute; }
|
||||
div#note-container div.note-body {
|
||||
background: #FFE;
|
||||
border: 1px solid black;
|
||||
max-width: 300px;
|
||||
min-width: 140px;
|
||||
min-height: 10px;
|
||||
position: absolute;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
overflow: auto; }
|
||||
div#note-container div.note-body p.tn {
|
||||
font-size: 0.8em;
|
||||
color: gray; }
|
||||
div#note-container div.note-box {
|
||||
position: absolute;
|
||||
border: 1px solid black;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
cursor: move;
|
||||
background: #FFE; }
|
||||
div#note-container div.note-box div.note-corner {
|
||||
background: black;
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
cursor: se-resize; }
|
||||
div#note-container div.unsaved {
|
||||
background: #FFF;
|
||||
border: 1px solid red; }
|
||||
div#note-container div.unsaved div.note-corner {
|
||||
background: red; }
|
||||
|
||||
div#jquery-test div.note {
|
||||
background: #FFE;
|
||||
border: 1px solid black;
|
||||
max-width: 300px;
|
||||
min-width: 140px;
|
||||
min-height: 10px;
|
||||
position: absolute;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
overflow: auto; }
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
psql -c "UPDATE posts SET is_flagged = false, is_pending = true, approver_id = null WHERE id = 1" danbooru2
|
||||
psql -c "DELETE FROM unapprovals" danbooru2
|
||||
@@ -1,4 +1,10 @@
|
||||
Factory.define(:tag_alias) do |f|
|
||||
f.antecedent_name "aaa"
|
||||
f.consequent_name "bbb"
|
||||
FactoryGirl.define do
|
||||
factory :tag_alias do
|
||||
antecedent_name "aaa"
|
||||
consequent_name "bbb"
|
||||
|
||||
after_create do |tag_alias|
|
||||
tag_alias.process!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
Factory.define(:tag_implication) do |f|
|
||||
f.antecedent_name "aaa"
|
||||
f.consequent_name "bbb"
|
||||
FactoryGirl.define do
|
||||
factory :tag_implication do
|
||||
antecedent_name "aaa"
|
||||
consequent_name "bbb"
|
||||
|
||||
after_create do |tag_implication|
|
||||
tag_implication.process!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
29
test/functional/moderator/tags_controller_test.rb
Normal file
29
test/functional/moderator/tags_controller_test.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
require 'test_helper'
|
||||
|
||||
module Moderator
|
||||
class TagsControllerTest < ActionController::TestCase
|
||||
context "The tags controller" do
|
||||
setup do
|
||||
@user = Factory.create(:moderator_user)
|
||||
CurrentUser.user = @user
|
||||
CurrentUser.ip_addr = "127.0.0.1"
|
||||
@post = Factory.create(:post)
|
||||
end
|
||||
|
||||
should "render the edit action" do
|
||||
get :edit, {}, {:user_id => @user.id}
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
should "execute the update action" do
|
||||
post :update, {:tag => {:predicate => "aaa", :consequent => "bbb"}}, {:user_id => @user.id}
|
||||
assert_redirected_to edit_moderator_tag_path
|
||||
end
|
||||
|
||||
should "fail gracefully if the update action fails" do
|
||||
post :update, {:tag => {:predicate => "", :consequent => "bbb"}}, {:user_id => @user.id}
|
||||
assert_redirected_to edit_moderator_tag_path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -7,6 +7,7 @@ class TagAliasesControllerTest < ActionController::TestCase
|
||||
CurrentUser.user = @user
|
||||
CurrentUser.ip_addr = "127.0.0.1"
|
||||
MEMCACHE.flush_all
|
||||
Delayed::Worker.delay_jobs = false
|
||||
end
|
||||
|
||||
teardown do
|
||||
|
||||
@@ -7,6 +7,7 @@ class TagImplicationsControllerTest < ActionController::TestCase
|
||||
CurrentUser.user = @user
|
||||
CurrentUser.ip_addr = "127.0.0.1"
|
||||
MEMCACHE.flush_all
|
||||
Delayed::Worker.delay_jobs = false
|
||||
end
|
||||
|
||||
teardown do
|
||||
|
||||
33
test/unit/moderator/tag_batch_change_test.rb
Normal file
33
test/unit/moderator/tag_batch_change_test.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
require "test_helper"
|
||||
|
||||
module Moderator
|
||||
class TagBatchChangeTest < ActiveSupport::TestCase
|
||||
context "a tag batch change" do
|
||||
setup do
|
||||
@user = Factory.create(:moderator_user)
|
||||
CurrentUser.user = @user
|
||||
CurrentUser.ip_addr = "127.0.0.1"
|
||||
@post = Factory.create(:post, :tag_string => "aaa")
|
||||
end
|
||||
|
||||
teardown do
|
||||
CurrentUser.user = nil
|
||||
CurrentUser.ip_addr = nil
|
||||
end
|
||||
|
||||
should "execute" do
|
||||
tag_batch_change = TagBatchChange.new("aaa", "bbb")
|
||||
tag_batch_change.execute
|
||||
@post.reload
|
||||
assert_equal("bbb", @post.tag_string)
|
||||
end
|
||||
|
||||
should "raise an error if there is no predicate" do
|
||||
tag_batch_change = TagBatchChange.new("", "bbb")
|
||||
assert_raises(TagBatchChange::Error) do
|
||||
tag_batch_change.execute
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -525,7 +525,13 @@ class PostTest < ActiveSupport::TestCase
|
||||
assert_equal(post2.id, relation.first.id)
|
||||
end
|
||||
|
||||
should "return posts for a tag subscription search"
|
||||
should "return posts for a tag subscription search" do
|
||||
post1 = Factory.create(:post, :tag_string => "aaa")
|
||||
sub = Factory.create(:tag_subscription, :tag_query => "aaa", :name => "zzz")
|
||||
TagSubscription.process_all
|
||||
relation = Post.tag_match("sub:#{CurrentUser.name}")
|
||||
assert_equal(1, relation.count)
|
||||
end
|
||||
|
||||
should "return posts for a particular rating" do
|
||||
post1 = Factory.create(:post, :rating => "s")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
require_relative '../test_helper'
|
||||
require 'test_helper'
|
||||
|
||||
class TagAliasTest < ActiveSupport::TestCase
|
||||
context "A tag alias" do
|
||||
@@ -15,14 +15,14 @@ class TagAliasTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
should "populate the creator information" do
|
||||
ta = Factory.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ta = FactoryGirl.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
assert_equal(CurrentUser.user.id, ta.creator_id)
|
||||
end
|
||||
|
||||
should "convert a tag to its normalized version" do
|
||||
tag1 = Factory.create(:tag, :name => "aaa")
|
||||
tag2 = Factory.create(:tag, :name => "bbb")
|
||||
ta = Factory.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ta = FactoryGirl.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
normalized_tags = TagAlias.to_aliased(["aaa", "ccc"])
|
||||
assert_equal(["bbb", "ccc"], normalized_tags.sort)
|
||||
end
|
||||
@@ -30,7 +30,7 @@ class TagAliasTest < ActiveSupport::TestCase
|
||||
should "update the cache" do
|
||||
tag1 = Factory.create(:tag, :name => "aaa")
|
||||
tag2 = Factory.create(:tag, :name => "bbb")
|
||||
ta = Factory.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ta = FactoryGirl.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
assert_equal("bbb", MEMCACHE.get("ta:aaa"))
|
||||
ta.destroy
|
||||
assert_nil(MEMCACHE.get("ta:aaa"))
|
||||
@@ -42,7 +42,7 @@ class TagAliasTest < ActiveSupport::TestCase
|
||||
post2 = Factory.create(:post, :tag_string => "ccc ddd")
|
||||
assert_equal("aaa bbb", post1.tag_string)
|
||||
assert_equal("ccc ddd", post2.tag_string)
|
||||
ta = Factory.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "ccc")
|
||||
ta = FactoryGirl.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "ccc")
|
||||
post1.reload
|
||||
post2.reload
|
||||
assert_equal("ccc bbb", post1.tag_string)
|
||||
@@ -50,7 +50,7 @@ class TagAliasTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
should "not validate for transitive relations" do
|
||||
ta1 = Factory.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ta1 = FactoryGirl.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
assert_difference("TagAlias.count", 0) do
|
||||
ta3 = Factory.build(:tag_alias, :antecedent_name => "bbb", :consequent_name => "ddd")
|
||||
ta3.save
|
||||
@@ -60,15 +60,15 @@ class TagAliasTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
should "record the alias's creator in the tag history" do
|
||||
user = Factory.create(:user)
|
||||
p1 = nil
|
||||
CurrentUser.scoped(user, "127.0.0.1") do
|
||||
p1 = Factory.create(:post, :tag_string => "aaa bbb ccc")
|
||||
uploader = Factory.create(:user)
|
||||
post = nil
|
||||
CurrentUser.scoped(uploader, "127.0.0.1") do
|
||||
post = Factory.create(:post, :tag_string => "aaa bbb ccc")
|
||||
end
|
||||
ta1 = Factory.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "xxx")
|
||||
p1.reload
|
||||
assert_not_equal(ta1.creator_id, p1.uploader_id)
|
||||
assert_equal(ta1.creator_id, p1.versions.last.updater_id)
|
||||
tag_alias = FactoryGirl.create(:tag_alias, :antecedent_name => "aaa", :consequent_name => "xxx")
|
||||
post.reload
|
||||
assert_not_equal(tag_alias.creator_id, post.uploader_id)
|
||||
assert_equal(tag_alias.creator_id, post.versions.last.updater_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,12 +16,12 @@ class TagImplicationTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
should "populate the creator information" do
|
||||
ti = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti = FactoryGirl.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
assert_equal(CurrentUser.user.id, ti.creator_id)
|
||||
end
|
||||
|
||||
should "not validate when a circular relation is created" do
|
||||
ti1 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti1 = FactoryGirl.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti2 = Factory.build(:tag_implication, :antecedent_name => "bbb", :consequent_name => "aaa")
|
||||
ti2.save
|
||||
assert(ti2.errors.any?, "Tag implication should not have validated.")
|
||||
@@ -29,34 +29,18 @@ class TagImplicationTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
should "not allow for duplicates" do
|
||||
ti1 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti1 = FactoryGirl.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti2 = Factory.build(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti2.save
|
||||
assert(ti2.errors.any?, "Tag implication should not have validated.")
|
||||
assert_equal("Antecedent name has already been taken", ti2.errors.full_messages.join(""))
|
||||
end
|
||||
|
||||
should "clear the cache upon saving" do
|
||||
ti1 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
assert_equal(["bbb"], ti1.descendant_names_array)
|
||||
assert_equal(["bbb"], MEMCACHE.get("ti:aaa"))
|
||||
ti1.update_attributes(
|
||||
:consequent_name => "ccc"
|
||||
)
|
||||
assert_equal(["ccc"], MEMCACHE.get("ti:aaa"))
|
||||
end
|
||||
|
||||
should "clear the cache upon destruction" do
|
||||
ti1 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti1.destroy
|
||||
assert_nil(MEMCACHE.get("ti:aaa"))
|
||||
end
|
||||
|
||||
should "calculate all its descendants" do
|
||||
ti1 = Factory.create(:tag_implication, :antecedent_name => "bbb", :consequent_name => "ccc")
|
||||
ti1 = FactoryGirl.create(:tag_implication, :antecedent_name => "bbb", :consequent_name => "ccc")
|
||||
assert_equal("ccc", ti1.descendant_names)
|
||||
assert_equal(["ccc"], ti1.descendant_names_array)
|
||||
ti2 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti2 = FactoryGirl.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
assert_equal("bbb ccc", ti2.descendant_names)
|
||||
assert_equal(["bbb", "ccc"], ti2.descendant_names_array)
|
||||
ti1.reload
|
||||
@@ -64,15 +48,9 @@ class TagImplicationTest < ActiveSupport::TestCase
|
||||
assert_equal(["ccc"], ti1.descendant_names_array)
|
||||
end
|
||||
|
||||
should "cache its descendants" do
|
||||
ti1 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
assert_equal(["bbb"], ti1.descendant_names_array)
|
||||
assert_equal(["bbb"], MEMCACHE.get("ti:aaa"))
|
||||
end
|
||||
|
||||
should "update its descendants on save" do
|
||||
ti1 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti2 = Factory.create(:tag_implication, :antecedent_name => "ccc", :consequent_name => "ddd")
|
||||
ti1 = FactoryGirl.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti2 = FactoryGirl.create(:tag_implication, :antecedent_name => "ccc", :consequent_name => "ddd")
|
||||
ti2.update_attributes(
|
||||
:antecedent_name => "bbb"
|
||||
)
|
||||
@@ -83,10 +61,10 @@ class TagImplicationTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
should "update the decendants for its parent on save" do
|
||||
ti1 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti2 = Factory.create(:tag_implication, :antecedent_name => "bbb", :consequent_name => "ccc")
|
||||
ti3 = Factory.create(:tag_implication, :antecedent_name => "ccc", :consequent_name => "ddd")
|
||||
ti4 = Factory.create(:tag_implication, :antecedent_name => "ccc", :consequent_name => "eee")
|
||||
ti1 = FactoryGirl.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "bbb")
|
||||
ti2 = FactoryGirl.create(:tag_implication, :antecedent_name => "bbb", :consequent_name => "ccc")
|
||||
ti3 = FactoryGirl.create(:tag_implication, :antecedent_name => "ccc", :consequent_name => "ddd")
|
||||
ti4 = FactoryGirl.create(:tag_implication, :antecedent_name => "ccc", :consequent_name => "eee")
|
||||
ti1.reload
|
||||
ti2.reload
|
||||
ti3.reload
|
||||
@@ -99,8 +77,8 @@ class TagImplicationTest < ActiveSupport::TestCase
|
||||
|
||||
should "update any affected post upon save" do
|
||||
p1 = Factory.create(:post, :tag_string => "aaa bbb ccc")
|
||||
ti1 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "xxx")
|
||||
ti2 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "yyy")
|
||||
ti1 = FactoryGirl.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "xxx")
|
||||
ti2 = FactoryGirl.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "yyy")
|
||||
p1.reload
|
||||
assert_equal("aaa yyy xxx bbb ccc", p1.tag_string)
|
||||
end
|
||||
@@ -111,7 +89,7 @@ class TagImplicationTest < ActiveSupport::TestCase
|
||||
CurrentUser.scoped(user, "127.0.0.1") do
|
||||
p1 = Factory.create(:post, :tag_string => "aaa bbb ccc")
|
||||
end
|
||||
ti1 = Factory.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "xxx")
|
||||
ti1 = FactoryGirl.create(:tag_implication, :antecedent_name => "aaa", :consequent_name => "xxx")
|
||||
p1.reload
|
||||
assert_not_equal(ti1.creator_id, p1.uploader_id)
|
||||
assert_equal(ti1.creator_id, p1.versions.last.updater_id)
|
||||
|
||||
@@ -6,6 +6,7 @@ class TagTest < ActiveSupport::TestCase
|
||||
CurrentUser.user = user
|
||||
CurrentUser.ip_addr = "127.0.0.1"
|
||||
MEMCACHE.flush_all
|
||||
Delayed::Worker.delay_jobs = false
|
||||
end
|
||||
|
||||
teardown do
|
||||
|
||||
BIN
tmp/test.jpg
Normal file
BIN
tmp/test.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Reference in New Issue
Block a user