radiant-reader-extension 2.0.0.rc4 → 3.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|