diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 4657e514e..59d73a5cf 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -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 diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2c14318c4..2acd1302e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -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 - - (%{
  • } + link_to(text, url, html_options) + "
  • ").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] - - %{ - - - #{title} - - - } - end end diff --git a/app/models/user.rb b/app/models/user.rb index 55c1ebda8..20fded626 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -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" diff --git a/app/views/layouts/default.html.erb b/app/views/layouts/default.html.erb index 165b18ea3..044f7b859 100644 --- a/app/views/layouts/default.html.erb +++ b/app/views/layouts/default.html.erb @@ -1,7 +1,7 @@ - <%= yield(:page_title) || Danbooru.config.app_name %> + <%= yield(:page_title) %> <%= csrf_meta_tag %> @@ -17,7 +17,7 @@ <% content_for(:page_title) do %> - users/<%= @user.name %> -<% end %> - -<% content_for(:page_header) do %> - / <%= @user.name %> + / Users / <%= @user.name %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index cb853117b..e674aa750 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/db/development_structure.sql b/db/development_structure.sql index 8c9f2ddf6..62b939e0a 100644 --- a/db/development_structure.sql +++ b/db/development_structure.sql @@ -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, diff --git a/db/migrate/20100204211522_create_users.rb b/db/migrate/20100204211522_create_users.rb index 8aada9595..02a828ece 100644 --- a/db/migrate/20100204211522_create_users.rb +++ b/db/migrate/20100204211522_create_users.rb @@ -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 diff --git a/db/migrate/20100309211553_create_janitor_trials.rb b/db/migrate/20100309211553_create_janitor_trials.rb index 455bf489f..ebff7352d 100644 --- a/db/migrate/20100309211553_create_janitor_trials.rb +++ b/db/migrate/20100309211553_create_janitor_trials.rb @@ -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 diff --git a/public/javascripts/src/uploads/new.js b/public/javascripts/src/uploads/new.js new file mode 100644 index 000000000..fd10373fb --- /dev/null +++ b/public/javascripts/src/uploads/new.js @@ -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) + "%"); + } + } +}); diff --git a/test/factories/comment_vote.rb b/test/factories/comment_vote.rb new file mode 100644 index 000000000..3f9cb1e13 --- /dev/null +++ b/test/factories/comment_vote.rb @@ -0,0 +1,4 @@ +Factory.define(:comment_vote) do |f| + f.comment {|x| x.association(:comment)} + f.user {|x| x.association(:user)} +end diff --git a/test/factories/user.rb b/test/factories/user.rb index 3ac8203bd..f78efdde2 100644 --- a/test/factories/user.rb +++ b/test/factories/user.rb @@ -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| diff --git a/test/test_helper.rb b/test/test_helper.rb index 9f005dd36..8b31aabb3 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,4 +1,5 @@ require File.expand_path(File.dirname(__FILE__) + "/../config/environment") + require 'shoulda' require 'factory_girl' require 'mocha' diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index b0adb578f..e085ef274 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -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