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.
Files changed (76) hide show
  1. data/README.md +9 -5
  2. data/app/controllers/{readers_controller.rb → accounts_controller.rb} +31 -30
  3. data/app/controllers/groups_controller.rb +35 -0
  4. data/app/controllers/messages_controller.rb +1 -0
  5. data/app/controllers/password_resets_controller.rb +6 -6
  6. data/app/controllers/reader_action_controller.rb +8 -0
  7. data/app/controllers/reader_activations_controller.rb +3 -2
  8. data/app/controllers/reader_sessions_controller.rb +6 -2
  9. data/app/helpers/reader_helper.rb +61 -17
  10. data/app/models/group.rb +33 -5
  11. data/app/models/message.rb +7 -4
  12. data/app/models/message_reader.rb +4 -0
  13. data/app/models/reader.rb +71 -3
  14. data/app/models/reader_page.rb +56 -0
  15. data/app/views/{readers → accounts}/_contributions.html.haml +0 -0
  16. data/app/views/{readers → accounts}/_controls.html.haml +1 -2
  17. data/app/views/accounts/_description.html.haml +2 -0
  18. data/app/views/{readers → accounts}/_extra_controls.html.haml +0 -0
  19. data/app/views/{readers → accounts}/_flasher.html.haml +0 -0
  20. data/app/views/{readers → accounts}/_form.html.haml +10 -15
  21. data/app/views/accounts/_gravatar.html.haml +3 -0
  22. data/app/views/accounts/_groups.html.haml +9 -0
  23. data/app/views/accounts/_links.html.haml +12 -0
  24. data/app/views/accounts/_list.html.haml +17 -0
  25. data/app/views/{readers → accounts}/_memberships.html.haml +0 -0
  26. data/app/views/accounts/_profile.html.haml +29 -0
  27. data/app/views/accounts/_profile_form.html.haml +86 -0
  28. data/app/views/accounts/_reader.html.haml +10 -0
  29. data/app/views/accounts/dashboard.html.haml +28 -0
  30. data/app/views/{readers → accounts}/edit.html.haml +12 -10
  31. data/app/views/accounts/edit_profile.html.haml +34 -0
  32. data/app/views/accounts/index.html.haml +23 -0
  33. data/app/views/{readers → accounts}/login.html.haml +0 -0
  34. data/app/views/{readers → accounts}/new.html.haml +0 -0
  35. data/app/views/{readers → accounts}/permission_denied.html.haml +0 -0
  36. data/app/views/{readers → accounts}/show.html.haml +9 -12
  37. data/app/views/dashboard/_description.html.haml +3 -0
  38. data/app/views/dashboard/_directory.html.haml +3 -0
  39. data/app/views/dashboard/_groups.html.haml +8 -0
  40. data/app/views/dashboard/_messages.html.haml +11 -0
  41. data/app/views/dashboard/_profile.html.haml +3 -0
  42. data/app/views/dashboard/_welcome.html.haml +5 -0
  43. data/app/views/groups/_all.html.haml +10 -0
  44. data/app/views/groups/index.html.haml +21 -0
  45. data/app/views/groups/show.html.haml +31 -0
  46. data/app/views/messages/show.html.haml +12 -3
  47. data/app/views/reader_sessions/new.html.haml +1 -1
  48. data/app/views/shared/_standard_reader_parts.html.haml +9 -3
  49. data/config/initializers/formats.rb +2 -0
  50. data/config/initializers/radiant_config.rb +3 -0
  51. data/config/locales/en.yml +90 -25
  52. data/config/routes.rb +8 -6
  53. data/db/migrate/20110707101339_group_slugs.rb +9 -0
  54. data/db/migrate/20110711150605_snail_addresses.rb +21 -0
  55. data/db/migrate/20110712081159_directory_permissions.rb +11 -0
  56. data/db/migrate/20110712141134_name_parts.rb +9 -0
  57. data/db/migrate/20110728112254_current_login_at.rb +9 -0
  58. data/lib/grouped_model.rb +16 -12
  59. data/lib/grouped_page.rb +1 -0
  60. data/lib/radiant-reader-extension.rb +1 -1
  61. data/lib/reader_admin_ui.rb +32 -1
  62. data/lib/reader_tags.rb +119 -52
  63. data/lib/site_controller_extensions.rb +2 -2
  64. data/public/stylesheets/sass/reader.sass +49 -0
  65. data/radiant-reader-extension.gemspec +4 -1
  66. data/reader_extension.rb +9 -9
  67. data/spec/controllers/{readers_controller_spec.rb → accounts_controller_spec.rb} +9 -5
  68. data/spec/controllers/groups_controller_spec.rb +17 -0
  69. data/spec/controllers/reader_activations_controller_spec.rb +3 -3
  70. data/spec/datasets/readers_dataset.rb +3 -0
  71. data/spec/lib/reader_tags_spec.rb +55 -0
  72. data/spec/matchers/reader_login_system_matcher.rb +2 -2
  73. data/spec/models/group_spec.rb +6 -0
  74. data/spec/models/reader_page_spec.rb +106 -0
  75. metadata +109 -26
  76. 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
- # I need to find a better way to do this, but this gives a starting point
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
- This will only work on an access-protected page and should never be used on a cached page, because everyone will see it.
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 !tag.locals.page.cache? && tag.locals.reader = Reader.current
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">@ into which you can drop whatever you like.
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">Hello #{tag.render('reader:name')}.</span> }
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)}">Preferences</a>}
104
- links << %{<a href="#{reader_path(tag.locals.reader)}">Your page</a>}
105
- links << %{<a href="/admin">Admin</a>} if tag.locals.reader.is_user?
106
- links << %{<a href="#{reader_logout_path}">Log out</a>}
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 << "Please check your email and activate your account."
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><span class="greeting">Welcome!</span> To take part, please <a href="#{reader_login_path}">log in</a> or <a href="#{reader_register_path}">register</a>.</p></div>}
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 only if there is a reader and we are on an uncached page.
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 !tag.locals.page.cache? && tag.locals.reader = Reader.current
137
+ tag.expand if get_reader(tag)
124
138
  end
125
139
 
126
140
  desc %{
127
- Expands only if there is no reader or we are not on an uncached page.
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 Reader.current && !tag.locals.page.cache?
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'] || '&hellip;'
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 ReaderGroup::PermissionDenied if page && !page.visible_to?(current_reader)
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 ReaderGroup::PermissionDenied
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', "~> 0.9.1"
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 "authlogic"
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("Reader", "/admin/readers/reader_configuration")
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 ReaderGroup
50
- class Exception < StandardError
51
- def initialize(message = "Sorry: group problem"); super end
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 ReadersController do
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 => 'readers', :action => 'edit'}
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 => 'readers', :action => 'show'}
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(reader_url(@reader))
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 show the show page" do
25
- response.should be_success
26
- response.should render_template("show")
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&hellip;') }
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?("/readers/login")
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 /readers/login but redirected to #{@response.redirect_url}"
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
@@ -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