From: yasushiito Date: Tue, 25 Dec 2012 23:05:52 +0000 (+0900) Subject: t30350#:fix destroy in op, p, user X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=212567177d209b6a8a83c5440cf3e33e7d389084;p=pettanr%2Fpettanr.git t30350#:fix destroy in op, p, user --- diff --git a/app/controllers/original_pictures_controller.rb b/app/controllers/original_pictures_controller.rb index 9739a0eb..2ba2f480 100644 --- a/app/controllers/original_pictures_controller.rb +++ b/app/controllers/original_pictures_controller.rb @@ -122,13 +122,15 @@ class OriginalPicturesController < ApplicationController def destroy @original_picture = OriginalPicture.edit(params[:id], @artist) - OriginalPicture.transaction do - @original_picture.destroy - end respond_to do |format| - format.html { redirect_to original_pictures_url } - format.json { head :ok } + if @original_picture.destroy_with_resource_picture + format.html { redirect_to original_pictures_url } + format.json { head :ok } + else + format.html { redirect_to original_picture_path(@original_picture) } + format.json { render json: @original_picture.errors, status: :unprocessable_entity } + end end end end diff --git a/app/models/author.rb b/app/models/author.rb index 6de0ac87..4149e765 100644 --- a/app/models/author.rb +++ b/app/models/author.rb @@ -1,8 +1,8 @@ class Author < ActiveRecord::Base has_one :artist belongs_to :user - has_many :comic - has_many :panel + has_many :comics + has_many :panels validates :name, :presence => true, :length => {:maximum => 30} validates :user_id, :numericality => true, :existence => {:both => false} diff --git a/app/models/original_picture.rb b/app/models/original_picture.rb index 33de4f20..f55c06b7 100644 --- a/app/models/original_picture.rb +++ b/app/models/original_picture.rb @@ -11,8 +11,6 @@ class OriginalPicture < ActiveRecord::Base validates :artist_id, :presence => true, :numericality => true, :existence => {:both => false} validates :md5, :presence => true, :length => {:minimum => 32, :maximum => 32} - before_destroy :destroy_with_file - def supply_default end @@ -137,11 +135,6 @@ class OriginalPicture < ActiveRecord::Base {:include => {:resource_picture => {}, :pictures => {}}} end - def destroy_with_file - PictureIO.original_picture_io.delete self.filename - self.resource_picture.destroy - end - def store(imager) unless imager self.errors.add :base, I18n.t('errors.invalid_image') @@ -167,6 +160,29 @@ class OriginalPicture < ActiveRecord::Base PictureIO.original_picture_io.get self.filename, subdir end + def destroy_with_resource_picture + res = false + OriginalPicture.transaction do + begin + PictureIO.original_picture_io.delete(self.filename) if PictureIO.original_picture_io.exist?(self.filename) + rescue PictureIO::Error + res = false + raise ActiveRecord::Rollback + end + if self.resource_picture + res = self.resource_picture.unpublish + raise ActiveRecord::Rollback unless res + end + self.pictures.each do |picture| + res = picture.unpublish + raise ActiveRecord::Rollback unless res + end + res = self.destroy + raise ActiveRecord::Rollback unless res + end + res + end + def self.export ar l = LicenseGroup.list op = OriginalPicture.list ar.id diff --git a/app/models/picture.rb b/app/models/picture.rb index b9d7da14..3b1fc560 100644 --- a/app/models/picture.rb +++ b/app/models/picture.rb @@ -44,6 +44,7 @@ class Picture < ActiveRecord::Base end def showable? au = nil + return false unless self.original_picture return true if self.own?(au) self.enable? and self.head? end @@ -161,6 +162,12 @@ class Picture < ActiveRecord::Base PictureIO.picture_io.get self.filename, subdir end + def unpublish + imager = PettanImager.load(File.open(Rails.root + 'app/assets/images/error.png', 'rb').read) + return false unless imager + self.store imager + end + def credit_template "#{self.classname.tableize}/attributes/credit" end diff --git a/app/models/resource_picture.rb b/app/models/resource_picture.rb index 68e22c09..15999d68 100644 --- a/app/models/resource_picture.rb +++ b/app/models/resource_picture.rb @@ -216,15 +216,14 @@ class ResourcePicture < ActiveRecord::Base res = false ResourcePicture.transaction do begin - if res = self.destroy - PictureIO.resource_picture_io.delete(self.filename) - PictureIO.resource_picture_io.delete(self.filename, 'full') - res = true - end + PictureIO.resource_picture_io.delete(self.filename) if PictureIO.resource_picture_io.exist?(self.filename) + PictureIO.resource_picture_io.delete(self.filename, 'full') if PictureIO.resource_picture_io.exist?(self.filename, 'full') rescue PictureIO::Error res = false raise ActiveRecord::Rollback end + res = self.destroy + raise ActiveRecord::Rollback unless res end res end diff --git a/app/models/user.rb b/app/models/user.rb index 54ee43dd..5c809602 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -28,8 +28,14 @@ class User < ActiveRecord::Base self.author.panels.each do |panel| raise ActiveRecord::Rollback unless panel.destroy_with_elements end + if self.author.artist + self.author.artist.original_pictures.each do |original_picture| + raise ActiveRecord::Rollback unless original_picture.destroy_with_resource_picture + end + raise ActiveRecord::Rollback unless self.author.artist.destroy + end raise ActiveRecord::Rollback unless self.author.destroy - raise ActiveRecord::Rollback unless self.destroy + raise ActiveRecord::Rollback unless super res = true end res diff --git a/app/views/pictures/show.html.erb b/app/views/pictures/show.html.erb index 5a11460d..59402e73 100644 --- a/app/views/pictures/show.html.erb +++ b/app/views/pictures/show.html.erb @@ -1,26 +1,32 @@

