added limit methods to user, more work on post views

This commit is contained in:
albert
2010-03-12 15:18:30 -05:00
parent 9f29ffc8c3
commit 9eb578927c
18 changed files with 282 additions and 108 deletions

View File

@@ -1,10 +1,54 @@
class UploadsController < ApplicationController
def new
@upload = Upload.new
if params[:url]
@post = Post.find_by_source(params[:url])
end
end
def show
end
def create
unless @current_user.can_upload?
respond_to_error("Daily limit exceeded", {:controller => "user", :action => "upload_limit"}, :status => 421)
return
end
if @current_user.is_contributor_or_higher?
status = "active"
else
status = "pending"
end
begin
@post = Post.new(params[:post].merge(:updater_user_id => @current_user.id, :updater_ip_addr => request.remote_ip))
@post.user_id = @current_user.id
@post.status = status
@post.ip_addr = request.remote_ip
@post.save
rescue Errno::ENOENT
respond_to_error("Internal error. Try uploading again.", {:controller => "post", :action => "error"})
return
end
if @post.errors.empty?
if params[:md5] && @post.md5 != params[:md5].downcase
@post.destroy
respond_to_error("MD5 mismatch", {:action => "error"}, :status => 420)
else
respond_to_success("Post uploaded", {:controller => "post", :action => "show", :id => @post.id, :tag_title => @post.tag_title}, :api => {:post_id => @post.id, :location => url_for(:controller => "post", :action => "show", :id => @post.id)})
end
elsif @post.errors.invalid?(:md5)
p = Post.find_by_md5(@post.md5)
update = { :tags => p.cached_tags + " " + params[:post][:tags], :updater_user_id => session[:user_id], :updater_ip_addr => request.remote_ip }
update[:source] = @post.source if p.source.blank? && !@post.source.blank?
p.update_attributes(update)
respond_to_error("Post already exists", {:controller => "post", :action => "show", :id => p.id, :tag_title => @post.tag_title}, :api => {:location => url_for(:controller => "post", :action => "show", :id => p.id)}, :status => 423)
else
respond_to_error(@post, :action => "error")
end
end
end

View File

@@ -1,62 +1,28 @@
module ApplicationHelper
def nav_link_to(text, url, html_options = nil)
if url.include?(params[:controller]) || (%w(tag_alias tag_implication).include?(params[:controller]) && url =~ /\/tag/)
klass = "current-page"
def nav_link_to(text, url, options = nil)
if nav_link_match(params[:controller], url)
klass = "current"
else
klass = nil
end
(%{<li class="#{klass}">} + link_to(text, url, html_options) + "</li>").html_safe
end
def format_text(text, options = {})
DText.parse(text)
end
def id_to_color(id)
r = id % 255
g = (id >> 8) % 255
b = (id >> 16) % 255
"rgb(#{r}, #{g}, #{b})"
end
def tag_header(tags)
unless tags.blank?
'/' + Tag.scan_query(tags).map {|t| link_to(h(t.tr("_", " ")), posts_path(:tags => t))}.join("+")
end
content_tag("li", link_to(text, url, options), :class => klass)
end
def compact_time(time)
if time > Time.now.beginning_of_day
time.strftime("%H:%M")
elsif time > Time.now.beginning_of_year
time.strftime("%b %e")
protected
def nav_link_match(controller, url)
url =~ case controller
when "tag_aliases", "tag_implications"
/^\/tags/
when "sessions", "user_maintenance"
/^\/users/
when "forum_posts"
/^\/forum_topics/
else
time.strftime("%b %e, %Y")
/^\/#{controller}/
end
end
def print_preview(post, options = {})
unless Danbooru.config.can_see_post?(post, @current_user)
return ""
end
options = {:blacklist => true}.merge(options)
blacklist = options[:blacklist] ? "blacklisted" : ""
width, height = post.preview_dimensions
image_id = options[:image_id]
image_id = %{id="#{h(image_id)}"} if image_id
title = "#{h(post.cached_tags)} rating:#{post.rating} score:#{post.score} uploader:#{h(post.uploader_name)}"
content_for(:blacklist) {"Post.register(#{post.to_json});\n"} if options[:blacklist]
%{
<span class="thumb #{blacklist}" id="p#{post.id}">
<a href="/posts/#{post.id}">
<img #{image_id} class="preview #{'flagged' if post.is_flagged?} #{'pending' if post.is_pending?}" src="#{post.preview_url}" title="#{title}" alt="#{title}" width="#{width}" height="#{height}">
</a>
</span>
}
end
end

