Handle unexpected errors while exporting userdata or photos
Otherwise the export stays soft-locked and the podmin needs to reset it manually. Fixes #6225
This commit is contained in:
parent
9adcca2679
commit
172f80bcae
2 changed files with 51 additions and 22 deletions
|
|
@ -297,18 +297,22 @@ class User < ApplicationRecord
|
||||||
mount_uploader :export, ExportedUser
|
mount_uploader :export, ExportedUser
|
||||||
|
|
||||||
def queue_export
|
def queue_export
|
||||||
update exporting: true
|
update exporting: true, export: nil, exported_at: nil
|
||||||
Workers::ExportUser.perform_async(id)
|
Workers::ExportUser.perform_async(id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform_export!
|
def perform_export!
|
||||||
export = Tempfile.new([username, '.json.gz'], encoding: 'ascii-8bit')
|
export = Tempfile.new([username, ".json.gz"], encoding: "ascii-8bit")
|
||||||
export.write(compressed_export) && export.close
|
export.write(compressed_export) && export.close
|
||||||
if export.present?
|
if export.present?
|
||||||
update exporting: false, export: export, exported_at: Time.zone.now
|
update exporting: false, export: export, exported_at: Time.zone.now
|
||||||
else
|
else
|
||||||
update exporting: false
|
update exporting: false
|
||||||
end
|
end
|
||||||
|
rescue => error
|
||||||
|
logger.error "Unexpected error while exporting user '#{username}': #{error.class}: #{error.message}\n" \
|
||||||
|
"#{error.backtrace.first(15).join("\n")}"
|
||||||
|
update exporting: false
|
||||||
end
|
end
|
||||||
|
|
||||||
def compressed_export
|
def compressed_export
|
||||||
|
|
@ -319,12 +323,16 @@ class User < ApplicationRecord
|
||||||
mount_uploader :exported_photos_file, ExportedPhotos
|
mount_uploader :exported_photos_file, ExportedPhotos
|
||||||
|
|
||||||
def queue_export_photos
|
def queue_export_photos
|
||||||
update exporting_photos: true
|
update exporting_photos: true, exported_photos_file: nil, exported_photos_at: nil
|
||||||
Workers::ExportPhotos.perform_async(id)
|
Workers::ExportPhotos.perform_async(id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform_export_photos!
|
def perform_export_photos!
|
||||||
PhotoExporter.new(self).perform
|
PhotoExporter.new(self).perform
|
||||||
|
rescue => error
|
||||||
|
logger.error "Unexpected error while exporting photos for '#{username}': #{error.class}: #{error.message}\n" \
|
||||||
|
"#{error.backtrace.first(15).join("\n")}"
|
||||||
|
update exporting_photos: false
|
||||||
end
|
end
|
||||||
|
|
||||||
######### Mailer #######################
|
######### Mailer #######################
|
||||||
|
|
|
||||||
|
|
@ -981,63 +981,84 @@ describe User, :type => :model do
|
||||||
|
|
||||||
describe "queue_export" do
|
describe "queue_export" do
|
||||||
it "queues up a job to perform the export" do
|
it "queues up a job to perform the export" do
|
||||||
user = FactoryGirl.create :user
|
user = FactoryGirl.create(:user)
|
||||||
|
user.update export: Tempfile.new([user.username, ".json.gz"]), exported_at: Time.zone.now
|
||||||
expect(Workers::ExportUser).to receive(:perform_async).with(user.id)
|
expect(Workers::ExportUser).to receive(:perform_async).with(user.id)
|
||||||
user.queue_export
|
user.queue_export
|
||||||
expect(user.exporting).to be_truthy
|
expect(user.exporting).to be_truthy
|
||||||
|
expect(user.export).not_to be_present
|
||||||
|
expect(user.exported_at).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "perform_export!" do
|
describe "perform_export!" do
|
||||||
|
let(:user) { FactoryGirl.create(:user, exporting: true) }
|
||||||
|
|
||||||
it "saves a json export to the user" do
|
it "saves a json export to the user" do
|
||||||
user = FactoryGirl.create :user, exporting: true
|
|
||||||
user.perform_export!
|
user.perform_export!
|
||||||
expect(user.export).to be_present
|
expect(user.export).to be_present
|
||||||
expect(user.exported_at).to be_present
|
expect(user.exported_at).to be_present
|
||||||
expect(user.exporting).to be_falsey
|
expect(user.exporting).to be_falsey
|
||||||
expect(user.export.filename).to match /.json/
|
expect(user.export.filename).to match(/.json/)
|
||||||
expect(ActiveSupport::Gzip.decompress(user.export.file.read)).to include user.username
|
expect(ActiveSupport::Gzip.decompress(user.export.file.read)).to include user.username
|
||||||
end
|
end
|
||||||
|
|
||||||
it "compresses the result" do
|
it "compresses the result" do
|
||||||
user = FactoryGirl.create :user, exporting: true
|
|
||||||
expect(ActiveSupport::Gzip).to receive :compress
|
expect(ActiveSupport::Gzip).to receive :compress
|
||||||
user.perform_export!
|
user.perform_export!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "resets exporting to false when failing" do
|
||||||
|
expect_any_instance_of(Diaspora::Exporter).to receive(:execute).and_raise("Unexpected error!")
|
||||||
|
user.perform_export!
|
||||||
|
expect(user.exporting).to be_falsey
|
||||||
|
expect(user.export).not_to be_present
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "queue_export_photos" do
|
describe "queue_export_photos" do
|
||||||
it "queues up a job to perform the export photos" do
|
it "queues up a job to perform the export photos" do
|
||||||
user = FactoryGirl.create :user
|
user = FactoryGirl.create(:user)
|
||||||
|
user.update exported_photos_file: Tempfile.new([user.username, ".zip"]), exported_photos_at: Time.zone.now
|
||||||
expect(Workers::ExportPhotos).to receive(:perform_async).with(user.id)
|
expect(Workers::ExportPhotos).to receive(:perform_async).with(user.id)
|
||||||
user.queue_export_photos
|
user.queue_export_photos
|
||||||
expect(user.exporting_photos).to be_truthy
|
expect(user.exporting_photos).to be_truthy
|
||||||
|
expect(user.exported_photos_file).not_to be_present
|
||||||
|
expect(user.exported_photos_at).to be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "perform_export_photos!" do
|
describe "perform_export_photos!" do
|
||||||
|
let(:user) { FactoryGirl.create(:user_with_aspect, exporting: true) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@user = alice
|
image = File.join(File.dirname(__FILE__), "..", "fixtures", "button.png")
|
||||||
filename = 'button.png'
|
@saved_image = user.build_post(:photo, user_file: File.open(image), to: user.aspects.first.id)
|
||||||
image = File.join(File.dirname(__FILE__), '..', 'fixtures', filename)
|
|
||||||
@saved_image = @user.build_post(:photo, :user_file => File.open(image), :to => alice.aspects.first.id)
|
|
||||||
@saved_image.save!
|
@saved_image.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
it "saves a zip export to the user" do
|
it "saves a zip export to the user" do
|
||||||
@user.perform_export_photos!
|
user.perform_export_photos!
|
||||||
expect(@user.exported_photos_file).to be_present
|
expect(user.exported_photos_file).to be_present
|
||||||
expect(@user.exported_photos_at).to be_present
|
expect(user.exported_photos_at).to be_present
|
||||||
expect(@user.exporting_photos).to be_falsey
|
expect(user.exporting_photos).to be_falsey
|
||||||
expect(@user.exported_photos_file.filename).to match /.zip/
|
expect(user.exported_photos_file.filename).to match(/.zip/)
|
||||||
expect(Zip::File.open(@user.exported_photos_file.path).entries.count).to eq(1)
|
expect(Zip::File.open(user.exported_photos_file.path).entries.count).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "does not add empty entries when photo not found" do
|
it "does not add empty entries when photo not found" do
|
||||||
File.unlink @user.photos.first.unprocessed_image.path
|
File.unlink user.photos.first.unprocessed_image.path
|
||||||
@user.perform_export_photos!
|
user.perform_export_photos!
|
||||||
expect(@user.exported_photos_file.filename).to match /.zip/
|
expect(user.exporting_photos).to be_falsey
|
||||||
expect(Zip::File.open(@user.exported_photos_file.path).entries.count).to eq(0)
|
expect(user.exported_photos_file.filename).to match(/.zip/)
|
||||||
|
expect(Zip::File.open(user.exported_photos_file.path).entries.count).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "resets exporting_photos to false when failing" do
|
||||||
|
expect_any_instance_of(PhotoExporter).to receive(:perform).and_raise("Unexpected error!")
|
||||||
|
user.perform_export_photos!
|
||||||
|
expect(user.exporting_photos).to be_falsey
|
||||||
|
expect(user.exported_photos_file).not_to be_present
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue