mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
add job to cleanup uncontainered attachments
This commit is contained in:
@@ -52,6 +52,9 @@ class Attachment < ActiveRecord::Base
|
||||
|
||||
after_commit :extract_fulltext, on: :create
|
||||
|
||||
after_create :schedule_cleanup_uncontainered_job,
|
||||
unless: :containered?
|
||||
|
||||
##
|
||||
# Returns an URL if the attachment is stored in an external (fog) attachment storage
|
||||
# or nil otherwise.
|
||||
@@ -121,6 +124,10 @@ class Attachment < ActiveRecord::Base
|
||||
file.readable?
|
||||
end
|
||||
|
||||
def containered?
|
||||
container.present?
|
||||
end
|
||||
|
||||
def diskfile
|
||||
file.local_file
|
||||
end
|
||||
@@ -180,6 +187,10 @@ class Attachment < ActiveRecord::Base
|
||||
|
||||
private
|
||||
|
||||
def schedule_cleanup_uncontainered_job
|
||||
Delayed::Job::enqueue Attachments::CleanupUncontaineredJob.new
|
||||
end
|
||||
|
||||
def filesize_below_allowed_maximum
|
||||
if filesize > Setting.attachment_max_size.to_i.kilobytes
|
||||
errors.add(:file, :file_too_large, count: Setting.attachment_max_size.to_i.kilobytes)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#-- encoding: UTF-8
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is a project management system.
|
||||
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
class Attachments::CleanupUncontaineredJob < ApplicationJob
|
||||
def perform
|
||||
Attachment
|
||||
.where(container: nil)
|
||||
.where(too_old)
|
||||
.destroy_all
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def too_old
|
||||
attachment_table = Attachment.arel_table
|
||||
|
||||
attachment_table[:created_at]
|
||||
.lteq(Time.now - OpenProject::Configuration.attachments_grace_period.minutes)
|
||||
.to_sql
|
||||
end
|
||||
end
|
||||
@@ -186,6 +186,10 @@ default:
|
||||
# attachments_storage_path: /var/openproject/files
|
||||
# attachments_storage_path:
|
||||
|
||||
# Grace period until uploaded but unassigned (i.e. to a container like work packages,
|
||||
# wiki pages) attachments are deleted (in minutes)
|
||||
# attachment_grace_period: 180
|
||||
|
||||
# Configuration of the autologin cookie.
|
||||
# autologin_cookie_name: the name of the cookie (default: autologin)
|
||||
# autologin_cookie_path: the cookie path (default: /)
|
||||
|
||||
@@ -39,6 +39,7 @@ module OpenProject
|
||||
@defaults = {
|
||||
'attachments_storage' => 'file',
|
||||
'attachments_storage_path' => nil,
|
||||
'attachments_grace_period' => 180,
|
||||
'autologin_cookie_name' => 'autologin',
|
||||
'autologin_cookie_path' => '/',
|
||||
'autologin_cookie_secure' => false,
|
||||
@@ -457,15 +458,15 @@ module OpenProject
|
||||
|
||||
def define_config_methods
|
||||
@config.keys.each do |setting|
|
||||
(class << self; self; end).class_eval do
|
||||
define_method setting do
|
||||
self[setting]
|
||||
end
|
||||
next if respond_to? setting
|
||||
|
||||
define_method "#{setting}?" do
|
||||
['true', true, '1'].include? self[setting]
|
||||
end
|
||||
end unless respond_to? setting
|
||||
define_singleton_method setting do
|
||||
self[setting]
|
||||
end
|
||||
|
||||
define_singleton_method "#{setting}?" do
|
||||
['true', true, '1'].include? self[setting]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -134,6 +134,20 @@ describe Attachment, type: :model do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#containered?' do
|
||||
it 'is false if the attachment has no container' do
|
||||
stubbed_attachment.container = nil
|
||||
|
||||
expect(stubbed_attachment)
|
||||
.not_to be_containered
|
||||
end
|
||||
|
||||
it 'is true if the attachment has a container' do
|
||||
expect(stubbed_attachment)
|
||||
.to be_containered
|
||||
end
|
||||
end
|
||||
|
||||
describe 'create' do
|
||||
it('creates a jpg file called test') do
|
||||
expect(File.exists?(attachment.diskfile.path)).to eq true
|
||||
@@ -160,6 +174,29 @@ describe Attachment, type: :model do
|
||||
expect(attachment.digest)
|
||||
.to eql Digest::MD5.file(file.path).hexdigest
|
||||
end
|
||||
|
||||
it 'adds no cleanup job' do
|
||||
expect(Delayed::Job)
|
||||
.not_to receive(:enqueue)
|
||||
.with an_instance_of(Attachments::CleanupUncontaineredJob)
|
||||
|
||||
attachment.save!
|
||||
end
|
||||
|
||||
context 'with an unclaimed attachment' do
|
||||
let(:container) { nil }
|
||||
|
||||
it 'adds a cleanup job' do
|
||||
allow(Delayed::Job)
|
||||
.to receive(:enqueue)
|
||||
|
||||
expect(Delayed::Job)
|
||||
.to receive(:enqueue)
|
||||
.with an_instance_of(Attachments::CleanupUncontaineredJob)
|
||||
|
||||
attachment.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'two attachments with same file name' do
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#-- encoding: UTF-8
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is a project management system.
|
||||
# Copyright (C) 2012-2017 the OpenProject Foundation (OPF)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See doc/COPYRIGHT.rdoc for more details.
|
||||
#++
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Attachments::CleanupUncontaineredJob, type: :job do
|
||||
let(:grace_period) { 120 }
|
||||
let!(:containered_attachment) { FactoryBot.create(:attachment) }
|
||||
let!(:old_uncontainered_attachment) do
|
||||
FactoryBot.create(:attachment, container: nil, created_at: Time.now - grace_period.minutes)
|
||||
end
|
||||
let!(:new_uncontainered_attachment) do
|
||||
FactoryBot.create(:attachment, container: nil, created_at: Time.now - (grace_period - 1).minutes)
|
||||
end
|
||||
let(:job) { described_class.new }
|
||||
|
||||
before do
|
||||
allow(OpenProject::Configuration)
|
||||
.to receive(:attachments_grace_period)
|
||||
.and_return(grace_period)
|
||||
end
|
||||
|
||||
it 'removes all uncontainered attachments that are older than the grace period' do
|
||||
job.perform
|
||||
|
||||
expect(Attachment.all)
|
||||
.to match_array([containered_attachment, new_uncontainered_attachment])
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user