View File

@@ -109,6 +109,8 @@ class User < ActiveRecord::Base
module LevelMethods
def promote_to_admin_if_first_user
return if Rails.env.test?
if User.count == 0
self.is_admin = true
end
@@ -168,6 +170,54 @@ class User < ActiveRecord::Base
end
end
module LimitMethods
def can_upload?
if is_contributor?
true
elsif created_at > 1.week.ago
false
else
upload_limit > 0
end
end
def can_comment?
if is_privileged?
true
elsif created_at > 1.week.ago
false
else
Comment.where("creator_id = ? and created_at > ?", id, 1.hour.ago).count <= Danbooru.config.member_comment_limit
end
end
def can_comment_vote?
CommentVote.where("user_id = ? and created_at > ?", id, 1.hour.ago).count < 10
end
def can_remove_from_pools?
created_at <= 1.week.ago
end
def upload_limit
deleted_count = Post.where("is_deleted = true and user_id = ?", id).count
unapproved_count = Post.where("is_pending = true and user_id = ?", id).count
approved_count = Post.where("is_flagged = false and is_deleted = false and is_pending = false and user_id = ?", id).count
limit = base_upload_limit + (approved_count / 10) - (deleted_count / 4) - unapproved_count
if limit > 20
limit = 20
end
if limit < 0
limit = 0
end
limit
end
end
include NameMethods
include PasswordMethods
extend AuthenticationMethods
@@ -176,6 +226,7 @@ class User < ActiveRecord::Base
include EmailVerificationMethods
include BlacklistMethods
include ForumMethods
include LimitMethods
def initialize_default_image_size
self.default_image_size = "Medium"

View File

@@ -1,7 +1,7 @@
<!doctype html>
<html>
<head>
<title><%= yield(:page_title) || Danbooru.config.app_name %></title>
<title><%= yield(:page_title) %></title>
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<link rel="top" title="<%= Danbooru.config.app_name %>" href="/">
<%= csrf_meta_tag %>
@@ -17,7 +17,7 @@
</head>
<body>
<nav>
<h1><%= link_to(Danbooru.config.app_name, "/") %><%= yield :page_header %></h1>
<h1><%= link_to(Danbooru.config.app_name, "/") %><%= yield :page_title %></h1>
<menu>
<% if @current_user.is_anonymous? %>
<%= nav_link_to("Login", new_session_path) %>

View File

@@ -0,0 +1,13 @@
<% content_for(:secondary_nav_links) do %>
<menu>
<li>Listing</li>
<li><%= link_to "Upload", new_upload_path %></li>
<li>Popular</li>
<li>Favorites</li>
<li>Subscriptions</li>
<li>Changes</li>
<li>Approvals</li>
<li>Moderate</li>
<li>Help</li>
</menu>
<% end %>

View File

@@ -18,10 +18,10 @@
<h1>Mode</h1>
<form action="/">
<select name="mode">
<option value="view">View posts</option>
<option value="edit">Edit posts</option>
<option value="add-fav">Add to favorites</option>
<option value="remove-fav">Remove from favorites</option>
<option value="view">View</option>
<option value="edit">Edit</option>
<option value="add-fav">Favorite</option>
<option value="remove-fav">Unfavorite</option>
<option value="rating-s">Rate safe</option>
<option value="rating-q">Rate questionable</option>
<option value="rating-e">Rate explicit</option>
@@ -32,9 +32,9 @@
<option value="edit-tag-script">Edit tag script</option>
<option value="apply-tag-script">Apply tag script</option>
<% if @current_user.is_janitor? %>
<option value="approve">Approve post</option>
<option value="approve">Approve</option>
<% end %>
<option value="flag">Flag post</option>
<option value="unapprove">Unapprove</option>
</select>
</form>
</section>
@@ -82,16 +82,4 @@
/ <%= @post_set.tags %>
<% end %>
<% content_for(:secondary_nav_links) do %>
<menu>
<li>Listing</li>
<li>Upload</li>
<li>Popular</li>
<li>Favorites</li>
<li>Subscriptions</li>
<li>Changes</li>
<li>Approvals</li>
<li>Moderate</li>
<li>Help</li>
</menu>
<% end %>
<%= render :partial => "posts/common_secondary_nav_links" %>