<%= t('.title') %>

- <% if @picture.enable? %> - <% if @picture.head? %> + <% if @picture.original_picture %> + <% if @picture.enable? %> + <% if @picture.head? %> +

+ <%= t 'pictures.show.announce.head' -%> + <%= link_to tag(:img, @picture.tmb_opt_img_tag), resource_picture_path(@picture.resource_picture) %> +

+ <% else %> +

+ <%= t 'pictures.show.announce.tail' -%> + <%= link_to tag(:img, @picture.head.tmb_opt_img_tag), resource_picture_path(@picture.head.resource_picture) %> +

+ <% end %> + <% else %>

- <%= t 'pictures.show.announce.head' -%> - <%= link_to tag(:img, @picture.tmb_opt_img_tag), resource_picture_path(@picture.resource_picture) %> + <%= t 'pictures.show.announce.disable' -%>

- <% else %> + <% end %> + <% if @picture.own? @artist %>

- <%= t 'pictures.show.announce.tail' -%> - <%= link_to tag(:img, @picture.head.tmb_opt_img_tag), resource_picture_path(@picture.head.resource_picture) %> + <%= t 'pictures.show.announce.owner' -%> + <%= link_to tag(:img, @picture.original_picture.tmb_opt_img_tag), original_picture_path(@picture.original_picture) %>

<% end %> <% else %>

- <%= t 'pictures.show.announce.disable' -%> -

- <% end %> - <% if @picture.own? @artist %> -

- <%= t 'pictures.show.announce.owner' -%> - <%= link_to tag(:img, @picture.original_picture.tmb_opt_img_tag), original_picture_path(@picture.original_picture) %> + <%= t 'pictures.show.announce.destroyed' -%>

