radiant-reader-extension 2.0.0.rc4 → 3.0.0.rc3
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/README.md +9 -5
- data/app/controllers/{readers_controller.rb → accounts_controller.rb} +31 -30
- data/app/controllers/groups_controller.rb +35 -0
- data/app/controllers/messages_controller.rb +1 -0
- data/app/controllers/password_resets_controller.rb +6 -6
- data/app/controllers/reader_action_controller.rb +8 -0
- data/app/controllers/reader_activations_controller.rb +3 -2
- data/app/controllers/reader_sessions_controller.rb +6 -2
- data/app/helpers/reader_helper.rb +61 -17
- data/app/models/group.rb +33 -5
- data/app/models/message.rb +7 -4
- data/app/models/message_reader.rb +4 -0
- data/app/models/reader.rb +71 -3
- data/app/models/reader_page.rb +56 -0
- data/app/views/{readers → accounts}/_contributions.html.haml +0 -0
- data/app/views/{readers → accounts}/_controls.html.haml +1 -2
- data/app/views/accounts/_description.html.haml +2 -0
- data/app/views/{readers → accounts}/_extra_controls.html.haml +0 -0
- data/app/views/{readers → accounts}/_flasher.html.haml +0 -0
- data/app/views/{readers → accounts}/_form.html.haml +10 -15
- data/app/views/accounts/_gravatar.html.haml +3 -0
- data/app/views/accounts/_groups.html.haml +9 -0
- data/app/views/accounts/_links.html.haml +12 -0
- data/app/views/accounts/_list.html.haml +17 -0
- data/app/views/{readers → accounts}/_memberships.html.haml +0 -0
- data/app/views/accounts/_profile.html.haml +29 -0
- data/app/views/accounts/_profile_form.html.haml +86 -0
- data/app/views/accounts/_reader.html.haml +10 -0
- data/app/views/accounts/dashboard.html.haml +28 -0
- data/app/views/{readers → accounts}/edit.html.haml +12 -10
- data/app/views/accounts/edit_profile.html.haml +34 -0
- data/app/views/accounts/index.html.haml +23 -0
- data/app/views/{readers → accounts}/login.html.haml +0 -0
- data/app/views/{readers → accounts}/new.html.haml +0 -0
- data/app/views/{readers → accounts}/permission_denied.html.haml +0 -0
- data/app/views/{readers → accounts}/show.html.haml +9 -12
- data/app/views/dashboard/_description.html.haml +3 -0
- data/app/views/dashboard/_directory.html.haml +3 -0
- data/app/views/dashboard/_groups.html.haml +8 -0
- data/app/views/dashboard/_messages.html.haml +11 -0
- data/app/views/dashboard/_profile.html.haml +3 -0
- data/app/views/dashboard/_welcome.html.haml +5 -0
- data/app/views/groups/_all.html.haml +10 -0
- data/app/views/groups/index.html.haml +21 -0
- data/app/views/groups/show.html.haml +31 -0
- data/app/views/messages/show.html.haml +12 -3
- data/app/views/reader_sessions/new.html.haml +1 -1
- data/app/views/shared/_standard_reader_parts.html.haml +9 -3
- data/config/initializers/formats.rb +2 -0
- data/config/initializers/radiant_config.rb +3 -0
- data/config/locales/en.yml +90 -25
- data/config/routes.rb +8 -6
- data/db/migrate/20110707101339_group_slugs.rb +9 -0
- data/db/migrate/20110711150605_snail_addresses.rb +21 -0
- data/db/migrate/20110712081159_directory_permissions.rb +11 -0
- data/db/migrate/20110712141134_name_parts.rb +9 -0
- data/db/migrate/20110728112254_current_login_at.rb +9 -0
- data/lib/grouped_model.rb +16 -12
- data/lib/grouped_page.rb +1 -0
- data/lib/radiant-reader-extension.rb +1 -1
- data/lib/reader_admin_ui.rb +32 -1
- data/lib/reader_tags.rb +119 -52
- data/lib/site_controller_extensions.rb +2 -2
- data/public/stylesheets/sass/reader.sass +49 -0
- data/radiant-reader-extension.gemspec +4 -1
- data/reader_extension.rb +9 -9
- data/spec/controllers/{readers_controller_spec.rb → accounts_controller_spec.rb} +9 -5
- data/spec/controllers/groups_controller_spec.rb +17 -0
- data/spec/controllers/reader_activations_controller_spec.rb +3 -3
- data/spec/datasets/readers_dataset.rb +3 -0
- data/spec/lib/reader_tags_spec.rb +55 -0
- data/spec/matchers/reader_login_system_matcher.rb +2 -2
- data/spec/models/group_spec.rb +6 -0
- data/spec/models/reader_page_spec.rb +106 -0
- metadata +109 -26
- data/app/views/readers/index.html.haml +0 -38
data/lib/reader_tags.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
module ReaderTags
|
2
2
|
include Radiant::Taggable
|
3
3
|
include ReaderHelper
|
4
|
+
include ActionView::Helpers::TextHelper
|
4
5
|
include GroupTags
|
5
6
|
include MessageTags
|
6
7
|
|
7
8
|
class TagError < StandardError; end
|
8
9
|
|
9
|
-
|
10
|
+
### standard reader css and javascript is just a starting point.
|
10
11
|
|
11
12
|
tag 'reader_css' do |tag|
|
12
13
|
%{<link rel="stylesheet" href="/stylesheets/reader.css" media="all" />}
|
@@ -16,15 +17,63 @@ module ReaderTags
|
|
16
17
|
%{<script type="text/javascript" src="/javascripts/reader.js"></script>}
|
17
18
|
end
|
18
19
|
|
20
|
+
### tags displaying the set of readers
|
21
|
+
|
22
|
+
desc %{
|
23
|
+
Cycles through the (paginated) list of readers available for display. You can do this on
|
24
|
+
any page but if it's a ReaderPage you also get some access control and the ability to
|
25
|
+
click through to an individual reader.
|
26
|
+
|
27
|
+
Please note that if you use this tag on a normal radiant page, all registered readers
|
28
|
+
will be displayed, regardless of group-based or other access limitations. You really
|
29
|
+
want to keep this tag for ReaderPages and GroupPages.
|
30
|
+
|
31
|
+
*Usage:*
|
32
|
+
<pre><code><r:readers:each [limit=0] [offset=0] [order="asc|desc"] [by="position|title|..."] [extensions="png|pdf|doc"]>...</r:readers:each></code></pre>
|
33
|
+
}
|
34
|
+
tag 'readers' do |tag|
|
35
|
+
tag.expand
|
36
|
+
end
|
37
|
+
tag 'readers:each' do |tag|
|
38
|
+
tag.locals.readers = get_readers(tag)
|
39
|
+
tag.render('reader_list', tag.attr.dup, &tag.block)
|
40
|
+
end
|
41
|
+
|
42
|
+
# General purpose paginated reader lister. Potentially useful dryness.
|
43
|
+
# Tag.locals.readers must be defined but can be empty.
|
44
|
+
|
45
|
+
tag 'reader_list' do |tag|
|
46
|
+
raise TagError, "r:reader_list: no readers to list" unless tag.locals.readers
|
47
|
+
options = tag.attr.symbolize_keys
|
48
|
+
result = []
|
49
|
+
paging = pagination_find_options(tag)
|
50
|
+
readers = paging ? tag.locals.readers.paginate(paging) : tag.locals.readers.all
|
51
|
+
readers.each do |reader|
|
52
|
+
tag.locals.reader = reader
|
53
|
+
result << tag.expand
|
54
|
+
end
|
55
|
+
if paging && readers.total_pages > 1
|
56
|
+
tag.locals.paginated_list = readers
|
57
|
+
result << tag.render('pagination', tag.attr.dup)
|
58
|
+
end
|
59
|
+
result
|
60
|
+
end
|
61
|
+
|
62
|
+
### Displaying or addressing an individual reader
|
63
|
+
### See also the r:recipient tags for use in email messages.
|
64
|
+
|
19
65
|
desc %{
|
20
66
|
The root 'reader' tag is not meant to be called directly.
|
21
67
|
All it does is summon a reader object so that its fields can be displayed with eg.
|
22
68
|
<pre><code><r:reader:name /></code></pre>
|
23
69
|
|
24
|
-
|
70
|
+
On a ReaderPage, this will be the reader designated by the url.
|
71
|
+
|
72
|
+
Anywhere else, it will be the current reader (ie the one reading), provided
|
73
|
+
we are on an uncached page.
|
25
74
|
}
|
26
75
|
tag 'reader' do |tag|
|
27
|
-
tag.expand if
|
76
|
+
tag.expand if get_reader(tag)
|
28
77
|
end
|
29
78
|
|
30
79
|
[:name, :forename, :email, :description, :login].each do |field|
|
@@ -33,44 +82,8 @@ module ReaderTags
|
|
33
82
|
<pre><code><r:reader:#{field} /></code></pre>
|
34
83
|
}
|
35
84
|
tag "reader:#{field}" do |tag|
|
36
|
-
tag.locals.reader.send(field)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
desc %{
|
41
|
-
Expands if the current reader has been sent any messages.
|
42
|
-
|
43
|
-
<pre><code><r:reader:if_messages>...</r:reader:if_messages /></code></pre>
|
44
|
-
}
|
45
|
-
tag "reader:if_messages" do |tag|
|
46
|
-
tag.expand if tag.locals.reader.messages.any?
|
47
|
-
end
|
48
|
-
|
49
|
-
desc %{
|
50
|
-
Expands if the current reader has not been sent any messages.
|
51
|
-
|
52
|
-
<pre><code><r:reader:unless_messages>...</r:reader:unless_messages /></code></pre>
|
53
|
-
}
|
54
|
-
tag "reader:unless_messages" do |tag|
|
55
|
-
tag.expand unless tag.locals.reader.messages.any?
|
56
|
-
end
|
57
|
-
|
58
|
-
desc %{
|
59
|
-
Loops through the messages that belong to this reader (whether they have been sent or not, so at the moment this may include drafts).
|
60
|
-
|
61
|
-
<pre><code><r:reader:messages:each>...</r:reader:messages:each /></code></pre>
|
62
|
-
}
|
63
|
-
tag "reader:messages" do |tag|
|
64
|
-
tag.locals.messages = tag.locals.reader.messages
|
65
|
-
tag.expand if tag.locals.messages.any?
|
66
|
-
end
|
67
|
-
tag "reader:messages:each" do |tag|
|
68
|
-
result = []
|
69
|
-
tag.locals.messages.each do |message|
|
70
|
-
tag.locals.message = message
|
71
|
-
result << tag.expand
|
85
|
+
tag.locals.reader.send(field) if tag.locals.reader
|
72
86
|
end
|
73
|
-
result
|
74
87
|
end
|
75
88
|
|
76
89
|
desc %{
|
@@ -80,6 +93,7 @@ module ReaderTags
|
|
80
93
|
<pre><code><r:reader:controls /></code></pre>
|
81
94
|
}
|
82
95
|
tag "reader:controls" do |tag|
|
96
|
+
# if there's no reader, the reader: stem will not expand to render this tag.
|
83
97
|
tag.render('reader_welcome')
|
84
98
|
end
|
85
99
|
|
@@ -88,7 +102,7 @@ module ReaderTags
|
|
88
102
|
If there is no reader, this will show a 'login or register' invitation, provided the reader.allow_registration? config entry is true.
|
89
103
|
If you don't want that, use @r:reader:controls@ instead: the reader: prefix means it will only show when a reader is present.
|
90
104
|
|
91
|
-
If this tag appears on a cached page, we return an empty @<div class="remote_controls">@
|
105
|
+
If this tag appears on a cached page, we return an empty @<div class="remote_controls">@ suitable for ajaxing.
|
92
106
|
|
93
107
|
<pre><code><r:reader_welcome /></code></pre>
|
94
108
|
}
|
@@ -97,38 +111,91 @@ module ReaderTags
|
|
97
111
|
%{<div class="remote_controls"></div>}
|
98
112
|
else
|
99
113
|
if tag.locals.reader = Reader.current
|
100
|
-
welcome = %{<span class="greeting"
|
114
|
+
welcome = %{<span class="greeting">#{I18n.t('reader_extension.navigation.greeting', :name => reader.name)}</span> }
|
101
115
|
links = []
|
102
116
|
if tag.locals.reader.activated?
|
103
|
-
links << %{<a href="#{edit_reader_path(tag.locals.reader)}"
|
104
|
-
links << %{<a href="#{reader_path(tag.locals.reader)}"
|
105
|
-
links << %{<a href="/admin"
|
106
|
-
links << %{<a href="#{reader_logout_path}"
|
117
|
+
links << %{<a href="#{edit_reader_path(tag.locals.reader)}">#{I18n.t('reader_extension.navigation.preferences')}</a>}
|
118
|
+
links << %{<a href="#{reader_path(tag.locals.reader)}">#{I18n.t('reader_extension.navigation.account')}</a>}
|
119
|
+
links << %{<a href="/admin">#{I18n.t('reader_extension.navigation.admin')}</a>} if tag.locals.reader.is_user?
|
120
|
+
links << %{<a href="#{reader_logout_path}">#{I18n.t('reader_extension.navigation.log_out')}</a>}
|
107
121
|
else
|
108
|
-
welcome <<
|
122
|
+
welcome << I18n.t('reader_extension.navigation.activate')
|
109
123
|
end
|
110
124
|
%{<div class="controls"><p>} + welcome + links.join(%{<span class="separator"> | </span>}) + %{</p></div>}
|
111
125
|
elsif Radiant::Config['reader.allow_registration?']
|
112
|
-
%{<div class="controls"><p
|
126
|
+
%{<div class="controls"><p>#{I18n.t('reader_extension.navigation.welcome_please_log_in', :login_url => reader_login_url, :register_url => new_reader_url)}</p></div>}
|
113
127
|
end
|
114
128
|
end
|
115
129
|
end
|
116
130
|
|
117
131
|
desc %{
|
118
|
-
Expands
|
132
|
+
Expands if there is a reader and we are on an uncached page.
|
119
133
|
|
120
134
|
<pre><code><r:if_reader><div id="controls"><r:reader:controls /></r:if_reader></code></pre>
|
121
135
|
}
|
122
136
|
tag "if_reader" do |tag|
|
123
|
-
tag.expand if
|
137
|
+
tag.expand if get_reader(tag)
|
124
138
|
end
|
125
139
|
|
126
140
|
desc %{
|
127
|
-
Expands
|
141
|
+
Expands if there is no reader or we are on a cached page.
|
128
142
|
|
129
143
|
<pre><code><r:unless_reader>Please log in</r:unless_reader></code></pre>
|
130
144
|
}
|
131
145
|
tag "unless_reader" do |tag|
|
132
|
-
tag.expand unless
|
146
|
+
tag.expand unless get_reader(tag)
|
147
|
+
end
|
148
|
+
|
149
|
+
desc %{
|
150
|
+
Truncates the contained text or html to the specified length. Unless you supply a
|
151
|
+
html="true" parameter, all html tags will be removed before truncation. You probably
|
152
|
+
don't want to do that: open tags will not be closed and the truncated
|
153
|
+
text length will vary.
|
154
|
+
|
155
|
+
<pre><code>
|
156
|
+
<r:truncated words="30"><r:content part="body" /></r:truncated>
|
157
|
+
<r:truncated chars="100" omission=" (continued)"><r:post:body /></r:truncated>
|
158
|
+
<r:truncated words="100" allow_html="true"><r:reader:description /></r:truncated>
|
159
|
+
</code></pre>
|
160
|
+
}
|
161
|
+
tag "truncated" do |tag|
|
162
|
+
content = tag.expand
|
163
|
+
tag.attr['words'] ||= tag.attr['length']
|
164
|
+
omission = tag.attr['omission'] || '…'
|
165
|
+
content = scrub_html(content) unless tag.attr['allow_html'] == 'true'
|
166
|
+
if tag.attr['chars']
|
167
|
+
truncate(content, :length => tag.attr['chars'].to_i, :omission => omission)
|
168
|
+
else
|
169
|
+
truncate_words(content, :length => tag.attr['words'].to_i, :omission => omission) # defined in ReaderHelper
|
170
|
+
end
|
133
171
|
end
|
172
|
+
|
173
|
+
deprecated_tag "truncate", :substitute => "truncated"
|
174
|
+
|
175
|
+
private
|
176
|
+
|
177
|
+
def get_reader(tag)
|
178
|
+
tag.locals.reader ||= if tag.attr['id']
|
179
|
+
Reader.find_by_id(tag.attr['id'].to_i)
|
180
|
+
elsif tag.locals.page.respond_to? :reader
|
181
|
+
tag.locals.page.reader
|
182
|
+
elsif !tag.locals.page.cache?
|
183
|
+
Reader.current
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def get_readers(tag)
|
188
|
+
attr = tag.attr.symbolize_keys
|
189
|
+
readers = tag.locals.page.respond_to?(:reader) ? tag.locals.page.readers : Reader.scoped({})
|
190
|
+
readers = readers.in_group(group) if group = attr[:group]
|
191
|
+
by = attr[:by] || 'name'
|
192
|
+
order = attr[:order] || 'ASC'
|
193
|
+
readers = readers.scoped({
|
194
|
+
:order => "#{by} #{order.upcase}",
|
195
|
+
:limit => attr[:limit] || nil,
|
196
|
+
:offset => attr[:offset] || nil
|
197
|
+
})
|
198
|
+
readers
|
199
|
+
end
|
200
|
+
|
134
201
|
end
|
@@ -7,13 +7,13 @@ module SiteControllerExtensions
|
|
7
7
|
|
8
8
|
def find_page_with_group_check(url)
|
9
9
|
page = find_page_without_group_check(url)
|
10
|
-
raise
|
10
|
+
raise ReaderError::AccessDenied if page && !page.visible_to?(current_reader)
|
11
11
|
page
|
12
12
|
end
|
13
13
|
|
14
14
|
def show_page_with_group_check
|
15
15
|
show_page_without_group_check
|
16
|
-
rescue
|
16
|
+
rescue ReaderError::AccessDenied
|
17
17
|
if current_reader
|
18
18
|
flash[:error] = t("reader_extension.access_denied")
|
19
19
|
redirect_to reader_permission_denied_url
|
@@ -122,3 +122,52 @@ form.friendly
|
|
122
122
|
color: white
|
123
123
|
text-decoration: none
|
124
124
|
|
125
|
+
.dashboard_module
|
126
|
+
margin-top: 2em
|
127
|
+
&:first-child
|
128
|
+
margin-top: 0
|
129
|
+
ul
|
130
|
+
margin: 1em 0
|
131
|
+
padding-left: 16px
|
132
|
+
h3:first-child
|
133
|
+
margin-top: 0
|
134
|
+
|
135
|
+
address
|
136
|
+
width: 75%
|
137
|
+
border: 1px solid $paler
|
138
|
+
padding: 1em
|
139
|
+
margin: 1em -1em
|
140
|
+
+border-radius(5px)
|
141
|
+
|
142
|
+
a.vcard
|
143
|
+
padding-left: 25px
|
144
|
+
background: transparent url(/images/furniture/vcard_tiny.png) no-repeat 0 3px
|
145
|
+
|
146
|
+
h3.vcard
|
147
|
+
padding-left: 40px
|
148
|
+
background: transparent url(/images/furniture/vcard.png) no-repeat 0 3px
|
149
|
+
|
150
|
+
a.mailto
|
151
|
+
color: $mid
|
152
|
+
|
153
|
+
.reader
|
154
|
+
margin-bottom: 1em
|
155
|
+
h2
|
156
|
+
margin-bottom: 0
|
157
|
+
.context
|
158
|
+
margin-top: 0
|
159
|
+
|
160
|
+
.column
|
161
|
+
float: left
|
162
|
+
width: 45%
|
163
|
+
margin-right: 3%
|
164
|
+
|
165
|
+
ul.groups
|
166
|
+
padding: 0
|
167
|
+
margin: 0 0 1em 0
|
168
|
+
li
|
169
|
+
margin-right: 1em
|
170
|
+
display: inline
|
171
|
+
|
172
|
+
.cleared
|
173
|
+
clear: left
|
@@ -12,10 +12,13 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.summary = RadiantReaderExtension::SUMMARY
|
13
13
|
s.description = RadiantReaderExtension::DESCRIPTION
|
14
14
|
|
15
|
-
s.add_dependency 'radiant-layouts-extension', "~>
|
15
|
+
s.add_dependency 'radiant-layouts-extension', "~> 1.1.3"
|
16
16
|
s.add_dependency 'radiant-mailer_layouts-extension', "~> 0.1.1"
|
17
17
|
s.add_dependency 'authlogic', "~> 2.1.6"
|
18
18
|
s.add_dependency 'sanitize', "~> 2.0.1"
|
19
|
+
s.add_dependency 'snail', "~> 0.5.5"
|
20
|
+
s.add_dependency 'vcard', "~> 0.1.1"
|
21
|
+
s.add_dependency 'fastercsv', "~> 1.5.4"
|
19
22
|
|
20
23
|
ignores = if File.exist?('.gitignore')
|
21
24
|
File.read('.gitignore').split("\n").inject([]) {|a,p| a + Dir[p] }
|
data/reader_extension.rb
CHANGED
@@ -7,8 +7,11 @@ class ReaderExtension < Radiant::Extension
|
|
7
7
|
url RadiantReaderExtension::URL
|
8
8
|
|
9
9
|
extension_config do |config|
|
10
|
-
config.gem
|
11
|
-
config.gem 'sanitize'
|
10
|
+
config.gem 'authlogic', :version => "~> 2.1.6"
|
11
|
+
config.gem 'sanitize', :version => "~> 2.0.1"
|
12
|
+
config.gem 'snail', :version => "~> 0.5.5"
|
13
|
+
config.gem 'vcard', :version => "~> 0.1.1"
|
14
|
+
config.gem 'fastercsv', :version => "~> 1.5.4"
|
12
15
|
end
|
13
16
|
|
14
17
|
migrate_from 'Reader Group', 20110214101339
|
@@ -37,7 +40,7 @@ class ReaderExtension < Radiant::Extension
|
|
37
40
|
add_item("Settings", "/admin/readers/reader_configuration")
|
38
41
|
end
|
39
42
|
tab("Settings") do
|
40
|
-
add_item("
|
43
|
+
add_item("Readers", "/admin/readers/reader_configuration")
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
@@ -46,11 +49,8 @@ class ReaderExtension < Radiant::Extension
|
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
49
|
-
module
|
50
|
-
class
|
51
|
-
def initialize(message = "Sorry:
|
52
|
-
end
|
53
|
-
class PermissionDenied < Exception
|
54
|
-
def initialize(message = "Sorry: you don't have access to that"); super end
|
52
|
+
module ReaderError
|
53
|
+
class AccessDenied < StandardError
|
54
|
+
def initialize(message = "Sorry: you have to log in to see that"); super end
|
55
55
|
end
|
56
56
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe AccountsController do
|
4
4
|
dataset :readers
|
5
5
|
|
6
6
|
before do
|
@@ -32,8 +32,12 @@ describe ReadersController do
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
describe "listing readers" do
|
36
|
+
it "should respond to csv requests"
|
37
|
+
it "should respond to vcard requests"
|
38
|
+
end
|
39
|
+
|
35
40
|
describe "with a registration" do
|
36
|
-
|
37
41
|
describe "that validates" do
|
38
42
|
before do
|
39
43
|
session[:email_field] = 'gibberish'
|
@@ -115,11 +119,11 @@ describe ReadersController do
|
|
115
119
|
end
|
116
120
|
|
117
121
|
it "should route '/account' to my account" do
|
118
|
-
params_from(:get, '/account').should == {:controller => '
|
122
|
+
params_from(:get, '/account').should == {:controller => 'accounts', :action => 'edit'}
|
119
123
|
end
|
120
124
|
|
121
125
|
it "should route '/profile' to my account" do
|
122
|
-
params_from(:get, '/profile').should == {:controller => '
|
126
|
+
params_from(:get, '/profile').should == {:controller => 'accounts', :action => 'show'}
|
123
127
|
end
|
124
128
|
|
125
129
|
it "should consent to show another reader page" do
|
@@ -178,7 +182,7 @@ describe ReadersController do
|
|
178
182
|
|
179
183
|
it "should redirect to the reader page" do
|
180
184
|
response.should be_redirect
|
181
|
-
response.should redirect_to(
|
185
|
+
response.should redirect_to(dashboard_url)
|
182
186
|
end
|
183
187
|
|
184
188
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe GroupsController do
|
4
|
+
dataset :readers
|
5
|
+
|
6
|
+
before do
|
7
|
+
controller.stub!(:request).and_return(request)
|
8
|
+
Page.current_site = sites(:test) if defined? Site
|
9
|
+
Radiant::Config['reader.allow_registration?'] = true
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "listing groups" do
|
13
|
+
it "should respond to csv requests"
|
14
|
+
it "should respond to vcard requests"
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -21,9 +21,9 @@ describe ReaderActivationsController do
|
|
21
21
|
@reader.activated_at.should be_close((Time.now).utc, 1.minute)
|
22
22
|
end
|
23
23
|
|
24
|
-
it "should
|
25
|
-
response.should
|
26
|
-
response.should
|
24
|
+
it "should redirect to the dashboard" do
|
25
|
+
response.should be_redirect
|
26
|
+
response.should redirect_to(dashboard_url)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -5,6 +5,8 @@ class ReadersDataset < Dataset::Base
|
|
5
5
|
uses :users, :pages
|
6
6
|
|
7
7
|
def load
|
8
|
+
create_page "People", :slug => "directory", :class_name => 'ReaderPage'
|
9
|
+
|
8
10
|
create_reader "Normal"
|
9
11
|
create_reader "Another"
|
10
12
|
create_reader "Visible"
|
@@ -90,6 +92,7 @@ From <r:sender:name />
|
|
90
92
|
def default_group_attributes(name="Group")
|
91
93
|
attributes = {
|
92
94
|
:name => name,
|
95
|
+
:slug => name.downcase,
|
93
96
|
:description => "#{name} group"
|
94
97
|
}
|
95
98
|
attributes[:site_id] ||= site_id(:test) if defined? Site
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe "Reader Tags" do
|
4
|
+
dataset :readers
|
5
|
+
|
6
|
+
let(:person){ readers(:normal) }
|
7
|
+
let(:another){ readers(:another) }
|
8
|
+
let(:page){ pages(:first) }
|
9
|
+
|
10
|
+
describe "r:readers tags" do
|
11
|
+
subject { page }
|
12
|
+
it { should render(%{<r:readers:each><r:reader:name /></r:readers:each>}).as(Reader.all.map(&:name).join('')) }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "r:reader tags" do
|
16
|
+
describe "on a ReaderPage" do
|
17
|
+
before do
|
18
|
+
@page = pages(:people)
|
19
|
+
@page.stub!(:reader).and_return(person)
|
20
|
+
end
|
21
|
+
subject { @page }
|
22
|
+
it { should render(%{<r:reader:name />}).as(person.name) }
|
23
|
+
it { should render(%{<r:if_reader>hello</r:if_reader>}).as('hello') }
|
24
|
+
it { should render(%{<r:unless_reader>hello</r:unless_reader>}).as('') }
|
25
|
+
[:name, :forename, :email, :description, :login].each { |field| it { should render(%{<r:reader:#{field} id="#{person.id}" />}).as(person.send(field)) } }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "on an uncached page" do
|
29
|
+
before do
|
30
|
+
@uncached_page = pages(:another)
|
31
|
+
@uncached_page.stub!(:cache?).and_return(false)
|
32
|
+
Reader.stub!(:current).and_return(readers(:another))
|
33
|
+
end
|
34
|
+
subject { @uncached_page }
|
35
|
+
it { should render(%{<r:reader:name />}).as(another.name) }
|
36
|
+
it { should_not render(%{<r:reader:welcome />}).as('') }
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "on a cached page" do
|
40
|
+
subject { page }
|
41
|
+
it { should render(%{<r:reader:name />}).as('') }
|
42
|
+
it { should render(%{<r:reader:welcome />}).as('') }
|
43
|
+
it { should render(%{<r:reader_welcome />}).as(%{<div class="remote_controls"></div>}) }
|
44
|
+
[:name, :forename, :email, :description, :login].each { |field| it { should render(%{<r:reader id="#{another.id}"><r:#{field} /></r:reader>}).as(another.send(field)) } }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "utility tags" do
|
49
|
+
subject { page }
|
50
|
+
it { should render(%{<r:truncated chars="50">All happy families are alike; each unhappy family is unhappy in its own way.</r:truncated>}).as(' All happy families are alike; each unhapp…') }
|
51
|
+
it { should render(%{<r:truncated words="5" omission="">All happy families are alike; each unhappy family is unhappy in its own way.</r:truncated>}).as('All happy families are alike;') }
|
52
|
+
it { should render(%{<r:truncated words="5" allow_html="true" omission=" (tbc)">All <em>happy families</em> are alike; each unhappy family is unhappy in its own way.</r:truncated>}).as('All <em>happy families</em> are alike; (tbc)') }
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -10,13 +10,13 @@ module Spec
|
|
10
10
|
proc.call
|
11
11
|
@response = @example.response
|
12
12
|
@was_redirect = @response.redirect?
|
13
|
-
@was_redirect_to_login = @response.redirect_url_match?("/
|
13
|
+
@was_redirect_to_login = @response.redirect_url_match?("/login")
|
14
14
|
@was_redirect && @was_redirect_to_login
|
15
15
|
end
|
16
16
|
|
17
17
|
def failure_message
|
18
18
|
if @was_redirect
|
19
|
-
"expected to redirect to /
|
19
|
+
"expected to redirect to /login but redirected to #{@response.redirect_url}"
|
20
20
|
else
|
21
21
|
"expected to require reader login but did not redirect"
|
22
22
|
end
|
data/spec/models/group_spec.rb
CHANGED
@@ -43,4 +43,10 @@ describe Group do
|
|
43
43
|
group.pages.any?.should be_true
|
44
44
|
group.pages.size.should == 2
|
45
45
|
end
|
46
|
+
|
47
|
+
it "should give itself a slug if none is present" do
|
48
|
+
g = Group.new(:name => 'testy group')
|
49
|
+
g.valid?.should be_true
|
50
|
+
g.slug.should == 'testy-group'
|
51
|
+
end
|
46
52
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe ReaderPage do
|
4
|
+
dataset :readers
|
5
|
+
activate_authlogic
|
6
|
+
|
7
|
+
let(:page) { Page.find_by_path('/directory') }
|
8
|
+
let(:page_with_group) { Page.find_by_path('/directory/normal') }
|
9
|
+
let(:page_with_reader) { Page.find_by_path("/directory/#{reader_id(:normal)}") }
|
10
|
+
let(:page_with_reader_and_group) { Page.find_by_path("/directory/special/#{reader_id(:another)}") }
|
11
|
+
|
12
|
+
it "should be a Page" do
|
13
|
+
page.is_a?(Page).should be_true
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "reading parameters" do
|
17
|
+
before do
|
18
|
+
Radiant.config['readers.public?'] = true
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should interrupt the find_by_path cascade" do
|
22
|
+
page.should == pages(:people)
|
23
|
+
page.should == pages(:people)
|
24
|
+
page_with_reader_and_group.is_a?(ReaderPage).should be_true
|
25
|
+
page.reader.should be_nil
|
26
|
+
page.group.should be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should read a group slug parameter" do
|
30
|
+
page_with_group.group.should == groups(:normal)
|
31
|
+
page_with_reader_and_group.group.should == groups(:special)
|
32
|
+
page_with_reader.group.should be_nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should read a reader id parameter" do
|
36
|
+
page_with_reader.reader.should == readers(:normal)
|
37
|
+
page_with_reader_and_group.reader.should == readers(:another)
|
38
|
+
page_with_group.reader.should be_nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should take exception to mismatched reader and group" do
|
42
|
+
lambda { Page.find_by_path("/directory/special/#{reader_id(:ungrouped)}") }.should raise_error(ActiveRecord::RecordNotFound)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should list readers and groups" do
|
46
|
+
page.readers.should =~ Reader.all
|
47
|
+
page.groups.should =~ Group.all
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "when the readership is private" do
|
52
|
+
before do
|
53
|
+
Radiant.config['readers.public?'] = false
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "and no reader is logged in" do
|
57
|
+
before do
|
58
|
+
logout_reader
|
59
|
+
Reader.current = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should deny access completely" do
|
63
|
+
lambda { Page.find_by_path("/directory") }.should raise_error(ReaderError::AccessDenied)
|
64
|
+
lambda { Page.find_by_path("/directory/normal") }.should raise_error(ReaderError::AccessDenied)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "and a reader is logged in" do
|
69
|
+
before do
|
70
|
+
Reader.current = login_as_reader(readers(:normal))
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should allow access to the reader list" do
|
74
|
+
lambda { Page.find_by_path("/directory") }.should_not raise_error
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should allow access to a group" do
|
78
|
+
lambda { Page.find_by_path("/directory/normal").group.should == groups(:normal) }.should_not raise_error
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should allow access to a reader" do
|
82
|
+
lambda { Page.find_by_path("/directory/#{reader_id(:normal)}").reader.should == readers(:normal) }.should_not raise_error
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "but confined to his groups" do
|
86
|
+
before do
|
87
|
+
Radiant.config['readers.confine_to_groups?'] = true
|
88
|
+
Reader.current = login_as_reader(readers(:normal))
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should allow access only to readers with group overlap" do
|
92
|
+
lambda { Page.find_by_path("/directory/#{reader_id(:inactive)}").reader.should == readers(:inactive) }.should_not raise_error
|
93
|
+
lambda { Page.find_by_path("/directory/#{reader_id(:another)}") }.should raise_error
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should allow access only to groups to which the reader belongs" do
|
97
|
+
lambda { Page.find_by_path("/directory/normal") }.should_not raise_error
|
98
|
+
lambda { Page.find_by_path("/directory/special") }.should raise_error(ReaderError::AccessDenied)
|
99
|
+
Page.find_by_path("/directory").groups.should =~ [groups(:normal), groups(:homed)]
|
100
|
+
Page.find_by_path("/directory").readers.should =~ (groups(:normal).readers + groups(:homed).readers).uniq
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|