View File

@@ -0,0 +1,54 @@
<div id="upload-guide-notice">
<p>Before uploading, please read the <%= link_to "how to upload guide", wiki_page_path("howto:upload") %>. It explains how to tag and what ratings are.</p>
</div>
<% form_for @upload do |f| %>
<% if params[:url] %>
<div id="image-preview">
<%= image_tag(params[:url], :title => "Preview") %>
<p id="scale"></p>
</div>
<% if @post %>
<p>This post was probably already uploaded (<%= link_to "post ##{@post.id}", posts_path(@post), :target => "_blank" %>).</p>
<% end %>
<% end %>
<fieldset>
<legend>Upload</legend>
<p>
<%= f.label :file %>
<%= f.file_field :file, :size => 50 %>
</p>
<p>
<%= f.label :source, nil, :title => "You can enter a URL to have #{Danbooru.config.app_name} automatically download and process it" %>
<%= f.text_field :source, :size => 50, :value => params[:url] %>
</p>
<p>
<%= f.label :tag_string, "Tags" %>
<%= f.text_area :tag_string, :size => "60x4" %>
</p>
<p>
<%= f.label :rating_e, "Explicit", :title => "Hardcore porn, visible genitals, gore" %>
<%= f.radio_button :rating, :e %>
<%= f.label :rating_q, "Questionable", :title => "Nudity, anything erotic" %>
<%= f.radio_button :rating, :q %>
<%= f.label :rating_s, "Safe", :title => "Everything else" %>
<%= f.radio_button :rating, :s %>
</p>
<p>
<%= submit_tag "Submit" %>
</p>
</fieldset>
<% end %>
<% content_for(:page_title) do %>
/ Upload
<% end %>

View File

@@ -1,39 +1,45 @@
<% form_for @user do |f| %>
<p>Hover over the labels to see a brief explanation of the setting. Required fields are marked in red.</p>
<fieldset>
<legend>Basic</legend>
<p>
<%= f.label :email %>
<%= f.text_field :email %>
<% if Danbooru.config.enable_email_verification? %>
<%= f.text_field :email %>
<% else %>
<%= f.text_field :email, :class => "required" %>
<% end %>
</p>
<p>
<%= f.label :receive_email_notifications, "Email notifications" %>
<%= f.label :receive_email_notifications, "Email notifications", :title => "Enable to receive email notification when you receive a DMail" %>
<%= f.check_box :receive_email_notifications %>
</p>
<p>
<%= f.label :comment_threshold %>
<%= f.label :comment_threshold, nil, :title => "Comments below this score will be hidden by default" %>
<%= f.text_field :comment_threshold, :size => 2 %>
</p>
<p>
<%= f.label :always_resize_images %>
<%= f.label :always_resize_images, nil, :title => "Enable to automatically resize images to fit your browser window" %>
<%= f.check_box :always_resize_images %>
</p>
<p>
<%= f.label :default_image_size %>
<%= f.label :default_image_size, nil, :title => "Medium shows images resized to #{Danbooru.config.medium_image_width} pixels wide, large is #{Danbooru.config.large_image_width} pixels wide, and original is whatever the original image is" %>
<%= f.select :default_image_size, %w(Medium Large Original) %>
</p>
<p>
<%= f.label :favorite_tags %>
<%= f.label :favorite_tags, nil, :title => "A list of whitespace delimited tags that show up in your profile" %>
<%= f.text_area :favorite_tags, :rows => 5 %>
</p>
<p>
<%= f.label :blacklisted_tags %>
<%= f.label :blacklisted_tags, nil, :title => "A list of newline delimited tags that you never want to see" %>
<%= f.text_area :blacklisted_tags, :rows => 5 %>
</p>
</fieldset>
@@ -43,17 +49,17 @@
<p>For security purposes, changing the following settings requires you to re-enter your password. You can leave the new password field blank to keep your current one.</p>
<p>
<%= f.label :name %>
<%= f.label :name, nil, :title => "Your login name" %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :password, "New password" %>
<%= f.label :password, "New password", :title => "What you want your new password to be (leave blank if you don't want to change your password)" %>
<%= f.text_field :password %>
</p>
<p>
<%= f.label :old_password %>
<%= f.label :old_password, nil, :title => "Your old password (you must enter your password if updating your name or password)" %>
<%= f.text_field :old_password %>
</p>
</fieldset>
@@ -62,9 +68,5 @@
<% end %>
<% content_for(:page_title) do %>
/<%= @user.name %>/Settings
<% end %>
<% content_for(:page_header) do %>
/ <%= @user.name %> / Settings
/ Users / <%= @user.name %> / Settings
<% end %>

