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