diff --git a/README.rdoc b/README.rdoc index 63a0261..e10f8e9 100644 --- a/README.rdoc +++ b/README.rdoc @@ -114,23 +114,125 @@ https://www.phusionpassenger.com/library/walkthroughs/deploy/ruby/ownserver/ngin Example nginx vhost config: +## +# You should look at the following URL's in order to grasp a solid understanding +# of Nginx configuration files in order to fully unleash the power of Nginx. +# http://wiki.nginx.org/Pitfalls +# http://wiki.nginx.org/QuickStart +# http://wiki.nginx.org/Configuration +# +# Generally, you will want to move this file somewhere, and start with a clean +# file but keep this around for reference. Or just disable in sites-enabled. +# +# Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. +## + +#proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=assets:768m use_temp_path=off; + +#add_header X-Cache-Status $upstream_cache_status; +#add_header X-Runtime 42; +more_clear_headers 'X-Runtime'; +more_clear_headers 'X-Powered-By'; +more_clear_headers 'Server'; +server_tokens off; + +#passenger_show_version_in_header off; + +#log_format proxy '[$time_local] Cache: $upstream_cache_status $upstream_addr $upstream_response_time $status $bytes_sent $proxy_add_x_forwarded_for $request_uri "$http_referer" "$http_user_agent"'; +#access_log /var/log/nginx/debshots-access.log proxy; + +# Default server configuration +# +#passenger_log_level 5; + server { - listen 85.25.83.22:80 default_server; + listen 85.25.83.22:80 default_server; + #listen 80 default_server; + #listen [::]:80 default_server; + + # SSL configuration + # + # listen 443 ssl default_server; + # listen [::]:443 ssl default_server; + # + # Self signed certs generated by the ssl-cert package + # Don't use them in a production server! + # + # include snippets/snakeoil.conf; + passenger_enabled on; passenger_ruby /home/debshots/.rbenv/versions/2.3.1/bin/ruby; - root /home/debshots/debshots/public; - server_name _; + #passenger_pass_header X-Accel-Redirect; + + #proxy_cache_methods GET HEAD; + + root /home/debshots/debshots/public; + + # Add index.php to the list if you are using PHP + #index index.html index.htm index.nginx-debian.html; + + server_name _; + #proxy_cache assets; + #add_header X-Cache-Status $upstream_cache_status; + #proxy_ignore_headers Cache-Control; + + #add_header X-Debian rocks; + + location /assets/ { + alias /home/debshots/debshots/public/assets/; + expires 1h; + #include debshots_params; + add_header X-Coffee assets; + add_header Cache-Control public; + } + location /logo/ { + alias /home/debshots/debshots/public/logo/; + expires 1h; + add_header X-Coffee logo; + add_header Cache-Control public; + } + location /screenshots/ { + alias /home/debshots/debshots/public/screenshots/; + expires max; + add_header X-Coffee screenshots; + add_header Cache-Control public; + } + location /images/ { + alias /home/debshots/debshots/public/images/; + expires 1h; + add_header X-Coffee images; + add_header Cache-Control public; + } + + # Send thumbnails using X-Sendfile / X-Accel-Redirect + # The correct thumbnail is computed by the Rails application so it cannot be served directly. + location /thumbnail/ { + expires 1d; + add_header X-Coffee thumbnail; + add_header Cache-Control public; + + passenger_set_header X-Sendfile-Type "X-Accel-Redirect"; + passenger_env_var HTTP_X_ACCEL_MAPPING /home/debshots/debshots/public/=/__send_file_accel/; + passenger_pass_header X-Accel-Redirect; + } + + # Send public assets using X-Sendfile / X-Accel-Redirect (e.g. public/images/dummy/...) + location /public/ { + expires 1h; + add_header X-Coffee public; + add_header Cache-Control public; + + passenger_set_header X-Sendfile-Type "X-Accel-Redirect"; + passenger_env_var HTTP_X_ACCEL_MAPPING /home/debshots/debshots/public/=/__send_file_accel/; + passenger_pass_header X-Accel-Redirect; + } + + location /__send_file_accel/ { + internal; + alias /home/debshots/debshots/public/; + } } -=== Enable nginx caching - -mkdir /var/cache/nginx - -chown www-data.www-data /var/cache/nginx - -nginx config… - -proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off; == Supported URL paths (aka routes) @@ -215,7 +317,7 @@ proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g /screenshot/:package /screenshot-404/:package (deprecated) -* Return a small (320x240 pixel) PNG screenshot file of a package +* Return a large (320x240 pixel) PNG screenshot file of a package * If the package does not have any screenshots then return a 404 code /screenshot-with-version/:package/:version diff --git a/app/assets/stylesheets/_settings.scss b/app/assets/stylesheets/_settings.scss index df8abd4..8dbd208 100644 --- a/app/assets/stylesheets/_settings.scss +++ b/app/assets/stylesheets/_settings.scss @@ -953,5 +953,8 @@ a.black margin-bottom: 0.5em; } - - +.description-verbatim-lines +{ + line-height: 120%; + // white-space: pre-line; +} diff --git a/app/assets/stylesheets/moderate.scss b/app/assets/stylesheets/moderate.scss deleted file mode 100644 index 5571dd0..0000000 --- a/app/assets/stylesheets/moderate.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the Moderate controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/json_controller.rb b/app/controllers/json_controller.rb new file mode 100644 index 0000000..9db5d5e --- /dev/null +++ b/app/controllers/json_controller.rb @@ -0,0 +1,21 @@ +class JsonController < ApplicationController + # JSON information on a single package + def package + @p = Package.find_by_name! params[:name] + end + + # JSON information on all packages + def packages + @p = Package.all + end + + # JSON information on all screenshots + def screenshots + @s = Screenshot.includes(:package) + end + + # JSON list of packages that do not have screenshots + def packages_without_screenshots + @p = Package.without_screenshots.all + end +end diff --git a/app/controllers/packages_controller.rb b/app/controllers/packages_controller.rb index dfbda50..410fc8a 100644 --- a/app/controllers/packages_controller.rb +++ b/app/controllers/packages_controller.rb @@ -3,15 +3,11 @@ class PackagesController < ApplicationController protect_from_forgery :except => :legacy_uploadfile def list - @packages = query_packages - @packages = @packages.paginate(page: params[:page], per_page: 6) - render 'packages/index-list.slim' + @packages = query_packages.paginate(page: params[:page], per_page: 6) end def grid - @packages = query_packages - @packages = @packages.paginate(page: params[:page], per_page: 24) - render 'packages/index-grid.slim' + @packages = query_packages.paginate(page: params[:page], per_page: 24) end def details @@ -111,7 +107,14 @@ class PackagesController < ApplicationController thumbnail404 return end - @screenshot = @package.screenshots.first + + # Called as /thumbnail-with-version/:name/:version + if params[:version] + @screenshot = @package.best_screenshot_for_version(params[:version]) + # Called as /thumbnail/:name + else + @screenshot = @package.screenshots.first + end # Return a 404 if the package has no screenshots or the image was not found unless @screenshot and @screenshot.image.path @@ -119,11 +122,39 @@ class PackagesController < ApplicationController return end - # Send the thumbnail - # TODO: Make sure it uses X-Sendfile correctly in production + # Send the thumbnail (uses X-Sendfile or similar if possible) send_file @screenshot.image.path(:thumb), type: "image/png", disposition: 'inline' end + # Returns a large screenshot image if posssible. + # If the package is not found it returns a dummy image along with status 404. + # If the package is found but has no screenshots then it also returns a + # dummy image along with status 404. + def screenshot + @package = Package.find_by(name: params[:name]) + unless @package + screenshot404 + return + end + + # Called as /thumbnail-with-version/:name/:version + if params[:version] + @screenshot = @package.best_screenshot_for_version(params[:version]) + # Called as /thumbnail/:name + else + @screenshot = @package.screenshots.first + end + + # Return a 404 if the package has no screenshots or the image was not found + unless @screenshot and @screenshot.image.path + screenshot404 + return + end + + # Send the thumbnail (uses X-Sendfile or similar if possible) + send_file @screenshot.image.path(:large), type: "image/png", disposition: 'inline' + end + # Receives a form with a simple text field 'description' so that users can update # the description of their screenshot. def update_screenshot_description @@ -147,9 +178,15 @@ class PackagesController < ApplicationController private # Send a dummy thumbnail reading "No screenshot available. Sorry." - # TODO: Make sure it uses X-Sendfile correctly in production def thumbnail404 - send_file Rails.root.join('public/images/dummy/no-screenshots-available.png'), + send_file Rails.root.join('public/images/dummy/thumbnail404.png'), + type: "image/png", + disposition: 'inline', + status: 404 + end + + def screenshot404 + send_file Rails.root.join('public/images/dummy/screenshot404.png'), type: "image/png", disposition: 'inline', status: 404 diff --git a/app/models/package.rb b/app/models/package.rb index 7e532df..2af10ea 100644 --- a/app/models/package.rb +++ b/app/models/package.rb @@ -53,6 +53,12 @@ class Package < ActiveRecord::Base end # Return the newest screenshot that is not newer than the given version. + # This algorithm collects all image + # versions of a package and determines the (second) newest version. + # E.g. if there are version 1.0 and 2.0 and the user is looking for + # a screenshot of version 1.5 then the 1.0 version is returned. + # This way the user does not see a screenshot of version 2.0 because + # 2.0 might contain features that were not there in version 1.5. def best_screenshot_for_version(version) sorted_screenshots = self.screenshots_sorted_by_version sorted_screenshots.each do |ss| @@ -65,6 +71,8 @@ class Package < ActiveRecord::Base private def version_compare(x,y) + x ||= '0' + y ||= '0' version_x = DebImporter::Version.new(x) version_y = DebImporter::Version.new(y) if version_x tags - if @package.long_description.present? - p =@package.long_description + = render(partial: 'long_description', locals: {text: @package.long_description}) + / p =@package.long_description - else p Sorry - no more information available. - if @package.homepage.present? diff --git a/app/views/packages/index-grid.slim b/app/views/packages/grid.slim similarity index 100% rename from app/views/packages/index-grid.slim rename to app/views/packages/grid.slim diff --git a/app/views/packages/index-list.slim b/app/views/packages/list.slim similarity index 100% rename from app/views/packages/index-list.slim rename to app/views/packages/list.slim diff --git a/config/environments/development.rb b/config/environments/development.rb index 6e3a125..b750e0b 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -9,9 +9,13 @@ Debshots::Application.configure do # Do not eager load code on boot. config.eager_load = false - # Show full error reports and disable caching. + # Show full error reports config.consider_all_requests_local = true + + # Disable caching (except for working on caching) config.action_controller.perform_caching = false + # config.action_controller.perform_caching = true + # config.cache_store = :file_store, "#{Rails.root.to_s}/tmp/cache/filestore" # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false diff --git a/config/environments/production.rb b/config/environments/production.rb index a6df31c..65d43d9 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -13,9 +13,12 @@ Debshots::Application.configure do # ActiveRecord errors propagate normally (forward deprecation to Rails 5) config.active_record.raise_in_transactional_callbacks = true - # Full error reports are disabled and caching is turned on. + # Full error reports are disabled config.consider_all_requests_local = false + + # Caching turned on config.action_controller.perform_caching = true + config.cache_store = :file_store, "#{Rails.root.to_s}/tmp/cache/filestore" # Enable Rack::Cache to put a simple HTTP cache in front of your application # Add `rack-cache` to your Gemfile before enabling this. diff --git a/config/routes.rb b/config/routes.rb index bb44f48..fc0a048 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -28,6 +28,18 @@ Debshots::Application.routes.draw do get 'approve_screenshot/:id' => 'packages#approve_screenshot', as: :approve_screenshot get 'about' => 'welcome#about' get 'thumbnail/:name' => 'packages#thumbnail', as: :thumbnail_image, name: /[^\/]+/ + get 'thumbnail-with-version/:name/:version' => 'packages#thumbnail', name: /[^\/]+/, version: /\S+/ + get 'screenshot/:name' => 'packages#screenshot', as: :screenshot_image, name: /[^\/]+/ + get 'screenshot-with-version/:name/:version' => 'packages#screenshot', name: /[^\/]+/, version: /\S+/ + + # Legacy URLs + get 'with_screenshots', to: redirect('/packages?show=with') + get 'without_screenshots', to: redirect('/packages?show=without') + + get 'json/package/:name' => 'json#package', as: :json_package, defaults: { format: :json } + get 'json/packages' => 'json#packages', as: :json_packages, defaults: { format: :json } + get 'json/screenshots' => 'json#screenshots', as: :json_screenshots, defaults: { format: :json } + get 'json/packages-without-screenshots' => 'json#packages_without_screenshots', defaults: { format: :json } # The priority is based upon order of creation: first created -> highest priority. # See how all your routes lay out with "rake routes". diff --git a/lib/deb_importer.rb b/lib/deb_importer.rb index 9ab3855..6d2b96d 100644 --- a/lib/deb_importer.rb +++ b/lib/deb_importer.rb @@ -101,14 +101,14 @@ module DebImporter name=value='' data.each_line do |line| case line - when /^(.+?): (.+)/ # "Key: Value" + when /^(\S+?): (.+)/ # "Key: Value" fields[name.to_sym]=value unless value.empty? name,value=$1,$2 - when /^(.+?):$/ # "Key:" (start of multi-line entry without value in line) + when /^(\S+?):$/ # "Key:" (start of multi-line entry without value in line) fields[name.to_sym]=value unless value.empty? name=$1 value='' - when /^\s+(.+)/ # " Indented multi-line value" + when /^\s(.+)/ # " Indented multi-line value" # Add a newline for multi-line entries ("Key: Value\n Foo\n Bar") unless value.empty? value << "\n" @@ -188,36 +188,5 @@ module DebImporter def dpkg_compare_version(v1, v2, op) system("dpkg --compare-versions #{v1} #{op} #{v2}") end - - # def ___version_compare(x,y) - # # Compare a version string (like the upstream_version or - # # debian_revision string) against another version string. - # # The algorithm works like this: - # # - # # The strings are compared from left to right. - # # First the initial part of each string consisting entirely of non-digit - # # characters is determined. These two parts (one of which may be empty) - # # are compared lexically. If a difference is found it is returned. - # # The lexical comparison is a comparison of ASCII values modified so - # # that all the letters sort earlier than all the non-letters and so that - # # a tilde sorts before anything, even the end of a part. - # # For example, the following parts are in sorted order from - # # earliest to latest: ~~, ~~a, ~, the empty part, a.[37] - # # - # # Then the initial part of the remainder of each string which - # # consists entirely of digit characters is determined. The - # # numerical values of these two parts are compared, and any - # # difference found is returned as the result of the comparison. - # # For these purposes an empty string (which can only occur at - # # the end of one or both version strings being compared) counts as zero. - # # - # # These two steps (comparing and removing initial non-digit strings - # # and initial digit strings) are repeated until a difference is - # # found or both strings are exhausted. - - # (x.chars).zip(y.chars) do |xchar,ychar| - # puts xchar, ychar - # end - # end end # /class end # module diff --git a/public/images/dummy/screenshot404.png b/public/images/dummy/screenshot404.png new file mode 100644 index 0000000..18b455d Binary files /dev/null and b/public/images/dummy/screenshot404.png differ diff --git a/public/images/dummy/no-screenshots-available.png b/public/images/dummy/thumbnail404.png similarity index 100% rename from public/images/dummy/no-screenshots-available.png rename to public/images/dummy/thumbnail404.png diff --git a/test/controllers/json_controller_test.rb b/test/controllers/json_controller_test.rb new file mode 100644 index 0000000..0b10766 --- /dev/null +++ b/test/controllers/json_controller_test.rb @@ -0,0 +1,24 @@ +require "test_helper" + +class JsonControllerTest < ActionController::TestCase + def test_package + get :package + assert_response :success + end + + def test_packages + get :packages + assert_response :success + end + + def test_screenshots + get :screenshots + assert_response :success + end + + def test_packages-without-screenshots + get :packages-without-screenshots + assert_response :success + end + +end