View File

@@ -6,9 +6,5 @@
</nav>
<% content_for(:page_title) do %>
users/<%= @user.name %>
<% end %>
<% content_for(:page_header) do %>
/ <%= @user.name %>
/ Users / <%= @user.name %>
<% end %>

View File

@@ -41,6 +41,7 @@ Danbooru::Application.routes.draw do |map|
resources :tag_implications
resources :tag_subscriptions
resources :unapprovals
resources :uploads
resources :users
resources :user_feedback
resources :wiki_pages do

View File

@@ -770,7 +770,6 @@ CREATE TABLE janitor_trials (
id integer NOT NULL,
user_id integer NOT NULL,
promoted_at timestamp without time zone,
original_level integer NOT NULL,
created_at timestamp without time zone,
updated_at timestamp without time zone
);
@@ -1411,6 +1410,7 @@ CREATE TABLE users (
is_janitor boolean DEFAULT false NOT NULL,
is_moderator boolean DEFAULT false NOT NULL,
is_admin boolean DEFAULT false NOT NULL,
base_upload_limit integer DEFAULT 10 NOT NULL,
last_logged_in_at timestamp without time zone,
last_forum_read_at timestamp without time zone,
has_mail boolean DEFAULT false NOT NULL,

View File

@@ -14,6 +14,7 @@ class CreateUsers < ActiveRecord::Migration
t.column :is_janitor, :boolean, :null => false, :default => false
t.column :is_moderator, :boolean, :null => false, :default => false
t.column :is_admin, :boolean, :null => false, :default => false
t.column :base_upload_limit, :integer, :null => false, :default => 10
# Cached data
t.column :last_logged_in_at, :datetime

View File

@@ -3,7 +3,6 @@ class CreateJanitorTrials < ActiveRecord::Migration
create_table :janitor_trials do |t|
t.column :user_id, :integer, :null => false
t.column :promoted_at, :datetime
t.column :original_level, :integer, :null => false
t.timestamps
end

View File

@@ -0,0 +1,13 @@
$(document).ready(function() {
var img = $("#image-preview img");
if (img) {
var height = img.attr("height");
var width = img.attr("width");
if (height > 400) {
var ratio = 400.0 / height;
img.attr("height", height * ratio);
img.attr("width", width * ratio);
$("#scale").val("Scaled " + parseInt(100 * ratio) + "%");
}
}
});

View File

@@ -0,0 +1,4 @@
Factory.define(:comment_vote) do |f|
f.comment {|x| x.association(:comment)}
f.user {|x| x.association(:user)}
end

View File

@@ -1,8 +1,10 @@
Factory.define(:user) do |f|
f.name {Faker::Name.first_name}
f.password "password"
f.password_hash {User.sha1("password")}
f.email {Faker::Internet.email}
f.default_image_size "medium"
f.base_upload_limit 10
end
Factory.define(:banned_user, :parent => :user) do |f|

View File

@@ -1,4 +1,5 @@
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
require 'shoulda'
require 'factory_girl'
require 'mocha'

View File

@@ -6,6 +6,45 @@ class UserTest < ActiveSupport::TestCase
MEMCACHE.flush_all
end
should "limit post uploads" do
user = Factory.create(:user)
assert(!user.can_upload?)
user.update_attribute(:is_contributor, true)
assert(user.can_upload?)
user.update_attribute(:is_contributor, false)
40.times do
Factory.create(:post, :uploader => user, :is_deleted => true)
end
assert(!user.can_upload?)
end
should "limit comment votes" do
user = Factory.create(:user)
assert(user.can_comment_vote?)
12.times do
Factory.create(:comment_vote, :user => user)
end
assert(!user.can_comment_vote?)
CommentVote.update_all("created_at = '1990-01-01'")
assert(user.can_comment_vote?)
end
should "limit comments" do
user = Factory.create(:user)
assert(!user.can_comment?)
user.update_attribute(:is_privileged, true)
assert(user.can_comment?)
user.update_attribute(:is_privileged, false)
user.update_attribute(:created_at, 1.year.ago)
assert(user.can_comment?)
(Danbooru.config.member_comment_limit + 1).times do
Factory.create(:comment, :creator => user)
end
assert(!user.can_comment?)
end
should "verify" do
user = Factory.create(:user)
assert(user.is_verified?)
@@ -17,7 +56,7 @@ class UserTest < ActiveSupport::TestCase
assert_nothing_raised {user.verify!(user.email_verification_key)}
assert(user.is_verified?)
end
should "authenticate" do
@user = Factory.create(:user)
assert(User.authenticate(@user.name, "password"), "Authentication should have succeeded")
@@ -25,42 +64,42 @@ class UserTest < ActiveSupport::TestCase
assert(User.authenticate_hash(@user.name, @user.password_hash), "Authentication should have succeeded")
assert(!User.authenticate_hash(@user.name, "xxxx"), "Authentication should not have succeeded")
end
should "normalize its level" do
user = Factory.create(:user, :is_admin => true)
assert(user.is_moderator?)
assert(user.is_janitor?)
assert(user.is_contributor?)
assert(user.is_privileged?)
user = Factory.create(:user, :is_moderator => true)
assert(!user.is_admin?)
assert(user.is_moderator?)
assert(user.is_janitor?)
assert(!user.is_contributor?)
assert(user.is_privileged?)
user = Factory.create(:user, :is_janitor => true)
assert(!user.is_admin?)
assert(!user.is_moderator?)
assert(user.is_janitor?)
assert(!user.is_contributor?)
assert(user.is_privileged?)
user = Factory.create(:user, :is_contributor => true)
assert(!user.is_admin?)
assert(!user.is_moderator?)
assert(!user.is_janitor?)
assert(user.is_contributor?)
assert(user.is_privileged?)
user = Factory.create(:user, :is_privileged => true)
assert(!user.is_admin?)
assert(!user.is_moderator?)
assert(!user.is_janitor?)
assert(!user.is_contributor?)
assert(user.is_privileged?)
user = Factory.create(:user)
assert(!user.is_admin?)
assert(!user.is_moderator?)
@@ -68,24 +107,24 @@ class UserTest < ActiveSupport::TestCase
assert(!user.is_contributor?)
assert(!user.is_privileged?)
end
context "name" do
should "be #{Danbooru.config.default_guest_name} given an invalid user id" do
assert_equal(Danbooru.config.default_guest_name, User.find_name(-1))
end
should "be fetched given a user id" do
@user = Factory.create(:user)
assert_equal(@user.name, User.find_name(@user.id))
end
should "be updated" do
@user = Factory.create(:user)
@user.update_attribute(:name, "danzig")
assert_equal("danzig", User.find_name(@user.id))
end
end
context "password" do
should "match the confirmation" do
@user = Factory.create(:user)
@@ -95,7 +134,7 @@ class UserTest < ActiveSupport::TestCase
@user.reload
assert(User.authenticate(@user.name, "zugzug5"), "Authentication should have succeeded")
end
should "match the confirmation" do
@user = Factory.create(:user)
@user.password = "zugzug6"
@@ -103,7 +142,7 @@ class UserTest < ActiveSupport::TestCase
@user.save
assert_equal(["Password doesn't match confirmation"], @user.errors.full_messages)
end
should "not be too short" do
@user = Factory.create(:user)
@user.password = "x5"
@@ -111,7 +150,7 @@ class UserTest < ActiveSupport::TestCase
@user.save
assert_equal(["Password is too short (minimum is 5 characters)"], @user.errors.full_messages)
end
should "should be reset" do
@user = Factory.create(:user)
new_pass = @user.reset_password