Merge branch 'master' of git.workaround.org:chaas/debshots

This commit is contained in:
Christoph Haas 2016-07-12 20:32:36 +02:00
commit 773548afc3
22 changed files with 303 additions and 75 deletions

View file

@ -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

View file

@ -953,5 +953,8 @@ a.black
margin-bottom: 0.5em;
}
.description-verbatim-lines
{
line-height: 120%;
// white-space: pre-line;
}

View file

@ -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/

View file

@ -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

View file

@ -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

View file

@ -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<version_y

View file

@ -0,0 +1,7 @@
json.package @p.name
json.screenshots @p.screenshots do |s|
json.small_image_url "#{request.protocol}#{request.host_with_port}#{s.image.url(:thumb, timestamp: false)}"
json.large_image_url "#{request.protocol}#{request.host_with_port}#{s.image.url(:large, timestamp: false)}"
json.version s.version
end

View file

@ -0,0 +1,6 @@
json.cache! ['json_packages'], expires_in: 1.hour do
json.packages @p do |p|
json.extract! p, :maintainer, :name, :section, :maintainer_email, :homepage, :description
json.url package_url(p.name)
end
end

View file

@ -0,0 +1,5 @@
json.cache! ['json_packages'], expires_in: 1.hour do
json.packages @p do |p|
json.extract! p, :name
end
end

View file

@ -0,0 +1,10 @@
json.cache! ['json_screenshots'], expires_in: 1.hour do
json.screenshots @s do |s|
p = s.package
json.extract! s, :version
json.extract! p, :maintainer, :name, :section, :maintainer_email, :homepage, :description
json.url package_url(p.name)
json.small_image_url "#{request.protocol}#{request.host_with_port}#{s.image.url(:thumb, timestamp: false)}"
json.large_image_url "#{request.protocol}#{request.host_with_port}#{s.image.url(:large, timestamp: false)}"
end
end

View file

@ -0,0 +1,19 @@
/ Converts long descriptions from Debian control files into
/ proper HTML.
/ See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Description
- text.lines.each do |line|
/ pre +++#{line}---
- case line.rstrip
- when '.'
/ Empty line
/ TODO: Technically wrong because this creates an empty paragraph:
p
- when /^(\s+)(.+)/
/ Verbatim text
div.description-verbatim-lines
= ('&nbsp;' * $1.to_s.length).html_safe
= $2
- else
/ Normal text
= line

View file

@ -4,7 +4,7 @@
'Manage your screenshot
.dropdown-pane data-dropdown=true id="admin-info-#{screenshot.id}"
a.button.small.alert[
href=delete_screenshot_path(@package.name, screenshot.id)
href=delete_screenshot_path(screenshot.id)
onclick="return confirm('Really delete the screenshot?');"
] Delete screenshot
p Write a description for this screenshot:

View file

@ -13,14 +13,14 @@
.text-center
a.black.fancybox href=screenshot.image.url(:large, timestamp: false) rel='fancybox-thumb' title=screenshot.caption
= image_tag(screenshot.image.url(:large, timestamp: false), alt: screenshot.caption)
- if screenshot.description
.imgcaption =screenshot.description
- if screenshot.version.present?
.imgcaption
em '(from version #{screenshot.version})
- if user_signed_in?
.imgcaption
em =screenshot.adminstatus
div
- if screenshot.description
.imgcaption =screenshot.description
- if screenshot.version.present?
em.imgcaption
'(from version #{screenshot.version})
- if user_signed_in?
em.imgcaption Admin status: #{screenshot.adminstatus}
// Is the user an admin?
- if user_signed_in?
@ -44,7 +44,8 @@
p.subtitle Description
// TODO: split long_description by <p> 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?

View file

@ -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

View file

@ -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.

View file

@ -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".

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

Before After
Before After

View file

@ -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