radiant-downloads-extension 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +2 -0
- data/README.markdown +81 -0
- data/Rakefile +137 -0
- data/app/controllers/admin/downloads_controller.rb +3 -0
- data/app/controllers/downloads_controller.rb +21 -0
- data/app/models/download.rb +33 -0
- data/app/views/admin/downloads/_form.html.haml +47 -0
- data/app/views/admin/downloads/edit.html.haml +7 -0
- data/app/views/admin/downloads/index.html.haml +32 -0
- data/app/views/admin/downloads/new.html.haml +7 -0
- data/db/migrate/001_create_downloads.rb +28 -0
- data/downloads_extension.rb +39 -0
- data/lib/download_group.rb +7 -0
- data/lib/download_tags.rb +165 -0
- data/lib/download_ui.rb +38 -0
- data/lib/tasks/downloads_extension_tasks.rake +28 -0
- data/public/stylesheets/admin/downloads.css +25 -0
- data/spec/controllers/downloads_controller_spec.rb +73 -0
- data/spec/datasets/download_groups_dataset.rb +42 -0
- data/spec/datasets/download_readers_dataset.rb +49 -0
- data/spec/datasets/download_sites_dataset.rb +9 -0
- data/spec/datasets/downloads_dataset.rb +28 -0
- data/spec/files/test.pdf +681 -0
- data/spec/files/test.txt +1 -0
- data/spec/models/download_spec.rb +41 -0
- data/spec/models/group_spec.rb +20 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +36 -0
- metadata +130 -0
@@ -0,0 +1,165 @@
|
|
1
|
+
module DownloadTags
|
2
|
+
include Radiant::Taggable
|
3
|
+
|
4
|
+
class TagError < StandardError; end
|
5
|
+
|
6
|
+
# the root group tag is defined in reader_group and should only expand if there is a page group or message group
|
7
|
+
|
8
|
+
desc %{
|
9
|
+
Expands if this group has any downloads.
|
10
|
+
|
11
|
+
<pre><code><r:group:if_downloads>...</r:group:if_downloads /></code></pre>
|
12
|
+
}
|
13
|
+
tag "group:if_downloads" do |tag|
|
14
|
+
tag.expand if tag.locals.group.downloads.any?
|
15
|
+
end
|
16
|
+
|
17
|
+
desc %{
|
18
|
+
Expands if this group does not have any downloads.
|
19
|
+
|
20
|
+
<pre><code><r:group:unless_downloads>...</r:group:unless_downloads /></code></pre>
|
21
|
+
}
|
22
|
+
tag "group:unless_downloads" do |tag|
|
23
|
+
tag.expand unless tag.locals.group.downloads.any?
|
24
|
+
end
|
25
|
+
|
26
|
+
desc %{
|
27
|
+
Cycles through all downloads for the current group.
|
28
|
+
(which will only be defined if this is the home page for a group)
|
29
|
+
|
30
|
+
*Usage:*
|
31
|
+
<pre><code><r:group:downloads:each>...</r:group:downloads:each></code></pre>
|
32
|
+
}
|
33
|
+
tag 'group:downloads' do |tag|
|
34
|
+
tag.expand if tag.locals.group
|
35
|
+
end
|
36
|
+
tag 'group:downloads:each' do |tag|
|
37
|
+
result = []
|
38
|
+
tag.locals.group.downloads.each do |download|
|
39
|
+
tag.locals.download = download
|
40
|
+
result << tag.expand
|
41
|
+
end
|
42
|
+
result
|
43
|
+
end
|
44
|
+
|
45
|
+
desc %{
|
46
|
+
Expands if the current reader has any downloads.
|
47
|
+
|
48
|
+
<pre><code><r:reader:if_downloads>...</r:reader:if_downloads /></code></pre>
|
49
|
+
}
|
50
|
+
tag "reader:if_downloads" do |tag|
|
51
|
+
tag.expand if tag.locals.reader.downloads.any?
|
52
|
+
end
|
53
|
+
|
54
|
+
desc %{
|
55
|
+
Expands if the current reader does not have any downloads.
|
56
|
+
|
57
|
+
<pre><code><r:reader:unless_downloads>...</r:reader:unless_downloads /></code></pre>
|
58
|
+
}
|
59
|
+
tag "reader:unless_downloads" do |tag|
|
60
|
+
tag.expand unless tag.locals.reader.downloads.any?
|
61
|
+
end
|
62
|
+
|
63
|
+
desc %{
|
64
|
+
Cycles through all downloads for the current reader.
|
65
|
+
|
66
|
+
*Usage:*
|
67
|
+
<pre><code><r:reader:downloads:each>...</r:reader:downloads:each></code></pre>
|
68
|
+
}
|
69
|
+
tag 'reader:downloads' do |tag|
|
70
|
+
tag.locals.reader ||= current_reader
|
71
|
+
tag.expand if tag.locals.reader
|
72
|
+
end
|
73
|
+
tag 'reader:downloads:each' do |tag|
|
74
|
+
result = []
|
75
|
+
tag.locals.reader.downloads.each do |download|
|
76
|
+
tag.locals.download = download
|
77
|
+
result << tag.expand
|
78
|
+
end
|
79
|
+
result
|
80
|
+
end
|
81
|
+
|
82
|
+
desc %{
|
83
|
+
The root 'download' tag is not meant to be called directly.
|
84
|
+
All it does is summon a download object so that its fields can be displayed with eg.
|
85
|
+
<pre><code><r:download:url /></code></pre>
|
86
|
+
}
|
87
|
+
|
88
|
+
tag 'download' do |tag|
|
89
|
+
tag.expand
|
90
|
+
# tag.locals.download ||= _get_download(tag)
|
91
|
+
# if tag.locals.download
|
92
|
+
# tag.expand
|
93
|
+
# else
|
94
|
+
# %{No download found with id '#{tag.attr['id']}' or title '#{tag.attr['title']}'}
|
95
|
+
# end
|
96
|
+
end
|
97
|
+
|
98
|
+
desc %{
|
99
|
+
Returns title of current download.
|
100
|
+
|
101
|
+
*Usage:*
|
102
|
+
<pre><code><r:download:title /></code></pre>
|
103
|
+
}
|
104
|
+
tag 'download:title' do |tag|
|
105
|
+
if download = _get_download(tag)
|
106
|
+
download.name
|
107
|
+
end
|
108
|
+
end
|
109
|
+
tag 'download:name' do |tag|
|
110
|
+
if download = _get_download(tag)
|
111
|
+
download.name
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
desc %{
|
116
|
+
Returns description of current download.
|
117
|
+
|
118
|
+
*Usage:*
|
119
|
+
<pre><code><r:download:description /></code></pre>
|
120
|
+
}
|
121
|
+
tag 'download:description' do |tag|
|
122
|
+
if download = _get_download(tag)
|
123
|
+
download.description
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
desc %{
|
128
|
+
Returns the secure url of the current download.
|
129
|
+
|
130
|
+
*Usage:*
|
131
|
+
<pre><code><a href="<r:download:url id="4" />">...</a></code></pre>
|
132
|
+
}
|
133
|
+
tag 'download:url' do |tag|
|
134
|
+
if download = _get_download(tag)
|
135
|
+
download_path(download)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
desc %{
|
140
|
+
Returns a link to the current download.
|
141
|
+
Attributes and enclosed link text are passed through in the usual way.
|
142
|
+
|
143
|
+
*Usage:*
|
144
|
+
<pre><code><r:download:link /></code></pre>
|
145
|
+
}
|
146
|
+
tag 'download:link' do |tag|
|
147
|
+
tag.locals.download = _get_download(tag)
|
148
|
+
options = tag.attr.dup
|
149
|
+
attributes = options.inject('') { |s, (k, v)| s << %{#{k.downcase}="#{v}" } }.strip
|
150
|
+
attributes = " #{attributes}" unless attributes.empty?
|
151
|
+
text = tag.double? ? tag.expand : tag.render('download:title')
|
152
|
+
%{<a href="#{tag.render('download:url')}"#{attributes}>#{text}</a>}
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
private
|
157
|
+
|
158
|
+
def _get_download(tag)
|
159
|
+
download = tag.locals.download
|
160
|
+
download ||= Download.find_by_id(tag.attr.delete('id')) if tag.attr['id']
|
161
|
+
download ||= Download.find_by_title(tag.attr.delete('title')) if tag.attr['title']
|
162
|
+
download
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
data/lib/download_ui.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module DownloadUI
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
|
6
|
+
attr_accessor :download
|
7
|
+
alias_method :downloads, :download
|
8
|
+
|
9
|
+
def load_default_regions_with_download
|
10
|
+
load_default_regions_without_download
|
11
|
+
@download = load_default_download_regions
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method_chain :load_default_regions, :download
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def load_default_download_regions
|
19
|
+
returning OpenStruct.new do |download|
|
20
|
+
download.edit = Radiant::AdminUI::RegionSet.new do |edit|
|
21
|
+
edit.main.concat %w{edit_header edit_form}
|
22
|
+
edit.form.concat %w{edit_title edit_description edit_document edit_access}
|
23
|
+
edit.form_bottom.concat %w{edit_timestamp edit_buttons}
|
24
|
+
end
|
25
|
+
download.index = Radiant::AdminUI::RegionSet.new do |index|
|
26
|
+
index.thead.concat %w{name_header document_header access_header modify_header}
|
27
|
+
index.tbody.concat %w{name_cell document_cell access_cell modify_cell}
|
28
|
+
index.bottom.concat %w{new_button}
|
29
|
+
end
|
30
|
+
download.remove = download.index
|
31
|
+
download.new = download.edit
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
namespace :radiant do
|
2
|
+
namespace :extensions do
|
3
|
+
namespace :downloads do
|
4
|
+
|
5
|
+
desc "Runs the migration of the Downloads extension"
|
6
|
+
task :migrate => :environment do
|
7
|
+
require 'radiant/extension_migrator'
|
8
|
+
if ENV["VERSION"]
|
9
|
+
DownloadsExtension.migrator.migrate(ENV["VERSION"].to_i)
|
10
|
+
else
|
11
|
+
DownloadsExtension.migrator.migrate
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Copies public assets of the Downloads to the instance public/ directory."
|
16
|
+
task :update => :environment do
|
17
|
+
is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
|
18
|
+
puts "Copying assets from DownloadsExtension"
|
19
|
+
Dir[DownloadsExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
|
20
|
+
path = file.sub(DownloadsExtension.root, '')
|
21
|
+
directory = File.dirname(path)
|
22
|
+
mkdir_p RAILS_ROOT + directory
|
23
|
+
cp file, RAILS_ROOT + path
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/* submenu admin */
|
2
|
+
|
3
|
+
#content table.index .node .download {
|
4
|
+
font-size:115%;
|
5
|
+
font-weight:bold;
|
6
|
+
}
|
7
|
+
|
8
|
+
#content table.index .node .download a {
|
9
|
+
color: black;
|
10
|
+
}
|
11
|
+
|
12
|
+
#content .form-area .user select {
|
13
|
+
font-family:Georgia,Palatino,"Times New Roman",Times,serif;
|
14
|
+
font-size:150%;
|
15
|
+
width:60%;
|
16
|
+
}
|
17
|
+
|
18
|
+
#content .form-area p.description {
|
19
|
+
margin-top: 10px;
|
20
|
+
}
|
21
|
+
|
22
|
+
#content .form-area span.formnote {
|
23
|
+
color: #7d796c;
|
24
|
+
font-size: 85%;
|
25
|
+
}
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe DownloadsController do
|
4
|
+
dataset :download_groups
|
5
|
+
|
6
|
+
before do
|
7
|
+
controller.stub!(:request).and_return(request)
|
8
|
+
Page.current_site = sites(:test) if defined? Site
|
9
|
+
request.env["HTTP_REFERER"] = 'http://test.host/referer!'
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "with a protected download" do
|
13
|
+
describe "and no reader" do
|
14
|
+
before do
|
15
|
+
logout_reader
|
16
|
+
get :show, :id => download_id(:grouped)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should redirect to login" do
|
20
|
+
response.should be_redirect
|
21
|
+
response.should redirect_to(reader_login_url)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should set the right return_to url" do
|
25
|
+
session[:return_to].should == request.request_uri
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "and a logged-in reader" do
|
30
|
+
describe "who is not in a permitted group" do
|
31
|
+
before do
|
32
|
+
login_as_reader(:ungrouped)
|
33
|
+
get :show, :id => download_id(:grouped)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should redirect to the permission denied page" do
|
37
|
+
response.should be_success
|
38
|
+
response.should render_template('site/not_allowed')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "who is in a permitted group" do
|
43
|
+
before do
|
44
|
+
login_as_reader(:normal)
|
45
|
+
get :show, :id => download_id(:grouped)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should return an internal redirect" do
|
49
|
+
dl = downloads(:grouped)
|
50
|
+
response.should be_success
|
51
|
+
response.headers.should include('X-Accel-Redirect');
|
52
|
+
response.headers['X-Accel-Redirect'].should == dl.document.path
|
53
|
+
response.headers['Content-Disposition'].should =~ /^attachment/
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "with an ungrouped download" do
|
60
|
+
describe "and no reader" do
|
61
|
+
before do
|
62
|
+
logout_reader
|
63
|
+
get :show, :id => download_id(:grouped)
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should refuse access" do
|
67
|
+
response.should be_redirect
|
68
|
+
response.should redirect_to(reader_login_url)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
class DownloadGroupsDataset < Dataset::Base
|
3
|
+
datasets = [:downloads, :download_readers]
|
4
|
+
datasets << :download_sites if defined? Site
|
5
|
+
uses *datasets
|
6
|
+
|
7
|
+
def load
|
8
|
+
create_group "Normal"
|
9
|
+
create_group "Busy"
|
10
|
+
create_group "Idle"
|
11
|
+
add_downloads_to_group :normal, [:grouped]
|
12
|
+
add_downloads_to_group :busy, [:grouped, :alsogrouped]
|
13
|
+
add_readers_to_group :busy, [:normal, :another]
|
14
|
+
end
|
15
|
+
|
16
|
+
helpers do
|
17
|
+
def create_group(name, att={})
|
18
|
+
group = create_record Group, name.symbolize, group_attributes(att.update(:name => name))
|
19
|
+
end
|
20
|
+
|
21
|
+
def group_attributes(att={})
|
22
|
+
name = att[:name] || "A group"
|
23
|
+
attributes = {
|
24
|
+
:name => name,
|
25
|
+
:description => "Test group"
|
26
|
+
}.merge(att)
|
27
|
+
attributes[:site_id] ||= site_id(:test) if defined? Site
|
28
|
+
attributes
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_readers_to_group(g, rr)
|
33
|
+
g = g.is_a?(Group) ? g : groups(g)
|
34
|
+
g.readers << rr.map{|r| readers(r)}
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_downloads_to_group(g, dd)
|
38
|
+
g = g.is_a?(Group) ? g : groups(g)
|
39
|
+
g.downloads << dd.map{|d| downloads(d)}
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "authlogic/test_case"
|
2
|
+
|
3
|
+
class DownloadReadersDataset < Dataset::Base
|
4
|
+
uses :download_sites if defined? Site
|
5
|
+
|
6
|
+
def load
|
7
|
+
create_reader "Normal"
|
8
|
+
create_reader "Another"
|
9
|
+
create_reader "Ungrouped"
|
10
|
+
end
|
11
|
+
|
12
|
+
helpers do
|
13
|
+
def create_reader(name, attributes={})
|
14
|
+
attributes = reader_attributes(attributes.update(:name => name))
|
15
|
+
reader = create_model Reader, name.symbolize, attributes
|
16
|
+
end
|
17
|
+
|
18
|
+
def reader_attributes(attributes={})
|
19
|
+
name = attributes[:name] || "John Doe"
|
20
|
+
symbol = name.symbolize
|
21
|
+
attributes = {
|
22
|
+
:name => name,
|
23
|
+
:email => "#{symbol}@spanner.org",
|
24
|
+
:login => "#{symbol}@spanner.org",
|
25
|
+
:activated_at => Time.now - 1.week,
|
26
|
+
:password_salt => "golly",
|
27
|
+
:password => 'password',
|
28
|
+
:password_confirmation => 'password'
|
29
|
+
}.merge(attributes)
|
30
|
+
attributes[:site] = sites(:test) if defined? Site
|
31
|
+
attributes
|
32
|
+
end
|
33
|
+
|
34
|
+
def login_as_reader(reader)
|
35
|
+
activate_authlogic
|
36
|
+
login_reader = reader.is_a?(Reader) ? reader : readers(reader)
|
37
|
+
ReaderSession.create(login_reader)
|
38
|
+
login_reader
|
39
|
+
end
|
40
|
+
|
41
|
+
def logout_reader
|
42
|
+
activate_authlogic
|
43
|
+
if session = ReaderSession.find
|
44
|
+
session.destroy
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class DownloadSitesDataset < Dataset::Base
|
2
|
+
uses :pages
|
3
|
+
|
4
|
+
def load
|
5
|
+
create_record Site, :test, :name => 'Test Site', :domain => 'test', :base_domain => 'test.host', :position => 1, :mail_from_name => 'test sender', :mail_from_address => 'sender@spanner.org', :homepage_id => page_id(:home)
|
6
|
+
Page.current_site = sites(:test)
|
7
|
+
end
|
8
|
+
|
9
|
+
end
|