diff --git a/Gemfile b/Gemfile index 48c3c5269..55086cc65 100644 --- a/Gemfile +++ b/Gemfile @@ -59,6 +59,7 @@ gem 'google-api-client' gem 'cityhash' gem 'bigquery', :git => "https://github.com/abronte/BigQuery.git", :ref => "b92b4e0b54574e3fde7ad910f39a67538ed387ad" gem 'memcache_mock' +gem 'memoist' # needed for looser jpeg header compat gem 'ruby-imagespec', :require => "image_spec", :git => "https://github.com/r888888888/ruby-imagespec.git", :branch => "exif-fixes" diff --git a/Gemfile.lock b/Gemfile.lock index 53b147376..c53f268dc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -405,6 +405,7 @@ DEPENDENCIES mechanize memcache-client memcache_mock + memoist mocha net-sftp net-ssh diff --git a/app/assets/stylesheets/specific/forum.css.scss b/app/assets/stylesheets/specific/forum.css.scss index f9a741458..e81ea4f87 100644 --- a/app/assets/stylesheets/specific/forum.css.scss +++ b/app/assets/stylesheets/specific/forum.css.scss @@ -9,6 +9,10 @@ div.list-of-forum-posts { margin-bottom: 3em; word-wrap: break-word; + &:target { + background-color: #FFC; + } + div.author { width: 12em; float: left; diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index f917eb6b1..748c8fad9 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -1,7 +1,6 @@ module Admin class UsersController < ApplicationController before_filter :moderator_only - rescue_from User::PrivilegeError, :with => :access_denied def edit @user = User.find(params[:id]) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 96933d631..86a97ddb9 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,7 +1,6 @@ class CommentsController < ApplicationController respond_to :html, :xml, :json before_filter :member_only, :except => [:index, :search, :show] - rescue_from ActiveRecord::StatementInvalid, :with => :rescue_exception skip_before_filter :api_check def index diff --git a/app/controllers/dmails_controller.rb b/app/controllers/dmails_controller.rb index 97e19a1d7..8c01895e3 100644 --- a/app/controllers/dmails_controller.rb +++ b/app/controllers/dmails_controller.rb @@ -1,7 +1,6 @@ class DmailsController < ApplicationController respond_to :html, :xml, :json before_filter :member_only - rescue_from User::PrivilegeError, :with => :access_denied def new if params[:respond_to_id] diff --git a/app/controllers/legacy_controller.rb b/app/controllers/legacy_controller.rb index f2204f345..385080220 100644 --- a/app/controllers/legacy_controller.rb +++ b/app/controllers/legacy_controller.rb @@ -1,6 +1,5 @@ class LegacyController < ApplicationController before_filter :member_only, :only => [:create_post] - rescue_from PostSets::SearchError, :with => :rescue_exception def posts @post_set = PostSets::Post.new(tag_query, params[:page], params[:limit], format: "json") diff --git a/app/controllers/maintenance/user/deletions_controller.rb b/app/controllers/maintenance/user/deletions_controller.rb index 2022595b2..a8254da37 100644 --- a/app/controllers/maintenance/user/deletions_controller.rb +++ b/app/controllers/maintenance/user/deletions_controller.rb @@ -1,8 +1,6 @@ module Maintenance module User class DeletionsController < ApplicationController - rescue_from UserDeletion::ValidationError, :with => :rescue_exception - def show end diff --git a/app/controllers/moderator/post/posts_controller.rb b/app/controllers/moderator/post/posts_controller.rb index 38e29cd76..94ceb1166 100644 --- a/app/controllers/moderator/post/posts_controller.rb +++ b/app/controllers/moderator/post/posts_controller.rb @@ -3,7 +3,6 @@ module Moderator class PostsController < ApplicationController before_filter :approver_only, :only => [:delete, :undelete, :move_favorites, :ban, :unban, :confirm_delete, :confirm_move_favorites, :confirm_ban] before_filter :admin_only, :only => [:expunge] - rescue_from ::PostFlag::Error, ::Post::ApprovalError, :with => :rescue_exception skip_before_filter :api_check def confirm_delete diff --git a/app/controllers/moderator/post/queues_controller.rb b/app/controllers/moderator/post/queues_controller.rb index 06b80dd18..e274c19fb 100644 --- a/app/controllers/moderator/post/queues_controller.rb +++ b/app/controllers/moderator/post/queues_controller.rb @@ -15,7 +15,7 @@ module Moderator end ::Post.without_timeout do - @posts = ::Post.order("posts.id asc").pending_or_flagged.available_for_moderation(params[:hidden]).tag_match(params[:query]).paginate(params[:page], :limit => per_page) + @posts = ::Post.includes(:disapprovals, :uploader).order("posts.id asc").pending_or_flagged.available_for_moderation(params[:hidden]).tag_match(params[:query]).paginate(params[:page], :limit => per_page) @posts.each # hack to force rails to eager load end respond_with(@posts) @@ -25,7 +25,7 @@ module Moderator cookies.permanent[:moderated] = Time.now.to_i ::Post.without_timeout do - @posts = ::Post.order("posts.id asc").pending_or_flagged.available_for_moderation(false).reorder("random()").limit(RANDOM_COUNT) + @posts = ::Post.includes(:disapprovals, :uploader).order("posts.id asc").pending_or_flagged.available_for_moderation(false).reorder("random()").limit(RANDOM_COUNT) @posts.each # hack to force rails to eager load if @posts.empty? diff --git a/app/controllers/post_versions_controller.rb b/app/controllers/post_versions_controller.rb index af484f500..2427b9074 100644 --- a/app/controllers/post_versions_controller.rb +++ b/app/controllers/post_versions_controller.rb @@ -1,9 +1,8 @@ class PostVersionsController < ApplicationController respond_to :html, :xml, :json - rescue_from ActiveRecord::StatementInvalid, :with => :rescue_exception def index - @post_versions = PostVersion.search(params[:search]).order("updated_at desc, id desc").paginate(params[:page], :limit => params[:limit], :search_count => params[:search]) + @post_versions = PostArchive.search(params[:search]).order("updated_at desc, id desc").paginate(params[:page], :limit => params[:limit], :search_count => params[:search]) respond_with(@post_versions) do |format| format.xml do render :xml => @post_versions.to_xml(:root => "post-versions") @@ -15,7 +14,7 @@ class PostVersionsController < ApplicationController end def undo - @post_version = PostVersion.find(params[:id]) + @post_version = PostArchive.find(params[:id]) if @post_version.post.visible? @post_version.undo! diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 0ddecd2f0..8708a6adf 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -3,10 +3,6 @@ class PostsController < ApplicationController before_filter :builder_only, :only => [:copy_notes] before_filter :enable_cors, :only => [:index, :show] respond_to :html, :xml, :json - rescue_from PostSets::SearchError, :with => :rescue_exception - rescue_from Post::SearchError, :with => :rescue_exception - rescue_from ActiveRecord::StatementInvalid, :with => :rescue_exception - rescue_from ActiveRecord::RecordNotFound, :with => :rescue_exception def index if params[:md5].present? diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 560750ca2..9a353aad9 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -1,7 +1,6 @@ class UploadsController < ApplicationController before_filter :member_only respond_to :html, :xml, :json, :js - rescue_from Upload::Error, :with => :rescue_exception def new @upload = Upload.new diff --git a/app/controllers/user_name_change_requests_controller.rb b/app/controllers/user_name_change_requests_controller.rb index 5cbed2686..7c5c79378 100644 --- a/app/controllers/user_name_change_requests_controller.rb +++ b/app/controllers/user_name_change_requests_controller.rb @@ -2,7 +2,6 @@ class UserNameChangeRequestsController < ApplicationController before_filter :member_only, :only => [:index, :show] before_filter :gold_only, :only => [:new, :create] before_filter :admin_only, :only => [:approve, :reject] - rescue_from User::PrivilegeError, :with => :access_denied respond_to :html, :json, :xml def new diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index b446f8cd2..9cda71582 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,7 +1,6 @@ class UsersController < ApplicationController respond_to :html, :xml, :json before_filter :member_only, :only => [:edit, :update, :upgrade] - rescue_from User::PrivilegeError, :with => :access_denied skip_before_filter :api_check def new diff --git a/app/controllers/wiki_pages_controller.rb b/app/controllers/wiki_pages_controller.rb index 9dd22b3f3..96b92d4ad 100644 --- a/app/controllers/wiki_pages_controller.rb +++ b/app/controllers/wiki_pages_controller.rb @@ -3,8 +3,6 @@ class WikiPagesController < ApplicationController before_filter :member_only, :except => [:index, :show, :show_or_new] before_filter :builder_only, :only => [:destroy] before_filter :normalize_search_params, :only => [:index] - rescue_from ActiveRecord::StatementInvalid, :with => :rescue_exception - rescue_from ActiveRecord::RecordNotFound, :with => :rescue_exception def new @wiki_page = WikiPage.new(params[:wiki_page]) diff --git a/app/logical/approver_pruner.rb b/app/logical/approver_pruner.rb index 8d9300bfc..bba3ffbf1 100644 --- a/app/logical/approver_pruner.rb +++ b/app/logical/approver_pruner.rb @@ -25,7 +25,7 @@ class ApproverPruner Dmail.create_automated( :to_id => user.id, :title => "Approver inactivity", - :body => "You haven't approved a post in the past three months. In order to make sure the list of active approvers is up-to-date, you have lost your approver privileges. Please reply to this message if you want to be reinstated." + :body => "You haven't approved a post in the past three months. In order to make sure the list of active approvers is up-to-date, you have lost your approver privileges." ) end end diff --git a/app/logical/bulk_revert.rb b/app/logical/bulk_revert.rb index e95ea806a..b5929ab2c 100644 --- a/app/logical/bulk_revert.rb +++ b/app/logical/bulk_revert.rb @@ -27,7 +27,7 @@ class BulkRevert end def find_post_versions - q = PostVersion.where("true") + q = PostArchive.where("true") if constraints[:user_name] constraints[:user_id] = User.find_by_name(constraints[:user_name]).try(:id) diff --git a/app/logical/moderator/ip_addr_search.rb b/app/logical/moderator/ip_addr_search.rb index eccbf11ab..c47216c04 100644 --- a/app/logical/moderator/ip_addr_search.rb +++ b/app/logical/moderator/ip_addr_search.rb @@ -34,7 +34,7 @@ module Moderator add_row(sums, Hash[User.where(last_ip_addr: ip_addrs).collect { |user| [user, 1] }]) add_row_id(sums, PoolArchive.where(updater_ip_addr: ip_addrs).group(:updater_id).count) if PoolArchive.enabled? - add_row_id(sums, PostVersion.where(updater_ip_addr: ip_addrs).group(:updater_id).count) + add_row_id(sums, PostArchive.where(updater_ip_addr: ip_addrs).group(:updater_id).count) if PostArchive.enabled? sums end @@ -52,7 +52,7 @@ module Moderator add_row(sums, ArtistVersion.where(updater: users).group(:updater_ip_addr).count) add_row(sums, NoteVersion.where(updater: users).group(:updater_ip_addr).count) add_row(sums, PoolArchive.where(updater_id: users.map(&:id)).group(:updater_ip_addr).count) if PoolArchive.enabled? - add_row(sums, PostVersion.where(updater_id: users.map(&:id)).group(:updater_ip_addr).count) + add_row(sums, PostArchive.where(updater_id: users.map(&:id)).group(:updater_ip_addr).count) if PostArchive.enabled? add_row(sums, WikiPageVersion.where(updater: users).group(:updater_ip_addr).count) add_row(sums, Comment.where(creator: users).group(:ip_addr).count) add_row(sums, Dmail.where(from: users).group(:creator_ip_addr).count) diff --git a/app/logical/reports/post_versions.rb b/app/logical/reports/post_versions.rb index 9c4da0bd4..5e58c66a0 100644 --- a/app/logical/reports/post_versions.rb +++ b/app/logical/reports/post_versions.rb @@ -13,7 +13,7 @@ module Reports end def mock_version(row) - PostVersion.new.tap do |x| + PostArchive.new.tap do |x| x.id = row["f"][0]["v"] x.post_id = row["f"][1]["v"] x.updated_at = Time.at(row["f"][2]["v"].to_f) diff --git a/app/logical/user_name_validator.rb b/app/logical/user_name_validator.rb new file mode 100644 index 000000000..c86c693db --- /dev/null +++ b/app/logical/user_name_validator.rb @@ -0,0 +1,10 @@ +class UserNameValidator < ActiveModel::EachValidator + def validate_each(rec, attr, value) + name = User.normalize_name(value) + + rec.errors[attr] << "already exists" if User.find_by_name(name).present? + rec.errors[attr] << "must be 2 to 100 characters long" if !name.length.between?(2, 100) + rec.errors[attr] << "cannot have whitespace or colons" if name =~ /[[:space:]]|:/ + rec.errors[attr] << "cannot begin or end with an underscore" if name =~ /\A_|_\z/ + end +end diff --git a/app/logical/user_revert.rb b/app/logical/user_revert.rb index d97f25fae..ba104d691 100644 --- a/app/logical/user_revert.rb +++ b/app/logical/user_revert.rb @@ -15,13 +15,13 @@ class UserRevert end def validate! - if PostVersion.where(updater_id: user_id).count > THRESHOLD + if PostArchive.where(updater_id: user_id).count > THRESHOLD raise TooManyChangesError.new("This user has too many changes to be reverted") end end def revert_post_changes - PostVersion.where(updater_id: user_id).find_each do |x| + PostArchive.where(updater_id: user_id).find_each do |x| x.undo! end end diff --git a/app/models/amazon_backup.rb b/app/models/amazon_backup.rb index 44f16921b..d7835fe70 100644 --- a/app/models/amazon_backup.rb +++ b/app/models/amazon_backup.rb @@ -12,6 +12,112 @@ class AmazonBackup < ActiveRecord::Base first.update_column(:last_id, new_id) end + def self.restore_from_glacier(min_id, max_id) + credentials = Aws::Credentials.new(Danbooru.config.aws_access_key_id, Danbooru.config.aws_secret_access_key) + Aws.config.update({ + region: "us-east-1", + credentials: credentials + }) + client = Aws::S3::Client.new + bucket = Danbooru.config.aws_s3_bucket_name + + f = lambda do |key| + begin + client.restore_object( + bucket: bucket, + key: key, + restore_request: { + days: 7, + glacier_job_parameters: { + tier: "Bulk" + } + } + ) + rescue Aws::S3::Errors::InternalError + puts " internal error...retrying" + sleep 30 + retry + rescue Aws::S3::Errors::InvalidObjectState + puts " already restored #{key}" + rescue Aws::S3::Errors::NoSuchKey + puts " missing #{key}" + file_path = "/var/www/danbooru2/shared/data/#{key}" + + if File.exists?(file_path) + base64_md5 = Digest::MD5.base64digest(File.read(file_path)) + body = open(file_path, "rb") + client.put_object(bucket: bucket, key: key, body: body, content_md5: base64_md5, acl: "public-read") + puts " uploaded" + end + rescue Aws::S3::Errors::RestoreAlreadyInProgress + puts " already restoring #{key}" + end + end + + Post.where("id >= ? and id <= ?", min_id, max_id).find_each do |post| + if post.has_large? + puts "large:#{post.id}" + key = "sample/" + File.basename(post.large_file_path) + f.call(key) + end + + if post.has_preview? + puts "preview:#{post.id}" + key = "preview/" + File.basename(post.preview_file_path) + f.call(key) + end + + puts "#{post.id}" + key = File.basename(post.file_path) + f.call(key) + end + end + + def self.copy_to_standard(min_id, max_id) + credentials = Aws::Credentials.new(Danbooru.config.aws_access_key_id, Danbooru.config.aws_secret_access_key) + Aws.config.update({ + region: "us-east-1", + credentials: credentials + }) + client = Aws::S3::Client.new + bucket = Danbooru.config.aws_s3_bucket_name + + f = lambda do |key| + begin + client.copy_object(bucket: bucket, key: key, acl: "public-read", storage_class: "STANDARD", copy_source: "/#{bucket}/#{key}", metadata_directive: "COPY") + puts " copied #{key}" + rescue Aws::S3::Errors::InternalError + puts " internal error...retrying" + sleep 30 + retry + rescue Aws::S3::Errors::InvalidObjectState + puts " invalid state #{key}" + rescue Aws::S3::Errors::NoSuchKey + puts " missing #{key}" + end + end + + Post.where("id >= ? and id <= ?", min_id, max_id).find_each do |post| + next unless post.has_preview? + + if post.has_preview? + puts "preview:#{post.id}" + key = "preview/" + File.basename(post.preview_file_path) + f.call(key) + end + + if post.has_large? + puts "large:#{post.id}" + key = "sample/" + File.basename(post.large_file_path) + f.call(key) + end + + puts "#{post.id}" + key = File.basename(post.file_path) + f.call(key) + end + end + def self.execute return false unless Danbooru.config.aws_s3_enabled? diff --git a/app/models/comment.rb b/app/models/comment.rb index 95a4494b1..b4652eb7c 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -14,8 +14,8 @@ class Comment < ActiveRecord::Base after_update(:if => lambda {|rec| CurrentUser.id != rec.creator_id}) do |rec| ModAction.log("comment ##{rec.id} updated by #{CurrentUser.name}") end - after_destroy :update_last_commented_at_on_destroy - after_destroy(:if => lambda {|rec| CurrentUser.id != rec.creator_id}) do |rec| + after_update :update_last_commented_at_on_destroy, :if => lambda {|rec| rec.is_deleted? && rec.is_deleted_changed?} + after_update(:if => lambda {|rec| rec.is_deleted? && rec.is_deleted_changed? && CurrentUser.id != rec.creator_id}) do |rec| ModAction.log("comment ##{rec.id} deleted by #{CurrentUser.name}") end attr_accessible :body, :post_id, :do_not_bump_post, :is_deleted, :as => [:member, :gold, :platinum, :builder, :janitor, :moderator, :admin] diff --git a/app/models/forum_topic.rb b/app/models/forum_topic.rb index d19a90c06..55df3e8fe 100644 --- a/app/models/forum_topic.rb +++ b/app/models/forum_topic.rb @@ -154,6 +154,10 @@ class ForumTopic < ActiveRecord::Base self.updater_id = CurrentUser.id end + def page_for(post_id) + (posts.where("id < ?", post_id).count / Danbooru.config.posts_per_page.to_f).ceil + end + def last_page (response_count / Danbooru.config.posts_per_page.to_f).ceil end diff --git a/app/models/janitor_trial.rb b/app/models/janitor_trial.rb index d7e1a55cb..6e07fb650 100644 --- a/app/models/janitor_trial.rb +++ b/app/models/janitor_trial.rb @@ -71,7 +71,7 @@ class JanitorTrial < ActiveRecord::Base end def send_dmail - body = "You have been selected as a test janitor. You can now approve pending posts and have access to the moderation interface. You should reacquaint yourself with the [[howto:upload]] guide to make sure you understand the site rules.\n\nOver the next several weeks your approvals will be monitored. If the majority of them are not quality uploads you will fail the trial period and lose your approval privileges. You will also receive a negative user record indicating you previously attempted and failed a test janitor trial.\n\nThere is a minimum quota of 1 approval a month to indicate that you are being active. Remember, the goal isn't to approve as much as possible. It's to filter out borderline-quality art.\n\nIf you have any questions please respond to this message." + body = "You have been selected as a test janitor. You can now approve pending posts and have access to the moderation interface. You should reacquaint yourself with the [[howto:upload]] guide to make sure you understand the site rules.\n\nOver the next several weeks your approvals will be monitored. If the majority of them are not quality uploads you will fail the trial period and lose your approval privileges. You will also receive a negative user record indicating you previously attempted and failed a test janitor trial.\n\nThere is a minimum quota of 1 approval a month to indicate that you are being active. Remember, the goal isn't to approve as much as possible. It's to filter out borderline-quality art." Dmail.create_automated(:title => "Test Janitor Trial Period", :body => body, :to_id => user_id) end diff --git a/app/models/post.rb b/app/models/post.rb index 059527a73..77237f812 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -42,7 +42,6 @@ class Post < ActiveRecord::Base has_one :pixiv_ugoira_frame_data, :class_name => "PixivUgoiraFrameData", :dependent => :destroy has_many :flags, :class_name => "PostFlag", :dependent => :destroy has_many :appeals, :class_name => "PostAppeal", :dependent => :destroy - has_many :versions, lambda {order("post_versions.updated_at ASC, post_versions.id ASC")}, :class_name => "PostVersion", :dependent => :destroy has_many :votes, :class_name => "PostVote", :dependent => :destroy has_many :notes, :dependent => :destroy has_many :comments, lambda {includes(:creator, :updater).order("comments.id")}, :dependent => :destroy @@ -1414,12 +1413,16 @@ class Post < ActiveRecord::Base end module VersionMethods + def versions + if PostArchive.enabled? + PostArchive.where(post_id: id).order("updated_at ASC, id asc") + else + raise "Archive service not configured" + end + end + def create_version(force = false) if new_record? || rating_changed? || source_changed? || parent_id_changed? || tag_string_changed? || force - if merge_version? - delete_previous_version - end - create_new_version end end @@ -1431,19 +1434,7 @@ class Post < ActiveRecord::Base def create_new_version User.where(id: CurrentUser.id).update_all("post_update_count = post_update_count + 1") - CurrentUser.reload - - versions.create( - :rating => rating, - :source => source, - :tags => tag_string, - :parent_id => parent_id - ) - end - - def delete_previous_version - prev = versions.last - prev.destroy + PostArchive.queue(self) if PostArchive.enabled? end def revert_to(target) diff --git a/app/models/post_archive.rb b/app/models/post_archive.rb index 1cc456331..77fe48047 100644 --- a/app/models/post_archive.rb +++ b/app/models/post_archive.rb @@ -1,4 +1,6 @@ class PostArchive < ActiveRecord::Base + extend Memoist + def self.enabled? Danbooru.config.aws_sqs_archives_url.present? end @@ -6,49 +8,285 @@ class PostArchive < ActiveRecord::Base establish_connection (ENV["ARCHIVE_DATABASE_URL"] || "archive_#{Rails.env}".to_sym) if enabled? self.table_name = "post_versions" - def self.calculate_version(post_id, updated_at, version_id) - if updated_at.to_i == Time.zone.parse("2007-03-14T19:38:12Z").to_i - # Old post versions which didn't have updated_at set correctly - 1 + PostVersion.where("post_id = ? and updated_at = ? and id < ?", post_id, updated_at, version_id).count - else - 1 + PostVersion.where("post_id = ? and updated_at < ?", post_id, updated_at).count - end - end - - def self.export(version_id = 9096768) - PostVersion.where("id > ?", version_id).find_each do |version| - previous = version.previous - tags = version.tags.scan(/\S+/) - - if previous - prev_tags = previous.tags.scan(/\S+/) - added_tags = tags - previous.tags.scan(/\S+/) - removed_tags = previous.tags.scan(/\S+/) - tags + module SearchMethods + def for_user(user_id) + if user_id + where("updater_id = ?", user_id) else - added_tags = tags - removed_tags = [] + where("false") + end + end + + def for_user_name(name) + user_id = User.name_to_id(name) + for_user(user_id) + end + + def search(params) + q = where("true") + params = {} if params.blank? + + if params[:updater_name].present? + q = q.for_user_name(params[:updater_name]) end - rating_changed = previous.nil? || version.rating != previous.try(:rating) - parent_changed = previous.nil? || version.parent_id != previous.try(:parent_id) - source_changed = previous.nil? || version.source != previous.try(:source) - create( - post_id: version.post_id, - tags: version.tags, - added_tags: added_tags, - removed_tags: removed_tags, - updater_id: version.updater_id, - updater_ip_addr: version.updater_ip_addr.to_s, - updated_at: version.updated_at, - version: calculate_version(version.post_id, version.updated_at, version.id), - rating: version.rating, - rating_changed: rating_changed, - parent_id: version.parent_id, - parent_changed: parent_changed, - source: version.source, - source_changed: source_changed - ) - puts "inserted #{version.id}" + if params[:updater_id].present? + q = q.where("updater_id = ?", params[:updater_id].to_i) + end + + if params[:post_id].present? + q = q.where("post_id = ?", params[:post_id].to_i) + end + + if params[:start_id].present? + q = q.where("id <= ?", params[:start_id].to_i) + end + + q end end + + module ArchiveServiceMethods + extend ActiveSupport::Concern + + class_methods do + def sqs_service + SqsService.new(Danbooru.config.aws_sqs_archives_url) + end + + def queue(post) + # queue updates to sqs so that if archives goes down for whatever reason it won't + # block post updates + raise "Archive service is not configured" if !enabled? + + json = { + "post_id" => post.id, + "rating" => post.rating, + "parent_id" => post.parent_id, + "source" => post.source, + "updater_id" => CurrentUser.id, + "updater_ip_addr" => CurrentUser.ip_addr.to_s, + "updated_at" => post.updated_at.try(:iso8601), + "created_at" => post.created_at.try(:iso8601), + "tags" => post.tag_string + } + msg = "add post version\n#{json.to_json}" + sqs_service.send_message(msg) + end + + def export_to_archives(version_id = 4394763) + PostVersion.where("id > ?", version_id).find_each do |version| + previous = version.previous + tags = version.tags.scan(/\S+/) + version_number = if version.updated_at.to_i == Time.zone.parse("2007-03-14T19:38:12Z").to_i + # Old post versions which didn't have updated_at set correctly + 1 + PostVersion.where("post_id = ? and updated_at = ? and id < ?", version.post_id, version.updated_at, version.id).count + else + 1 + PostVersion.where("post_id = ? and updated_at < ?", version.post_id, version.updated_at).count + end + + if previous + prev_tags = previous.tags.scan(/\S+/) + added_tags = tags - prev_tags + removed_tags = prev_tags - tags + else + added_tags = tags + removed_tags = [] + end + + rating_changed = previous.nil? || version.rating != previous.rating + parent_changed = previous.nil? || version.parent_id != previous.parent_id + source_changed = previous.nil? || version.source != previous.source + create( + post_id: version.post_id, + tags: version.tags, + added_tags: added_tags, + removed_tags: removed_tags, + updater_id: version.updater_id, + updater_ip_addr: version.updater_ip_addr.to_s, + updated_at: version.updated_at, + version: version_number, + rating: version.rating, + rating_changed: rating_changed, + parent_id: version.parent_id, + parent_changed: parent_changed, + source: version.source, + source_changed: source_changed + ) + puts "inserted #{version.id}" + end + end + end + end + + extend SearchMethods + include ArchiveServiceMethods + + def tag_array + tags.scan(/\S+/) + end + + def presenter + PostVersionPresenter.new(self) + end + + def reload + flush_cache + super + end + + def post + Post.where(id: post_id).first + end + + def previous + PostArchive.where("post_id = ? and version < ?", post_id, version).order("version desc").first + end + + def updater + User.find(updater_id) + end + + def diff(version = nil) + if post.nil? + latest_tags = tag_array + else + latest_tags = post.tag_array + latest_tags << "rating:#{post.rating}" if post.rating.present? + latest_tags << "parent:#{post.parent_id}" if post.parent_id.present? + latest_tags << "source:#{post.source}" if post.source.present? + end + + new_tags = tag_array + new_tags << "rating:#{rating}" if rating.present? + new_tags << "parent:#{parent_id}" if parent_id.present? + new_tags << "source:#{source}" if source.present? + + old_tags = version.present? ? version.tag_array : [] + if version.present? + old_tags << "rating:#{version.rating}" if version.rating.present? + old_tags << "parent:#{version.parent_id}" if version.parent_id.present? + old_tags << "source:#{version.source}" if version.source.present? + end + + added_tags = new_tags - old_tags + removed_tags = old_tags - new_tags + + return { + :added_tags => added_tags, + :removed_tags => removed_tags, + :obsolete_added_tags => added_tags - latest_tags, + :obsolete_removed_tags => removed_tags & latest_tags, + :unchanged_tags => new_tags & old_tags, + } + end + + def changes + delta = { + :added_tags => added_tags, + :removed_tags => removed_tags + } + + latest_tags = post.tag_array + latest_tags << "rating:#{post.rating}" if post.rating.present? + latest_tags << "parent:#{post.parent_id}" if post.parent_id.present? + latest_tags << "source:#{post.source}" if post.source.present? + + if parent_changed + delta[:added_tags] << "parent:#{parent_id}" + + if previous + delta[:removed_tags] << "parent:#{previous.parent_id}" + end + end + + if rating_changed + delta[:added_tags] << "rating:#{rating}" + + if previous + delta[:removed_tags] << "rating:#{previous.rating}" + end + end + + if source_changed + delta[:added_tags] << "source:#{source}" + + if previous + delta[:removed_tags] << "source:#{previous.source}" + end + end + + delta[:obsolete_added_tags] = delta[:added_tags] - latest_tags + delta[:obsolete_removed_tags] = delta[:removed_tags] & latest_tags + + if previous + delta[:unchanged_tags] = tag_array & previous.tag_array + else + delta[:unchanged_tags] = [] + end + + delta + end + + def added_tags_with_fields + changes[:added_tags].join(" ") + end + + def removed_tags_with_fields + changes[:removed_tags].join(" ") + end + + def obsolete_added_tags + changes[:obsolete_added_tags].join(" ") + end + + def obsolete_removed_tags + changes[:obsolete_removed_tags].join(" ") + end + + def unchanged_tags + changes[:unchanged_tags].join(" ") + end + + def truncated_source + source.gsub(/^http:\/\//, "").sub(/\/.+/, "") + end + + def undo + added = changes[:added_tags_with_fields] - changes[:obsolete_added_tags] + removed = changes[:removed_tags_with_fields] - changes[:obsolete_removed_tags] + + added.each do |tag| + if tag =~ /^source:/ + post.source = "" + elsif tag =~ /^parent:/ + post.parent_id = nil + else + escaped_tag = Regexp.escape(tag) + post.tag_string = post.tag_string.sub(/(?:\A| )#{escaped_tag}(?:\Z| )/, " ").strip + end + end + removed.each do |tag| + if tag =~ /^source:(.+)$/ + post.source = $1 + else + post.tag_string = "#{post.tag_string} #{tag}".strip + end + end + end + + def undo! + undo + post.save! + end + + def updater + User.find_by_id(updater_id) + end + + def method_attributes + super + [:obsolete_added_tags, :obsolete_removed_tags, :unchanged_tags, :updater_name] + end + + memoize :previous, :post, :tag_array, :changes, :added_tags_with_fields, :removed_tags_with_fields, :obsolete_removed_tags, :obsolete_added_tags, :unchanged_tags end diff --git a/app/models/post_version.rb b/app/models/post_version.rb index e3c1be962..2006da241 100644 --- a/app/models/post_version.rb +++ b/app/models/post_version.rb @@ -61,17 +61,6 @@ class PostVersion < ActiveRecord::Base super end - def sequence_for_post - versions = PostVersion.where(:post_id => post_id).order("updated_at desc, id desc") - diffs = [] - versions.each_index do |i| - if i < versions.size - 1 - diffs << versions[i].diff(versions[i + 1]) - end - end - return diffs - end - def diff(version) latest_tags = post.tag_array latest_tags << "rating:#{post.rating}" if post.rating.present? diff --git a/app/models/user.rb b/app/models/user.rb index 73a29581d..6c0ac9129 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -54,10 +54,8 @@ class User < ActiveRecord::Base attr_accessor :password, :old_password attr_accessible :dmail_filter_attributes, :enable_privacy_mode, :enable_post_navigation, :new_post_navigation_layout, :password, :old_password, :password_confirmation, :password_hash, :email, :last_logged_in_at, :last_forum_read_at, :has_mail, :receive_email_notifications, :comment_threshold, :always_resize_images, :favorite_tags, :blacklisted_tags, :name, :ip_addr, :time_zone, :default_image_size, :enable_sequential_post_navigation, :per_page, :hide_deleted_posts, :style_usernames, :enable_auto_complete, :custom_style, :show_deleted_children, :disable_categorized_saved_searches, :disable_tagged_filenames, :enable_recent_searches, :as => [:moderator, :janitor, :gold, :platinum, :member, :anonymous, :default, :builder, :admin] attr_accessible :level, :as => :admin - validates_length_of :name, :within => 2..100, :on => :create - validates_format_of :name, :with => /\A[^\s:]+\Z/, :on => :create, :message => "cannot have whitespace or colons" - validates_format_of :name, :with => /\A[^_].*[^_]\Z/, :on => :create, :message => "cannot begin or end with an underscore" - validates_uniqueness_of :name, :case_sensitive => false + + validates :name, user_name: true, on: :create validates_uniqueness_of :email, :case_sensitive => false, :if => lambda {|rec| rec.email.present? && rec.email_changed? } validates_length_of :password, :minimum => 5, :if => lambda {|rec| rec.new_record? || rec.password.present?} validates_inclusion_of :default_image_size, :in => %w(large original) @@ -153,6 +151,10 @@ class User < ActiveRecord::Base def id_to_pretty_name(user_id) id_to_name(user_id).gsub(/([^_])_+(?=[^_])/, "\\1 \\2") end + + def normalize_name(name) + name.to_s.mb_chars.downcase.strip.tr(" ", "_").to_s + end end def pretty_name diff --git a/app/models/user_name_change_request.rb b/app/models/user_name_change_request.rb index eaf8cd372..b7de494f9 100644 --- a/app/models/user_name_change_request.rb +++ b/app/models/user_name_change_request.rb @@ -3,11 +3,8 @@ class UserNameChangeRequest < ActiveRecord::Base validates_inclusion_of :status, :in => %w(pending approved rejected) belongs_to :user belongs_to :approver, :class_name => "User" - validate :uniqueness_of_desired_name validate :not_limited, :on => :create - validates_length_of :desired_name, :within => 2..100, :on => :create - validates_format_of :desired_name, :with => /\A[^\s:]+\Z/, :on => :create, :message => "cannot have whitespace or colons" - before_validation :normalize_name + validates :desired_name, user_name: true attr_accessible :status, :user_id, :original_name, :desired_name, :change_reason, :rejection_reason, :approver_id def self.pending @@ -40,8 +37,8 @@ class UserNameChangeRequest < ActiveRecord::Base status == "pending" end - def normalize_name - self.desired_name = desired_name.strip.gsub(/ /, "_") + def desired_name=(name) + super(User.normalize_name(name)) end def feedback @@ -71,15 +68,6 @@ class UserNameChangeRequest < ActiveRecord::Base return true end end - - def uniqueness_of_desired_name - if User.find_by_name(desired_name) - errors.add(:desired_name, "already exists") - return false - else - return true - end - end def hidden_attributes if CurrentUser.is_admin? || user == CurrentUser.user diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 1ef615a30..d31b7fb20 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -163,6 +163,7 @@ class WikiPage < ActiveRecord::Base :title => title, :body => body, :is_locked => is_locked, + :is_deleted => is_deleted, :other_names => other_names ) end diff --git a/app/models/wiki_page_version.rb b/app/models/wiki_page_version.rb index 5e580061d..f830eb87b 100644 --- a/app/models/wiki_page_version.rb +++ b/app/models/wiki_page_version.rb @@ -2,7 +2,7 @@ class WikiPageVersion < ActiveRecord::Base belongs_to :wiki_page belongs_to :updater, :class_name => "User" belongs_to :artist - attr_accessible :wiki_page_id, :title, :body, :is_locked, :updater_id, :updater_ip_addr, :version, :other_names + attr_accessible :wiki_page_id, :title, :body, :is_locked, :is_deleted, :updater_id, :updater_ip_addr, :version, :other_names delegate :visible?, :to => :wiki_page module SearchMethods diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb index adf3a1b9a..9cfa5e712 100644 --- a/app/presenters/post_presenter.rb +++ b/app/presenters/post_presenter.rb @@ -95,6 +95,10 @@ class PostPresenter < Presenter @post = post end + def tag_set_presenter + @tag_set_presenter ||= TagSetPresenter.new(@post.tag_array) + end + def preview_html PostPresenter.preview(@post) end @@ -170,13 +174,15 @@ class PostPresenter < Presenter end def tag_list_html(template, options = {}) - @tag_set_presenter ||= TagSetPresenter.new(@post.tag_array) - @tag_set_presenter.tag_list_html(template, options.merge(:show_extra_links => CurrentUser.user.is_gold?)) + tag_set_presenter.tag_list_html(template, options.merge(:show_extra_links => CurrentUser.user.is_gold?)) end def split_tag_list_html(template, options = {}) - @tag_set_presenter ||= TagSetPresenter.new(@post.tag_array) - @tag_set_presenter.split_tag_list_html(template, options.merge(:show_extra_links => CurrentUser.user.is_gold?)) + tag_set_presenter.split_tag_list_html(template, options.merge(:show_extra_links => CurrentUser.user.is_gold?)) + end + + def inline_tag_list_html(template) + tag_set_presenter.inline_tag_list(template) end def has_nav_links?(template) diff --git a/app/presenters/tag_set_presenter.rb b/app/presenters/tag_set_presenter.rb index 2321bc03f..a09d3e586 100644 --- a/app/presenters/tag_set_presenter.rb +++ b/app/presenters/tag_set_presenter.rb @@ -64,6 +64,17 @@ class TagSetPresenter < Presenter html.html_safe end + # compact (horizontal) list, as seen in the /comments index. + def inline_tag_list(template) + @tags.map do |tag_name| + <<-EOS + + #{template.link_to(tag_name.tr("_", " "), template.posts_path(tags: tag_name))} + + EOS + end.join.html_safe + end + private def general_tags @general_tags ||= categories.select {|k, v| v == Tag.categories.general} diff --git a/app/views/comments/partials/index/_header.html.erb b/app/views/comments/partials/index/_header.html.erb index 0e0e1ce02..1815dc23b 100644 --- a/app/views/comments/partials/index/_header.html.erb +++ b/app/views/comments/partials/index/_header.html.erb @@ -24,11 +24,7 @@
diff --git a/app/views/dmails/show.html.erb b/app/views/dmails/show.html.erb index ef0a43623..c5973b319 100644 --- a/app/views/dmails/show.html.erb +++ b/app/views/dmails/show.html.erb @@ -19,7 +19,7 @@ <% if @dmail.is_automated? %>- This is an automated message. Post in the forums if you have any questions. + This is an automated message. Responses will not be seen. If you have any questions either message a moderator or ask in the forum.
<% end %> diff --git a/app/views/moderator/post/queues/show.html.erb b/app/views/moderator/post/queues/show.html.erb index 1b9fe1aba..f23b1714b 100644 --- a/app/views/moderator/post/queues/show.html.erb +++ b/app/views/moderator/post/queues/show.html.erb @@ -60,7 +60,7 @@ Hidden: <%= render "post_disapprovals/compact_counts", :disapprovals => post.disapprovals, :post => post %>- It has been reviewed by <%= pluralize disapprovals.count, "moderator" %>. + It has been reviewed by <%= pluralize disapprovals.length, "moderator" %>. - <% if disapprovals.breaks_rules.count > 0 %> - <%= disapprovals.breaks_rules.count %> believe it breaks the rules. + <% if disapprovals.map(&:reason).grep("breaks_rules").count > 0 %> + <%= disapprovals.map(&:reason).grep("breaks_rules").count %> believe it breaks the rules. <% end %> - <% if disapprovals.poor_quality.count > 0 %> - <%= disapprovals.poor_quality.count %> believe it has poor quality. + <% if disapprovals.map(&:reason).grep("poor_quality").count > 0 %> + <%= disapprovals.map(&:reason).grep("poor_quality").count %> believe it has poor quality. <% end %> - <% if disapprovals.disinterest.count > 0 %> - <%= disapprovals.disinterest.count %> did not like the post enough to approve it. + <% if disapprovals.map(&:reason).grep(/disinterest|legacy/).count > 0 %> + <%= disapprovals.map(&:reason).grep(/disinterest|legacy/).count %> did not like the post enough to approve it. <% end %> - <% if disapprovals.with_message.any? %> - Messages: <%= disapprovals.with_message.map(&:message).to_sentence %> + <% if disapprovals.map(&:message).any?(&:present?) %> + Messages: <%= disapprovals.map(&:message).select(&:present?).map { |msg| format_text(msg, ragel: true, inline: true) }.to_sentence.html_safe %>. <% end %>
-<% end %> \ No newline at end of file +<% end %> diff --git a/test/functional/moderator/dashboards_controller_test.rb b/test/functional/moderator/dashboards_controller_test.rb index dbdff63fd..6259601e9 100644 --- a/test/functional/moderator/dashboards_controller_test.rb +++ b/test/functional/moderator/dashboards_controller_test.rb @@ -53,7 +53,7 @@ module Moderator end should "render" do - assert_equal(1, PostVersion.count) + assert_equal(1, PostArchive.count) get :show, {}, {:user_id => @admin.id} assert_response :success end diff --git a/test/functional/posts_controller_test.rb b/test/functional/posts_controller_test.rb index 01da6f29f..d78111855 100644 --- a/test/functional/posts_controller_test.rb +++ b/test/functional/posts_controller_test.rb @@ -144,12 +144,12 @@ class PostsControllerTest < ActionController::TestCase context "revert action" do setup do - @post.stubs(:merge_version?).returns(false) + PostArchive.sqs_service.stubs(:merge?).returns(false) @post.update_attributes(:tag_string => "zzz") end should "work" do - @version = @post.versions(true).first + @version = @post.versions.first assert_equal("aaaa", @version.tags) post :revert, {:id => @post.id, :version_id => @version.id}, {:user_id => @user.id} assert_redirected_to post_path(@post) diff --git a/test/helpers/post_archive_test_helper.rb b/test/helpers/post_archive_test_helper.rb new file mode 100644 index 000000000..7a0a19453 --- /dev/null +++ b/test/helpers/post_archive_test_helper.rb @@ -0,0 +1,45 @@ +module PostArchiveTestHelper + def setup + super + + mock_post_archive_service! + start_post_archive_transaction + end + + def teardown + super + + rollback_post_archive_transaction + end + + def mock_post_archive_service! + mock_sqs_service = Class.new do + def send_message(msg) + _, json = msg.split(/\n/) + json = JSON.parse(json) + json.delete("created_at") + json["version"] = 1 + PostArchive.where(post_id: json["post_id"]).count + prev = PostArchive.where(post_id: json["post_id"]).order("id desc").first + if merge?(prev, json) + prev.update_columns(json) + else + PostArchive.create(json) + end + end + + def merge?(prev, json) + prev && (prev.updater_id == json["updater_id"]) && (prev.updated_at >= 1.hour.ago) + end + end + + PostArchive.stubs(:sqs_service).returns(mock_sqs_service.new) + end + + def start_post_archive_transaction + PostArchive.connection.begin_transaction joinable: false + end + + def rollback_post_archive_transaction + PostArchive.connection.rollback_transaction + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index d428a5de4..b71c9bbb3 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -11,6 +11,7 @@ end require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' require 'cache' +require 'helpers/post_archive_test_helper' Dir[File.expand_path(File.dirname(__FILE__) + "/factories/*.rb")].each {|file| require file} @@ -24,6 +25,24 @@ if defined?(MEMCACHE) Object.send(:remove_const, :MEMCACHE) end +class ActiveSupport::TestCase + include PostArchiveTestHelper +end + +class ActionController::TestCase + include PostArchiveTestHelper + + def assert_authentication_passes(action, http_method, role, params, session) + __send__(http_method, action, params, session.merge(:user_id => @users[role].id)) + assert_response :success + end + + def assert_authentication_fails(action, http_method, role) + __send__(http_method, action, params, session.merge(:user_id => @users[role].id)) + assert_redirected_to(new_sessions_path) + end +end + MEMCACHE = MemcacheMock.new Delayed::Worker.delay_jobs = false diff --git a/test/unit/note_test.rb b/test/unit/note_test.rb index d2a392162..081f46fbd 100644 --- a/test/unit/note_test.rb +++ b/test/unit/note_test.rb @@ -107,11 +107,14 @@ class NoteTest < ActiveSupport::TestCase setup do @post = FactoryGirl.create(:post, :image_width => 1000, :image_height => 1000) @note = FactoryGirl.create(:note, :post => @post) + @note.stubs(:merge_version?).returns(false) end should "increment the updater's note_update_count" do - assert_difference("CurrentUser.note_update_count", 1) do + @user.reload + assert_difference("@user.note_update_count", 1) do @note.update_attributes(:body => "zzz") + @user.reload end end diff --git a/test/unit/post_test.rb b/test/unit/post_test.rb index 0ac525442..96b0ab8a4 100644 --- a/test/unit/post_test.rb +++ b/test/unit/post_test.rb @@ -10,7 +10,9 @@ class PostTest < ActiveSupport::TestCase assert_equal(posts.map(&:id), Post.tag_match(query).pluck(:id)) end - setup do + def setup + super + Timecop.travel(2.weeks.ago) do @user = FactoryGirl.create(:user) end @@ -20,7 +22,9 @@ class PostTest < ActiveSupport::TestCase mock_saved_search_service! end - teardown do + def teardown + super + CurrentUser.user = nil CurrentUser.ip_addr = nil end @@ -1055,7 +1059,7 @@ class PostTest < ActiveSupport::TestCase context "that has been updated" do should "create a new version if it's the first version" do - assert_difference("PostVersion.count", 1) do + assert_difference("PostArchive.count", 1) do post = FactoryGirl.create(:post) end end @@ -1063,7 +1067,7 @@ class PostTest < ActiveSupport::TestCase should "create a new version if it's been over an hour since the last update" do post = FactoryGirl.create(:post) Timecop.travel(6.hours.from_now) do - assert_difference("PostVersion.count", 1) do + assert_difference("PostArchive.count", 1) do post.update_attributes(:tag_string => "zzz") end end @@ -1071,15 +1075,16 @@ class PostTest < ActiveSupport::TestCase should "merge with the previous version if the updater is the same user and it's been less than an hour" do post = FactoryGirl.create(:post) - assert_difference("PostVersion.count", 0) do + assert_difference("PostArchive.count", 0) do post.update_attributes(:tag_string => "zzz") end assert_equal("zzz", post.versions.last.tags) end should "increment the updater's post_update_count" do + PostArchive.sqs_service.stubs(:merge?).returns(false) post = FactoryGirl.create(:post, :tag_string => "aaa bbb ccc") - post.stubs(:merge_version?).returns(false) + CurrentUser.reload assert_difference("CurrentUser.post_update_count", 1) do post.update_attributes(:tag_string => "zzz") @@ -2289,8 +2294,8 @@ class PostTest < ActiveSupport::TestCase context "a post that has been updated" do setup do + PostArchive.sqs_service.stubs(:merge?).returns(false) @post = FactoryGirl.create(:post, :rating => "q", :tag_string => "aaa", :source => nil) - @post.stubs(:merge_version?).returns(false) @post.update_attributes(:tag_string => "aaa bbb ccc ddd") @post.update_attributes(:tag_string => "bbb xxx yyy", :source => "xyz") @post.update_attributes(:tag_string => "bbb mmm yyy", :source => "abc") diff --git a/test/unit/post_version_test.rb b/test/unit/post_version_test.rb index cd9f45a01..c89a64dd6 100644 --- a/test/unit/post_version_test.rb +++ b/test/unit/post_version_test.rb @@ -18,28 +18,21 @@ class PostVersionTest < ActiveSupport::TestCase context "that has multiple versions: " do setup do + PostArchive.sqs_service.stubs(:merge?).returns(false) @post = FactoryGirl.create(:post, :tag_string => "1") - @post.stubs(:merge_version?).returns(false) - @post.stubs(:tag_string_changed?).returns(true) @post.update_attributes(:tag_string => "1 2") @post.update_attributes(:tag_string => "2 3") end context "a version record" do setup do - @version = PostVersion.last + @version = PostArchive.last end should "know its previous version" do assert_not_nil(@version.previous) assert_equal("1 2", @version.previous.tags) end - - should "know the seuqence of all versions for the post" do - assert_equal(2, @version.sequence_for_post.size) - assert_equal(%w(3), @version.sequence_for_post[0][:added_tags]) - assert_equal(%w(2), @version.sequence_for_post[1][:added_tags]) - end end end @@ -75,9 +68,8 @@ class PostVersionTest < ActiveSupport::TestCase context "that has been updated" do setup do - @parent = FactoryGirl.create(:post) + PostArchive.sqs_service.stubs(:merge?).returns(false) @post = FactoryGirl.create(:post, :tag_string => "aaa bbb ccc", :rating => "q", :source => "xyz") - @post.stubs(:merge_version?).returns(false) @post.update_attributes(:tag_string => "bbb ccc xxx", :source => "") end diff --git a/test/unit/post_vote_test.rb b/test/unit/post_vote_test.rb index 33e874fbf..4b35fa200 100644 --- a/test/unit/post_vote_test.rb +++ b/test/unit/post_vote_test.rb @@ -1,7 +1,9 @@ require 'test_helper' class PostVoteTest < ActiveSupport::TestCase - setup do + def setup + super + user = FactoryGirl.create(:user) CurrentUser.user = user CurrentUser.ip_addr = "127.0.0.1" diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index 34253af5a..f9f4f2a3d 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -186,6 +186,13 @@ class UserTest < ActiveSupport::TestCase assert_equal(Danbooru.config.default_guest_name, User.id_to_name(-1)) end + should "not contain whitespace" do + # U+2007: https://en.wikipedia.org/wiki/Figure_space + user = FactoryGirl.build(:user, :name => "foo\u2007bar") + user.save + assert_equal(["Name cannot have whitespace or colons"], user.errors.full_messages) + end + should "not contain a colon" do user = FactoryGirl.build(:user, :name => "a:b") user.save