<% end %>
diff --git a/config/locales/pettanr.ja.yml b/config/locales/pettanr.ja.yml index 16127691..f3dd974f 100644 --- a/config/locales/pettanr.ja.yml +++ b/config/locales/pettanr.ja.yml @@ -584,6 +584,7 @@ ja: head: 素材として利用できます。 tail: この画像は既に改訂されています。素材として利用するなら、こちら(最新版)が利用できます。 owner: あなたの画像です。原画を管理するなら、こちらを利用してください。 + destroyed: この素材は削除されています。素材として利用できません。 md5: title: 実素材MD5検索一覧 credit: diff --git a/spec/controllers/original_pictures_controller_spec.rb b/spec/controllers/original_pictures_controller_spec.rb index 4a325ef8..782b8eba 100644 --- a/spec/controllers/original_pictures_controller_spec.rb +++ b/spec/controllers/original_pictures_controller_spec.rb @@ -909,4 +909,99 @@ describe OriginalPicturesController do end end + describe '削除に於いて' do + before do + @op = FactoryGirl.create :original_picture, :artist_id => @artist.id + sign_in @user + end + context '事前チェックしておく' do + before do + OriginalPicture.stub(:edit).with(any_args()).and_return @op + OriginalPicture.any_instance.stub(:destroy_with_resource_picture).with(any_args()).and_return(true) + end + it '原画モデルに編集取得を問い合わせている' do + OriginalPicture.should_receive(:edit).exactly(1) + delete :destroy, :id => @op.id + end + it 'モデルに削除を依頼する' do + OriginalPicture.any_instance.should_receive(:destroy_with_resource_picture).exactly(1) + delete :destroy, :id => @op.id + end + it '@original_pictureにアレを取得している' do + delete :destroy, :id => @op.id + assigns(:original_picture).id.should eq(@op.id) + end + end + context 'つつがなく終わるとき' do + before do + OriginalPicture.any_instance.stub(:destroy_with_resource_picture).with(any_args()).and_return(true) + end + context 'html形式' do + it 'ステータスコード302 Foundを返す' do + delete :destroy, :id => @op.id + response.status.should eq 302 + end + it '原画の一覧ページへ遷移する' do + delete :destroy, :id => @op.id + response.should redirect_to(original_pictures_path) + end + end + context 'json形式' do + it 'ステータスコード200 OKを返す' do + delete :destroy, :id => @op.id, :format => :json + response.should be_success + end + it 'ページ本体は特に返さない' do + delete :destroy, :id => @op.id, :format => :json + response.body.should match /./ + end + end + end + context '作家権限がないとき' do + before do + sign_out @user + end + it 'ステータスコード302 Foundを返す' do + delete :destroy, :id => @op.id + response.status.should eq 302 + end + context 'html形式' do + it 'サインインページへ遷移する' do + delete :destroy, :id => @op.id + response.body.should redirect_to '/users/sign_in' + end + end + context 'json形式' do + it '応答メッセージにUnauthorizedを返す' do + delete :destroy, :id => @op.id, :format => :json + response.message.should match(/Unauthorized/) + end + end + end + context '削除に失敗したとき' do + before do + OriginalPicture.any_instance.stub(:destroy_with_resource_picture).and_return(false) + end + context 'html形式' do + it 'ステータスコード302 Foundを返す' do + delete :destroy, :id => @op.id + response.status.should eq 302 + end + it 'その原画の詳細ページへ遷移する' do + delete :destroy, :id => @op.id + response.should redirect_to(original_picture_path(@op)) + end + end + context 'json形式' do + it 'ステータスコード422 unprocessable_entity を返す' do + delete :destroy, :id => @op.id, :format => :json + response.status.should eq 422 + end + it '応答メッセージUnprocessable Entityを返す' do + delete :destroy, :id => @op.id, :format => :json + response.message.should match(/Unprocessable/) + end + end + end + end end diff --git a/spec/models/original_picture_spec.rb b/spec/models/original_picture_spec.rb index ae736ba9..89918303 100644 --- a/spec/models/original_picture_spec.rb +++ b/spec/models/original_picture_spec.rb @@ -783,6 +783,140 @@ describe OriginalPicture do end end + describe '削除に於いて' do + before do + @op = FactoryGirl.create :original_picture, :artist_id => @artist.id + end + context '事前チェックしておく' do + before do + OriginalPicture.any_instance.stub(:destroy).and_return(true) + ResourcePicture.any_instance.stub(:unpublish).and_return(true) + Picture.any_instance.stub(:unpublish).with(any_args).and_return(true) + PictureIO.original_picture_io.stub(:delete).with(any_args).and_return(true) + end + it '原画モデルに削除を依頼している' do + OriginalPicture.any_instance.should_receive(:destroy).exactly(1) + r = @op.destroy_with_resource_picture + end + it '保管庫に原画の画像データ削除を依頼している' do + PictureIO.original_picture_io.should_receive(:delete).with(@op.filename).exactly(1) + r = @op.destroy_with_resource_picture + end + context '自身にリンクされた素材があるとき' do + it '素材モデルに削除を依頼している' do + @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :revision => 0 + @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id + ResourcePicture.any_instance.should_receive(:unpublish).exactly(1) + r = @op.destroy_with_resource_picture + end + end + context '自身にリンクされた素材がないとき' do + it '素材モデルに削除を依頼しない' do + ResourcePicture.any_instance.should_not_receive(:unpublish) + r = @op.destroy_with_resource_picture + end + end + context '自身にリンクされた実素材があるとき' do + it 'すべての実素材に墨塗を依頼している' do + @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :revision => 0 + Picture.any_instance.should_receive(:unpublish).with(any_args).exactly(1) + r = @op.destroy_with_resource_picture + end + end + context '自身にリンクされた実素材がないとき' do + it '実素材に墨塗を依頼しない' do + Picture.any_instance.should_not_receive(:unpublish) + r = @op.destroy_with_resource_picture + end + end + end + context 'つつがなく終わるとき' do + before do + PictureIO.original_picture_io.stub(:delete).with(any_args).and_return(true) + @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :revision => 0 + @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id + end + it '自身を削除する' do + lambda { + r = @op.destroy_with_resource_picture + }.should change(OriginalPicture, :count).by(-1) + lambda { + r = OriginalPicture.find @op.id + }.should raise_error + end + it 'Trueを返す' do + r = @op.destroy_with_resource_picture + r.should be_true + end + end + context '自身の削除に失敗したとき' do + before do + OriginalPicture.any_instance.stub(:destroy).with(any_args).and_return(false) + end + it 'Falseを返す' do + r = @op.destroy_with_resource_picture + r.should be_false + end + it 'ロールバックしている' do + lambda { + r = @op.destroy_with_resource_picture + }.should_not change(OriginalPicture, :count) + end + end + context '画像の削除に失敗したとき' do + before do + PictureIO.original_picture_io.stub(:delete).with(@op.filename).and_raise(PictureIO::Error) + end + it 'Falseを返す' do + r = @op.destroy_with_resource_picture + r.should be_false + end + it 'ロールバックしている' do + lambda { + r = @op.destroy_with_resource_picture + }.should_not change(OriginalPicture, :count) + end + end + context '素材の削除に失敗とき' do + before do + @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :revision => 0 + @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id + ResourcePicture.any_instance.stub(:unpublish).with(any_args).and_return(false) + end + it 'Falseを返す' do + r = @op.destroy_with_resource_picture + r.should be_false + end + it 'ロールバックしている' do + lambda { + r = @op.destroy_with_resource_picture + }.should_not change(OriginalPicture, :count) + lambda { + r = @op.destroy_with_resource_picture + }.should_not change(ResourcePicture, :count) + end + end + context '実素材の墨塗に失敗とき' do + before do + @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :revision => 0 + @rp = FactoryGirl.create :resource_picture, :artist_id => @artist.id, :license_id => @license.id, :original_picture_id => @op.id, :picture_id => @p.id + Picture.any_instance.stub(:unpublish).with(any_args).and_return(false) + end + it 'Falseを返す' do + r = @op.destroy_with_resource_picture + r.should be_false + end + it 'ロールバックしている' do + lambda { + r = @op.destroy_with_resource_picture + }.should_not change(OriginalPicture, :count) + lambda { + r = @op.destroy_with_resource_picture + }.should_not change(ResourcePicture, :count) + end + end + end + =begin describe 'エクスポートに於いて' do before do diff --git a/spec/models/picture_spec.rb b/spec/models/picture_spec.rb index e37eac72..8684f43a 100644 --- a/spec/models/picture_spec.rb +++ b/spec/models/picture_spec.rb @@ -286,6 +286,15 @@ describe Picture do before do @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id end + context '自身に原画がリンクしていないとき' do + before do + Picture.any_instance.stub(:original_picture).with(any_args).and_return(nil) + end + it 'Falseを返す' do + r = @p.showable?(@author) + r.should be_false + end + end it '自作の実素材ならyes' do Picture.any_instance.stub(:own?).with(any_args).and_return(true) @p.showable?(@artist).should == true @@ -852,6 +861,55 @@ describe Picture do end + describe '墨塗に於いて' do + before do + @p = FactoryGirl.create :picture, :original_picture_id => @op.id, :license_id => @license.id, :artist_id => @artist.id, :ext => 'png' + end + context '事前チェック' do + before do + @imager = ImagerTest.load "abc\ndef\nghi" + Picture.any_instance.stub(:store).with(any_args).and_return(true) + PettanImager.stub(:load).with(any_args).and_return(@imager) + end + it '画像ライブラリにロードを依頼している' do + PettanImager.should_receive(:load).with(any_args).exactly(1) + r = @p.unpublish + end + it '自身に作成を依頼している' do + Picture.any_instance.should_receive(:store).with(any_args).exactly(1) + r = @p.unpublish + end + end + context 'つつがなく終わるとき' do + before do + Picture.any_instance.stub(:store).with(any_args).and_return(true) + end + it 'Trueを返す' do + r = @p.unpublish + r.should be_true + end + end + #例外ケース + context '画像ライブラリのロードに失敗したとき' do + before do + PettanImager.stub(:load).and_return(false) + end + it 'Falseを返す' do + r = @p.unpublish + r.should be_false + end + end + context '作成に失敗したとき' do + before do + Picture.any_instance.stub(:store).with(any_args).and_return(false) + end + it 'Falseを返す' do + r = @p.unpublish + r.should be_false + end + end + end + describe 'フラグ展開に於いて' do before do @p = FactoryGirl.build :picture, :original_picture_id => @op.id, :license_id => @license.id,