add post previews to user profile, improved ui for tag subscriptions

This commit is contained in:
albert
2013-02-21 18:18:08 -05:00
parent d7fb091bd1
commit 23c0cb5529
9 changed files with 234 additions and 96 deletions

View File

@@ -2,6 +2,28 @@
div#c-users { div#c-users {
div#a-show { div#a-show {
div.grid {
div.col {
float: left;
width: 50%;
}
div.box {
clear: both;
margin-bottom: 2em;
}
/* clearfix hacks */
div.box:before, div.box:after {
content: "";
display: table;
}
div.box:after {
clear: both;
}
}
dl { dl {
dt { dt {
width: 12em; width: 12em;

View File

@@ -6,6 +6,7 @@ class TagSubscription < ActiveRecord::Base
before_save :limit_tag_count before_save :limit_tag_count
attr_accessible :name, :tag_query, :post_ids, :is_public, :is_visible_on_profile attr_accessible :name, :tag_query, :post_ids, :is_public, :is_visible_on_profile
validates_presence_of :name, :tag_query, :is_public, :creator_id validates_presence_of :name, :tag_query, :is_public, :creator_id
validate :creator_can_create_subscriptions
def normalize_name def normalize_name
self.name = name.gsub(/\W/, "_") self.name = name.gsub(/\W/, "_")
@@ -19,6 +20,15 @@ class TagSubscription < ActiveRecord::Base
process process
end end
def creator_can_create_subscriptions
if TagSubscription.owned_by(creator).count >= Danbooru.config.max_tag_subscriptions
self.errors.add(:creator, "can subscribe up to #{Danbooru.config.max_tag_subscriptions} tags")
return false
else
return true
end
end
def tag_query_array def tag_query_array
Tag.scan_query(tag_query) Tag.scan_query(tag_query)
end end
@@ -94,10 +104,10 @@ class TagSubscription < ActiveRecord::Base
end end
def self.find_post_ids(user_id, name = nil, limit = Danbooru.config.tag_subscription_post_limit) def self.find_post_ids(user_id, name = nil, limit = Danbooru.config.tag_subscription_post_limit)
relation = where(["creator_id = ?", user_id]) relation = where("creator_id = ?", user_id)
if name if name
relation = relation.where(["name ILIKE ? ESCAPE E'\\\\'", name.to_escaped_for_sql_like]) relation = relation.where("name ILIKE ? ESCAPE E'\\\\'", name.to_escaped_for_sql_like)
end end
relation.each do |tag_sub| relation.each do |tag_sub|

View File

@@ -25,10 +25,16 @@ class UserPresenter
end end
end end
def tag_subscriptions(template) def tag_subscriptions
user.subscriptions.map do |subscription| if CurrentUser.user.id == user.id
template.link_to(subscription.name, template.tag_subscription_path(subscription)) user.subscriptions
end.join("; ") else
user.subscriptions.select {|x| x.is_public?}
end
end
def posts_for_subscription(subscription)
Post.where("id in (?)", subscription.post_id_array.slice(0, 6).map(&:to_i))
end end
def upload_limit def upload_limit
@@ -57,39 +63,55 @@ class UserPresenter
return string return string
end end
def uploads(template) def uploads
@uploads ||= Post.where("uploader_id = ?", user.id).order("id desc").limit(6)
end
def has_uploads?
user.post_upload_count > 0
end
def favorites
@favorites ||= user.favorites.limit(6).includes(:post).map(&:post)
end
def has_favorites?
user.favorite_count > 0
end
def upload_count(template)
template.link_to(user.post_upload_count, template.posts_path(:tags => "user:#{user.name}")) template.link_to(user.post_upload_count, template.posts_path(:tags => "user:#{user.name}"))
end end
def deleted_uploads(template) def deleted_upload_count(template)
template.link_to(Post.for_user(user.id).deleted.count, template.posts_path(:tags => "status:deleted user:#{user.name}")) template.link_to(Post.for_user(user.id).deleted.count, template.posts_path(:tags => "status:deleted user:#{user.name}"))
end end
def favorites(template) def favorite_count(template)
template.link_to(user.favorite_count, template.posts_path(:tags => "fav:#{user.name}")) template.link_to(user.favorite_count, template.posts_path(:tags => "fav:#{user.name}"))
end end
def comments(template) def comment_count(template)
template.link_to(Comment.for_creator(user.id).count, template.comments_path(:search => {:creator_id => user.id})) template.link_to(Comment.for_creator(user.id).count, template.comments_path(:search => {:creator_id => user.id}))
end end
def post_versions(template) def post_version_count(template)
template.link_to(user.post_update_count, template.post_versions_path(:search => {:updater_id => user.id})) template.link_to(user.post_update_count, template.post_versions_path(:search => {:updater_id => user.id}))
end end
def note_versions(template) def note_version_count(template)
template.link_to(user.note_update_count, template.note_versions_path(:search => {:updater_id => user.id})) template.link_to(user.note_update_count, template.note_versions_path(:search => {:updater_id => user.id}))
end end
def wiki_page_versions(template) def wiki_page_version_count(template)
template.link_to(WikiPageVersion.for_user(user.id).count, template.wiki_page_versions_path(:search => {:updater_id => user.id})) template.link_to(WikiPageVersion.for_user(user.id).count, template.wiki_page_versions_path(:search => {:updater_id => user.id}))
end end
def forum_posts(template) def forum_post_count(template)
template.link_to(ForumPost.for_user(user.id).count, template.forum_posts_path(:search => {:creator_id => user.id})) template.link_to(ForumPost.for_user(user.id).count, template.forum_posts_path(:search => {:creator_id => user.id}))
end end
def pool_versions(template) def pool_version_count(template)
template.link_to(PoolVersion.for_user(user.id).count, template.pool_versions_path(:search => {:updater_id => user.id})) template.link_to(PoolVersion.for_user(user.id).count, template.pool_versions_path(:search => {:updater_id => user.id}))
end end
@@ -101,7 +123,7 @@ class UserPresenter
end end
end end
def approvals(template) def approval_count(template)
template.link_to(Post.where("approver_id = ?", user.id).count, template.posts_path(:tags => "approver:#{user.name}")) template.link_to(Post.where("approver_id = ?", user.id).count, template.posts_path(:tags => "approver:#{user.name}"))
end end
@@ -113,15 +135,17 @@ class UserPresenter
template.link_to("positive:#{positive} neutral:#{neutral} negative:#{negative}", template.user_feedbacks_path(:search => {:user_id => user.id})) template.link_to("positive:#{positive} neutral:#{neutral} negative:#{negative}", template.user_feedbacks_path(:search => {:user_id => user.id}))
end end
def subscriptions(template) def subscriptions
if user.subscriptions.any? user.subscriptions
str = user.subscriptions.map do |subscription| #
template.link_to(subscription.name, template.posts_path(:tags => "sub:#{user.name}:#{subscription.name}")) # if user.subscriptions.any?
end.join(", ") # str = user.subscriptions.map do |subscription|
str += " [" + template.link_to("edit", template.tag_subscriptions_path) + "]" # template.link_to(subscription.name, template.posts_path(:tags => "sub:#{user.name}:#{subscription.name}"))
str.html_safe # end.join(", ")
else # str += " [" + template.link_to("edit", template.tag_subscriptions_path) + "]"
"None" # str.html_safe
end # else
# "None"
# end
end end
end end

View File

@@ -1,8 +1,12 @@
<section id="related-box"> <section id="related-box">
<h1>Related Searches</h1> <h1>Related</h1>
<ul id="related-list"> <ul id="related-list">
<% if @post_set.has_deleted? %> <% if @post_set.has_deleted? %>
<li><%= link_to "Deleted", posts_path(:tags => "#{params[:tags]} status:deleted") %></li> <li><%= link_to "Deleted posts", posts_path(:tags => "#{params[:tags]} status:deleted") %></li>
<% end %>
<% if @post_set.is_tag_subscription? %>
<li><%= link_to "Edit tag subscription", tag_subscriptions_path %></li>
<% end %> <% end %>
</ul> </ul>
</section> </section>

View File

@@ -2,60 +2,106 @@
<div id="a-show"> <div id="a-show">
<h1><%= @presenter.name %></h1> <h1><%= @presenter.name %></h1>
<dl> <div class="grid">
<dt>Join Date</dt> <div class="col">
<dd><%= @presenter.join_date %></dd> <div class="box">
<h2><%= link_to "Uploads", posts_path(:tags => "user:#{@user.name}") %></h2>
<% if @presenter.has_uploads? %>
<div>
<% @presenter.uploads.each do |post| %>
<%= PostPresenter.preview(post) %>
<% end %>
</div>
<% else %>
<p>None</p>
<% end %>
</div>
<dt>Inviter</dt> <div class="box">
<dd><%= @presenter.inviter(self) %></dd> <h2><%= link_to "Favorites", posts_path(:tags => "fav:#{@user.name}") %></h2>
<% if @presenter.has_favorites? %>
<div>
<% @presenter.favorites.each do |post| %>
<%= PostPresenter.preview(post) %>
<% end %>
</div>
<% else %>
<p>None</p>
<% end %>
</div>
<dt>Level</dt> <div class="box">
<dd><%= @presenter.level %></dd> <h2>Subscriptions</h2>
<% @presenter.subscriptions.each do |subscription| %>
<div class="box">
<h3><%= link_to subscription.name, posts_path(:tags => "sub:#{@user.name}:#{subscription.name}") %></h3>
<% if @user.is_banned? %> <div>
<dt>Ban reason</dt> <% @presenter.posts_for_subscription(subscription).each do |post| %>
<dd><%= @presenter.ban_reason %></dd> <%= PostPresenter.preview(post) %>
<% end %> <% end %>
</div>
</div>
<dt>Upload Limit</dt> <% end %>
<dd><%= @presenter.upload_limit %></dd> </div>
</div>
<dt>Uploads</dt> <div class="col">
<dd><%= @presenter.uploads(self) %></dd> <h2>Statistics</h2>
<dl>
<dt>Join Date</dt>
<dd><%= @presenter.join_date %></dd>
<dt>Deleted Uploads</dt> <dt>Inviter</dt>
<dd><%= @presenter.deleted_uploads(self) %></dd> <dd><%= @presenter.inviter(self) %></dd>
<dt>Favorites</dt> <dt>Level</dt>
<dd><%= @presenter.favorites(self) %></dd> <dd><%= @presenter.level %></dd>
<dt>Subscriptions</dt> <% if @user.is_banned? %>
<dd><%= @presenter.subscriptions(self) %></dd> <dt>Ban reason</dt>
<dd><%= @presenter.ban_reason %></dd>
<% end %>
<dt>Post Changes</dt> <dt>Upload Limit</dt>
<dd><%= @presenter.post_versions(self) %></dd> <dd><%= @presenter.upload_limit %></dd>
<dt>Note Changes</dt> <dt>Uploads</dt>
<dd><%= @presenter.note_versions(self) %></dd> <dd><%= @presenter.upload_count(self) %></dd>
<dt>Wiki Page Changes</dt> <dt>Deleted Uploads</dt>
<dd><%= @presenter.wiki_page_versions(self) %></dd> <dd><%= @presenter.deleted_upload_count(self) %></dd>
<dt>Pool Changes</dt> <dt>Favorites</dt>
<dd><%= @presenter.pool_versions(self) %></dd> <dd><%= @presenter.favorite_count(self) %></dd>
<dt>Forum Posts</dt> <dt>Post Changes</dt>
<dd><%= @presenter.forum_posts(self) %></dd> <dd><%= @presenter.post_version_count(self) %></dd>
<dt>Approvals</dt> <dt>Note Changes</dt>
<dd><%= @presenter.approvals(self) %></dd> <dd><%= @presenter.note_version_count(self) %></dd>
<dt>Comments</dt> <dt>Wiki Page Changes</dt>
<dd><%= @presenter.comments(self) %></dd> <dd><%= @presenter.wiki_page_version_count(self) %></dd>
<dt>Feedback</dt> <dt>Pool Changes</dt>
<dd><%= @presenter.feedbacks(self) %></dd> <dd><%= @presenter.pool_version_count(self) %></dd>
</dl>
<dt>Forum Posts</dt>
<dd><%= @presenter.forum_post_count(self) %></dd>
<dt>Approvals</dt>
<dd><%= @presenter.approval_count(self) %></dd>
<dt>Comments</dt>
<dd><%= @presenter.comment_count(self) %></dd>
<dt>Feedback</dt>
<dd><%= @presenter.feedbacks(self) %></dd>
</dl>
</div>
</div>
</div> </div>
</div> </div>

View File

@@ -1,11 +1,11 @@
class AddIndexUpdatedAtOnPoolVersions < ActiveRecord::Migration class AddIndexUpdatedAtOnPoolVersions < ActiveRecord::Migration
def up def up
execute "set statement_timeout = 0" execute "set statement_timeout = 0"
add_index :post_versions, :updated_at add_index :pool_versions, :updated_at
end end
def down def down
execute "set statement_timeout = 0" execute "set statement_timeout = 0"
remove_index :post_versions, :updated_at remove_index :pool_versions, :updated_at
end end
end end

View File

@@ -5647,6 +5647,13 @@ CREATE INDEX index_notes_on_post_id ON notes USING btree (post_id);
CREATE INDEX index_pool_versions_on_pool_id ON pool_versions USING btree (pool_id); CREATE INDEX index_pool_versions_on_pool_id ON pool_versions USING btree (pool_id);
--
-- Name: index_pool_versions_on_updated_at; Type: INDEX; Schema: public; Owner: -; Tablespace:
--
CREATE INDEX index_pool_versions_on_updated_at ON pool_versions USING btree (updated_at);
-- --
-- Name: index_pool_versions_on_updater_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- Name: index_pool_versions_on_updater_id; Type: INDEX; Schema: public; Owner: -; Tablespace:
-- --
@@ -6199,3 +6206,5 @@ INSERT INTO schema_migrations (version) VALUES ('20130219184743');
INSERT INTO schema_migrations (version) VALUES ('20130221032344'); INSERT INTO schema_migrations (version) VALUES ('20130221032344');
INSERT INTO schema_migrations (version) VALUES ('20130221035518'); INSERT INTO schema_migrations (version) VALUES ('20130221035518');
INSERT INTO schema_migrations (version) VALUES ('20130221214811');

View File

@@ -14,6 +14,19 @@ class TagSubscriptionTest < ActiveSupport::TestCase
end end
context "A tag subscription" do context "A tag subscription" do
context "for a user with too many subscriptions" do
setup do
Danbooru.config.stubs(:max_tag_subscriptions).returns(0)
@user = FactoryGirl.create(:user)
end
should "fail" do
sub = FactoryGirl.build(:tag_subscription, :tag_query => "aaa bbb", :creator => @user, :name => "zzz")
sub.save
assert_equal(["Creator can subscribe up to 0 tags"], sub.errors.full_messages)
end
end
should "find the union of all posts for each tag in its tag query" do should "find the union of all posts for each tag in its tag query" do
posts = [] posts = []
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
@@ -21,10 +34,12 @@ class TagSubscriptionTest < ActiveSupport::TestCase
posts << FactoryGirl.create(:post, :tag_string => "bbb") posts << FactoryGirl.create(:post, :tag_string => "bbb")
posts << FactoryGirl.create(:post, :tag_string => "ccc") posts << FactoryGirl.create(:post, :tag_string => "ccc")
posts << FactoryGirl.create(:post, :tag_string => "ddd") posts << FactoryGirl.create(:post, :tag_string => "ddd")
sub_1 = FactoryGirl.create(:tag_subscription, :tag_query => "aaa bbb", :creator => user, :name => "zzz") CurrentUser.scoped(user, "127.0.0.1") do
sub_2 = FactoryGirl.create(:tag_subscription, :tag_query => "ccc", :creator => user, :name => "yyy") sub_1 = FactoryGirl.create(:tag_subscription, :tag_query => "aaa bbb", :name => "zzz")
assert_equal([posts[1].id, posts[0].id], TagSubscription.find_posts(user.id, "zzz").map(&:id)) sub_2 = FactoryGirl.create(:tag_subscription, :tag_query => "ccc", :name => "yyy")
assert_equal([posts[2].id, posts[1].id, posts[0].id], TagSubscription.find_posts(user.id).map(&:id)) assert_equal([posts[1].id, posts[0].id], TagSubscription.find_posts(user.id, "zzz").map(&:id))
assert_equal([posts[2].id, posts[1].id, posts[0].id], TagSubscription.find_posts(user.id).map(&:id))
end
end end
should "cache its tag query results" do should "cache its tag query results" do
@@ -33,26 +48,30 @@ class TagSubscriptionTest < ActiveSupport::TestCase
posts << FactoryGirl.create(:post, :tag_string => "aaa") posts << FactoryGirl.create(:post, :tag_string => "aaa")
posts << FactoryGirl.create(:post, :tag_string => "bbb") posts << FactoryGirl.create(:post, :tag_string => "bbb")
posts << FactoryGirl.create(:post, :tag_string => "ccc") posts << FactoryGirl.create(:post, :tag_string => "ccc")
sub = FactoryGirl.create(:tag_subscription, :tag_query => "aaa bbb", :creator => user, :name => "zzz") CurrentUser.scoped(user, "127.0.0.1") do
assert_equal("#{posts[1].id},#{posts[0].id}", sub.post_ids) sub = FactoryGirl.create(:tag_subscription, :tag_query => "aaa bbb", :name => "zzz")
assert_equal("#{posts[1].id},#{posts[0].id}", sub.post_ids)
end
end end
should "find posts based on its cached post ids" do should "find posts based on its cached post ids" do
user = FactoryGirl.create(:user) user = FactoryGirl.create(:user)
subs = [] CurrentUser.scoped(user, "127.0.0.1") do
subs << FactoryGirl.create(:tag_subscription, :tag_query => "aaa", :creator => user, :name => "zzz") subs = []
subs << FactoryGirl.create(:tag_subscription, :tag_query => "bbb", :creator => user, :name => "yyy") subs << FactoryGirl.create(:tag_subscription, :tag_query => "aaa", :name => "zzz")
assert_equal([], TagSubscription.find_posts(user.id)) subs << FactoryGirl.create(:tag_subscription, :tag_query => "bbb", :name => "yyy")
assert_equal([], TagSubscription.find_posts(user.id, "zzz")) assert_equal([], TagSubscription.find_posts(user.id))
assert_equal([], TagSubscription.find_posts(user.id, "yyy")) assert_equal([], TagSubscription.find_posts(user.id, "zzz"))
posts = [] assert_equal([], TagSubscription.find_posts(user.id, "yyy"))
posts << FactoryGirl.create(:post, :tag_string => "aaa") posts = []
posts << FactoryGirl.create(:post, :tag_string => "bbb") posts << FactoryGirl.create(:post, :tag_string => "aaa")
posts << FactoryGirl.create(:post, :tag_string => "ccc") posts << FactoryGirl.create(:post, :tag_string => "bbb")
subs.each {|x| x.process; x.save} posts << FactoryGirl.create(:post, :tag_string => "ccc")
assert_equal([posts[1].id, posts[0].id], TagSubscription.find_posts(user.id).map(&:id)) subs.each {|x| x.process; x.save}
assert_equal([posts[0].id], TagSubscription.find_posts(user.id, "zzz").map(&:id)) assert_equal([posts[1].id, posts[0].id], TagSubscription.find_posts(user.id).map(&:id))
assert_equal([posts[1].id], TagSubscription.find_posts(user.id, "yyy").map(&:id)) assert_equal([posts[0].id], TagSubscription.find_posts(user.id, "zzz").map(&:id))
assert_equal([posts[1].id], TagSubscription.find_posts(user.id, "yyy").map(&:id))
end
end end
end end
@@ -66,8 +85,12 @@ class TagSubscriptionTest < ActiveSupport::TestCase
posts << FactoryGirl.create(:post, :tag_string => "bbb") posts << FactoryGirl.create(:post, :tag_string => "bbb")
posts << FactoryGirl.create(:post, :tag_string => "ccc") posts << FactoryGirl.create(:post, :tag_string => "ccc")
subscriptions = [] subscriptions = []
subscriptions << FactoryGirl.create(:tag_subscription, :tag_query => "aaa", :creator => users[0]) CurrentUser.scoped(users[0], "127.0.0.1") do
subscriptions << FactoryGirl.create(:tag_subscription, :tag_query => "bbb", :creator => users[1]) subscriptions << FactoryGirl.create(:tag_subscription, :tag_query => "aaa")
end
CurrentUser.scoped(users[1], "127.0.0.1") do
subscriptions << FactoryGirl.create(:tag_subscription, :tag_query => "bbb")
end
TagSubscription.process_all TagSubscription.process_all
subscriptions.each {|x| x.reload} subscriptions.each {|x| x.reload}
assert_equal("#{posts[0].id}", subscriptions[0].post_ids) assert_equal("#{posts[0].id}", subscriptions[0].post_ids)