diff --git a/app/controllers/public/content_viewer_controller.rb b/app/controllers/public/content_viewer_controller.rb index c3856a1..f1efb63 100644 --- a/app/controllers/public/content_viewer_controller.rb +++ b/app/controllers/public/content_viewer_controller.rb @@ -205,8 +205,6 @@ class ContentViewerController < ApplicationController def rendered_file_download(view = nil) if @page.download? view - headers['Content-Type'] = @page.mime_type - headers.merge! @page.download_headers data = @page.data # TODO test the condition @@ -214,7 +212,12 @@ class ContentViewerController < ApplicationController raise "No data for file" end - render :text => data, :layout => false + if @page.published && @page.uploaded_file? + redirect_to @page.public_filename + else + send_data data, @page.download_headers + end + return true end diff --git a/app/models/article.rb b/app/models/article.rb index 82fddb1..0a5b8fc 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -383,6 +383,10 @@ class Article < ActiveRecord::Base end end + def full_path + profile.hostname.blank? ? "/#{profile.identifier}/#{path}" : "/#{path}" + end + def url @url ||= self.profile.url.merge(:page => path.split('/')) end @@ -408,17 +412,19 @@ class Article < ActiveRecord::Base end def download? view = nil - (self.uploaded_file? and not self.image?) or - (self.image? and view.blank?) or - (not self.uploaded_file? and self.mime_type != 'text/html') + false end def is_followed_by?(user) self.person_followers.include? user end + def download_disposition + 'inline' + end + def download_headers - {} + { :filename => filename, :type => mime_type, :disposition => download_disposition} end def alternate_languages diff --git a/app/models/rss_feed.rb b/app/models/rss_feed.rb index ed5cf75..a862261 100644 --- a/app/models/rss_feed.rb +++ b/app/models/rss_feed.rb @@ -65,6 +65,10 @@ class RssFeed < Article 'text/xml' end + def download?(view = nil) + true + end + include Rails.application.routes.url_helpers def fetch_articles if parent && parent.has_posts? diff --git a/app/models/uploaded_file.rb b/app/models/uploaded_file.rb index 90b8162..2d3a380 100644 --- a/app/models/uploaded_file.rb +++ b/app/models/uploaded_file.rb @@ -2,6 +2,9 @@ # # Limitation: only file metadata are versioned. Only the latest version # of the file itself is kept. (FIXME?) + +require 'sdbm' + class UploadedFile < Article attr_accessible :uploaded_data, :title @@ -10,6 +13,19 @@ class UploadedFile < Article _('File') end + DBM_PRIVATE_FILE = 'cache/private_files' + after_save do |uploaded_file| + if uploaded_file.published_changed? + dbm = SDBM.open(DBM_PRIVATE_FILE) + if uploaded_file.published + dbm.delete(uploaded_file.public_filename) + else + dbm.store(uploaded_file.public_filename, uploaded_file.full_path) + end + dbm.close + end + end + track_actions :upload_image, :after_create, :keep_params => ["view_url", "thumbnail_path", "parent.url", "parent.name"], :if => Proc.new { |a| a.published? && a.image? && !a.parent.nil? && a.parent.gallery? }, :custom_target => :parent def title @@ -106,10 +122,13 @@ class UploadedFile < Article self.name ||= self.filename end - def download_headers - { - 'Content-Disposition' => "attachment; filename=\"#{self.filename}\"", - } + def download_disposition + case content_type + when 'application/pdf' + 'inline' + else + 'attachment' + end end def data diff --git a/app/views/file_presenter/_generic.html.erb b/app/views/file_presenter/_generic.html.erb index 4d57860..3a5db12 100644 --- a/app/views/file_presenter/_generic.html.erb +++ b/app/views/file_presenter/_generic.html.erb @@ -2,4 +2,4 @@ <%= generic.abstract %> -<%= button(:download, _('Download'), [Noosfero.root, generic.public_filename].join, class:'download-link', option:'primary', size:'lg') %> +<%= button(:download, _('Download'), generic.url, class:'download-link', option:'primary', size:'lg', :target => "_blank") %> diff --git a/debian/apache2/virtualhost.conf b/debian/apache2/virtualhost.conf index fadd2f3..ab9ba39 100644 --- a/debian/apache2/virtualhost.conf +++ b/debian/apache2/virtualhost.conf @@ -16,6 +16,11 @@ RewriteRule /http-bind http://localhost:5280/http-bind [P,QSA,L] Allow from All +# Pass access to private files to backend +RewriteMap private_files "dbm=sdbm:/usr/share/noosfero/cache/private_files" +RewriteCond ${private_files:$1|NOT_FOUND} !NOT_FOUND +RewriteRule ^(/articles/.*) ${private_files:$1} [P,QSA,L] + # Rewrite index to check for static index.html RewriteRule ^/$ /index.html [QSA] diff --git a/debian/noosfero.links b/debian/noosfero.links index eea35ee..124f85d 100644 --- a/debian/noosfero.links +++ b/debian/noosfero.links @@ -1,5 +1,6 @@ var/tmp/noosfero usr/share/noosfero/tmp var/log/noosfero usr/share/noosfero/log +var/cache/noosfero usr/share/noosfero/cache etc/noosfero/database.yml usr/share/noosfero/config/database.yml etc/noosfero/unicorn.rb usr/share/noosfero/config/unicorn.rb etc/noosfero/plugins usr/share/noosfero/config/plugins diff --git a/debian/noosfero.postinst b/debian/noosfero.postinst index 36b2721..e9d053f 100644 --- a/debian/noosfero.postinst +++ b/debian/noosfero.postinst @@ -74,6 +74,11 @@ fi . /usr/share/dbconfig-common/dpkg/postinst dbc_go noosfero $@ +if [ ! -f /usr/share/noosfero/cache/private_files.pag ] && [ $1 = "configure" ] && [ -n $2 ]; then + echo "Creating private files dbm map..." + cd /usr/share/noosfero && su noosfero -c "rake cache:private_files RAILS_ENV=production" +fi + # stop debconf to avoid the problem with infinite hanging, cfe # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=295477 db_stop diff --git a/etc/init.d/noosfero b/etc/init.d/noosfero index f8d6f4e..e0d1ba5 100755 --- a/etc/init.d/noosfero +++ b/etc/init.d/noosfero @@ -86,6 +86,13 @@ do_setup() { chmod 750 /var/tmp/noosfero fi + # Noosfero cache directory + if [ ! -d /var/cache/noosfero ]; then + mkdir /var/cache/noosfero + chown $NOOSFERO_USER:root /var/cache/noosfero + chmod 755 /var/cache/noosfero + fi + # symlink the directories into Noosfero directory if [ ! -e $NOOSFERO_DIR/tmp ]; then ln -s /var/tmp/noosfero $NOOSFERO_DIR/tmp @@ -96,6 +103,9 @@ do_setup() { if [ ! -e $NOOSFERO_DIR/log ]; then ln -s /var/log/noosfero $NOOSFERO_DIR/log fi + if [ ! -e $NOOSFERO_DIR/cache ]; then + ln -s /var/cache/noosfero $NOOSFERO_DIR/cache + fi } do_start() { diff --git a/lib/file_presenter.rb b/lib/file_presenter.rb index 2ef620e..cc169fe 100644 --- a/lib/file_presenter.rb +++ b/lib/file_presenter.rb @@ -52,8 +52,8 @@ class FilePresenter nil end - def download?(view=nil) - false + def download? view = nil + view.blank? end def short_description diff --git a/lib/tasks/cache.rake b/lib/tasks/cache.rake new file mode 100644 index 0000000..c073aeb --- /dev/null +++ b/lib/tasks/cache.rake @@ -0,0 +1,14 @@ +namespace :cache do + task :private_files => :environment do + require 'sdbm' + + hash = {} + UploadedFile.where(:published => false).find_each do |uploaded_file| + hash[uploaded_file.public_filename] = uploaded_file.full_path + end + + dbm = SDBM.open(UploadedFile::DBM_PRIVATE_FILE) + dbm.update(hash) + dbm.close + end +end diff --git a/test/functional/content_viewer_controller_test.rb b/test/functional/content_viewer_controller_test.rb index 66b612a..766c06a 100644 --- a/test/functional/content_viewer_controller_test.rb +++ b/test/functional/content_viewer_controller_test.rb @@ -51,27 +51,26 @@ class ContentViewerControllerTest < ActionController::TestCase assert_response :missing end - should 'produce a download-link when article is a uploaded file' do + should 'produce a download-link when view page is true' do profile = create_user('someone').person html = UploadedFile.create! :uploaded_data => fixture_file_upload('/files/500.html', 'text/html'), :profile => profile html.save! - get :view_page, :profile => 'someone', :page => [ '500.html' ] + get :view_page, :profile => 'someone', :page => [ '500.html' ], :view => true assert_response :success - assert_match /#{html.public_filename}/, @response.body + assert_select "a[href=#{html.full_path}]" end - should 'download file when article is image' do + should 'download file when view page is blank' do profile = create_user('someone').person image = UploadedFile.create! :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => profile image.save! get :view_page, :profile => 'someone', :page => [ 'rails.png' ] - assert_response :success - assert_not_nil assigns(:page).data - assert_match /image\/png/, @response.headers['Content-Type'] + assert_response :redirect + assert_redirected_to image.public_filename end should 'display image on a page when article is image and has a view param' do diff --git a/test/unit/article_block_test.rb b/test/unit/article_block_test.rb index 995e85a..d76eeae 100644 --- a/test/unit/article_block_test.rb +++ b/test/unit/article_block_test.rb @@ -140,6 +140,8 @@ class ArticleBlockTest < ActiveSupport::TestCase block.article = file block.save! + UploadedFile.any_instance.stubs(:url).returns('myhost.mydomain/path/to/file') + assert_tag_in_string instance_eval(&block.content), :tag => 'a', :content => _('Download') end diff --git a/test/unit/article_test.rb b/test/unit/article_test.rb index 459cb2a..11fa473 100644 --- a/test/unit/article_test.rb +++ b/test/unit/article_test.rb @@ -2241,4 +2241,15 @@ class ArticleTest < ActiveSupport::TestCase assert !a.display_preview? end + should 'return full_path' do + p1 = fast_create(Profile) + p2 = fast_create(Profile) + p2.domains << Domain.create!(:name => 'p2.domain') + a1 = fast_create(Article, :profile_id => p1.id) + a2 = fast_create(Article, :profile_id => p2.id) + + assert_equal "/#{p1.identifier}/#{a1.path}", a1.full_path + assert_equal "/#{a2.path}", a2.full_path + end + end diff --git a/test/unit/blog_helper_test.rb b/test/unit/blog_helper_test.rb index bf3fb31..d4ead4f 100644 --- a/test/unit/blog_helper_test.rb +++ b/test/unit/blog_helper_test.rb @@ -101,11 +101,9 @@ class BlogHelperTest < ActionView::TestCase should 'display link to file if post is an uploaded_file' do file = create(UploadedFile, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => profile, :published => true, :parent => blog) - result = display_post(file) - assert_tag_in_string result, :tag => 'a', - :attributes => { :href => file.public_filename }, - :content => _('Download') + + assert_tag_in_string result, :tag => 'a', :content => _('Download') end should 'display image if post is an image' do diff --git a/test/unit/uploaded_file_test.rb b/test/unit/uploaded_file_test.rb index 03e1799..4c8e0a9 100644 --- a/test/unit/uploaded_file_test.rb +++ b/test/unit/uploaded_file_test.rb @@ -357,4 +357,25 @@ class UploadedFileTest < ActiveSupport::TestCase assert_instance_of Fixnum, UploadedFile.max_size end + should 'add file to dbm if it becomes private' do + require 'sdbm' + public_file = create(UploadedFile, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => profile, :published => true) + private_file = create(UploadedFile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => profile, :published => false) + + dbm = SDBM.open(UploadedFile::DBM_PRIVATE_FILE) + assert !dbm.has_key?(public_file.public_filename) + assert dbm.has_key?(private_file.public_filename) + dbm.close + + public_file.published = false + public_file.save! + private_file.published = true + private_file.save! + + dbm = SDBM.open(UploadedFile::DBM_PRIVATE_FILE) + assert dbm.has_key?(public_file.public_filename) + assert !dbm.has_key?(private_file.public_filename) + dbm.close + end + end -- libgit2 0.21.2