radiant-reader-extension 3.0.5 → 3.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -8,7 +8,7 @@ The visitors are referred to as 'readers' here. Readers never see the admin inte
8
8
 
9
9
  ## Status
10
10
 
11
- Compatible with radiant 1, which isn't out yet. You can use radiant edge to try this out. Expect a few point releases as radiant 1 is finalised.
11
+ Compatible with radiant 1, which is nearly out. You can use radiant edge to try this out. Expect a few point releases as radiant 1 is finalised.
12
12
 
13
13
  Multi-site compatibility is currently missing but will follow as soon as I can add a better scoping engine to radiant core.
14
14
 
@@ -41,11 +41,11 @@ and then you can bring over assets and create data tables:
41
41
 
42
42
  ## Configuration
43
43
 
44
- All the main configuration settings can now be managed through the `settings > readers` configuration pane. THey have sensible defaults but you will need to choose a layout for reader-administration views and supply the name and email address that messages should appear to come from.
44
+ All the main configuration settings can now be managed through the `settings > readers` configuration pane. They have sensible defaults but you will need to choose a layout for reader-administration views and supply the name and email address that messages should appear to come from.
45
45
 
46
- ## Usage
46
+ ## Readers
47
47
 
48
- This is primarily a framework and its main purpose is to take care of the tedious minutiae of account-management. The basic reader framework provides for:
48
+ This is primarily a framework and its main purpose is to take care of the dull minutiae of account-management. The basic reader framework provides for:
49
49
 
50
50
  * registration
51
51
  * honeypot spam trap
@@ -59,6 +59,8 @@ This is primarily a framework and its main purpose is to take care of the tediou
59
59
  * administrative email messages for welcome, invitation, etc
60
60
  * ad-hoc email messages to some or all readers
61
61
 
62
+ ## Reader groups
63
+
62
64
  The extension also includes a group-based access control mechanism. You can organise your readers into groups (either by invitation or by public subscription) and any resource (eg a page) associated with one or more groups is visible only to their members. Anyone else attempting to access the page will be prompted to log in (or register, if registration is permitted).
63
65
 
64
66
  You can use the group mechanism in a simple way just to create self-selected interest groups, or you can disable public registration and use the full group-hierarchical functionality to provide a very secure system of controlled access to selected resources.
@@ -120,7 +122,7 @@ There are four levels of directory visibility, and the behaviour of your site is
120
122
  * *none* is the default. No reader details are shown to anybody.
121
123
  * *public* means that anyone can see the directory. Individual readers can still opt out, but this is intended for public directory services with the expectation that people want to be shown.
122
124
  * *private* means that only logged in readers can see the directory. Useful for closed groups and works well as an internal directory for an organisation or team.
123
- * *grouped* means that only logged in people can see the directory and that they can only see the people with whom they share a group. Useful for more complex authorization requirements but also for sites that have a privileged core group and unprivileged guests.
125
+ * *grouped* means that only logged in people can see the directory and that they can only see those people with whom they share a group. Useful for more complex authorization requirements but also for sites that have a privileged core group and unprivileged guests.
124
126
 
125
127
  ## Using readers in other extensions
126
128
 
@@ -24,7 +24,7 @@ class GroupsController < ReaderActionController
24
24
  private
25
25
 
26
26
  def get_group_or_groups
27
- @groups = Group.roots.visible_to(current_reader)
27
+ @groups = current_reader.all_visible_groups
28
28
  @group = Group.find(params[:id]) if params[:id]
29
29
  end
30
30
 
@@ -34,16 +34,4 @@ private
34
34
  end
35
35
  end
36
36
 
37
- def generate_csv(readers=[])
38
- columns = %w{forename surname email phone mobile postal_address}
39
- table = FasterCSV.generate do |csv|
40
- csv << columns.map { |f| t("activerecord.attributes.reader.#{f}") }
41
- readers.each { |r| csv << columns.map{ |f| r.send(f.to_sym) } }
42
- end
43
- end
44
-
45
- def generate_vcard(readers=[])
46
- readers.map(&:vcard).join("\n")
47
- end
48
-
49
37
  end
@@ -11,6 +11,13 @@
11
11
  = f.text_field :honorific, :class => 'standard'
12
12
  %span.formnote= t('reader_extension.form_notes.account.honorific')
13
13
 
14
+ %p
15
+ = f.label :email, nil, :class => 'required'
16
+ %br
17
+ = f.text_field :email, :class => 'standard'
18
+ %br
19
+ %span.formnote= t('reader_extension.form_notes.account.email')
20
+
14
21
  %p
15
22
  = f.label :phone, nil, :class => 'optional'
16
23
  %br
@@ -1,8 +1,14 @@
1
- // This is going to be a tree of checkboxes with some
2
- // javascript to make visible the inheritance of permission.
3
- // It will be used on pages, messages and any other group-linkable object.
1
+ - chooser ||= @page
2
+ - if chooser
3
+ - root ||= nil
4
+ - disabled ||= false
5
+ - branches = root ? root.children : Group.roots
4
6
 
5
- - Group.roots.each do |group|
6
- = f.check_box :group_ids, {}, group.id
7
- = f.label :group_ids, group.name, :class => 'checkbox'
8
- %br
7
+ %ul{:class => root ? '' : 'tree'}
8
+ - branches.each do |group|
9
+ %li
10
+ - checked = chooser.has_group?(group)
11
+ = check_box_tag 'group_ids', group.id, checked, :id => "group_ids_#{group.id}", :class => "treebox", :disabled => disabled
12
+ %label{:for => "group_ids_#{group.id}", :class => 'checkbox'}
13
+ = group.name
14
+ = render :partial => 'admin/groups/chooser', :object => chooser, :locals => {:root => group, :disabled => checked}
@@ -34,17 +34,17 @@
34
34
  - delivery.function do
35
35
  - if @message.administrative?
36
36
  %p
37
- - if @message.group
38
- = t("reader_extension.belongs_to_group", :name => @message.group.name, :href => admin_group_url(@message.group))
37
+ - if @message.groups.any?
38
+ = t("reader_extension.belongs_to_groups", :links => @message.groups.map{ |g| link_to g.name, admin_group_url(g) }.to_sentence, :count => @message.groups.count)
39
39
  = t("reader_extension.message_group_administrative")
40
- = t("reader_extension.message_function.#{@message.function}")
41
40
  - else
42
41
  = t("reader_extension.message_administrative")
43
- = t("reader_extension.message_function.#{@message.function}")
42
+ = t("reader_extension.message_function.#{@message.function}")
44
43
  - else
45
44
  %p
46
45
  = t("reader_extension.message_adhoc")
47
- = t("reader_extension.message_group_adhoc", :name => @message.group.name, :href => admin_group_url(@message.group))
46
+ - if @message.groups.any?
47
+ = t("reader_extension.message_group_adhoc", :links => @message.groups.map{|g| link_to g.name, admin_group_url(g)}.to_sentence, :count => @message.groups.count)
48
48
 
49
49
  - delivery.options do
50
50
  - unless @message.administrative?
@@ -0,0 +1,7 @@
1
+ - page ||= @current_node
2
+ %td.access
3
+ - if page.visible?
4
+ =t('reader_extension.access_open')
5
+ - else
6
+ %span.access.draft_status{:title => t('reader_extension.access_restricted_to', :groups => page.groups.map(&:name).to_sentence)}
7
+ =t('reader_extension.access_restricted')
@@ -0,0 +1,2 @@
1
+ - include_stylesheet "admin/reader_group"
2
+ %th.access= t('reader_extension.access')
@@ -0,0 +1,12 @@
1
+ #groups_popup.popup{:style => "display: none"}
2
+ #groups_busy.busy{:style => "display: none"}= image('spinner.gif', :alt => "")
3
+ .popup_title
4
+ = t('reader_extension.access_control')
5
+ %p
6
+ = t('reader_extension.page_access_explanation')
7
+ %form.group_selection
8
+ = render :partial => 'admin/groups/chooser', :object => @page
9
+ .buttons
10
+ = submit_tag t('reader_extension.set_access'), :class=>'button', :id=>'add_page_field_button'
11
+ = t('or')
12
+ = link_to_function t('cancel'), "$(this).closePopup()", :class=>"cancel"
@@ -1,7 +1,15 @@
1
+ - include_stylesheet 'admin/reader_group'
2
+ - include_javascript 'admin/reader'
3
+
1
4
  - groups = Group.find(:all)
2
5
  - if groups.any?
3
- %p
4
- = t('reader_extension.permitted_groups')
5
- %br
6
- - fields_for @page do |f|
7
- = render :partial => 'admin/groups/chooser', :locals => {:f => f}
6
+ %p.access
7
+ %label
8
+ = t('reader_extension.access')
9
+ - if @page.visible?
10
+ = link_to t('reader_extension.access_open'), '#groups_popup', :class => 'popup unrestricted', :id => 'group_status_flag'
11
+ - else
12
+ = link_to t('reader_extension.access_restricted'), '#groups_popup', :class => 'popup restricted', :id => 'group_status_flag'
13
+ - fields_for @page do |f|
14
+ = f.hidden_field :group_ids
15
+
@@ -8,11 +8,20 @@
8
8
  %tr
9
9
  - render_region :thead do |thead|
10
10
  - thead.title_header do
11
- %th.reader Name / Login
11
+ %th.reader
12
+ = t('reader_extension.name')
13
+ - thead.email_header do
14
+ %th.email
15
+ = t('reader_extension.email')
16
+ - thead.groups_header do
17
+ %th.reader_groups
18
+ = t('reader_extension.groups')
12
19
  - thead.description_header do
13
- %th.reader_description Self-description
20
+ %th.reader_description
21
+ = t('reader_extension.self_description')
14
22
  - thead.modify_header do
15
- %th.modify Modify
23
+ %th.modify
24
+ = t('modify')
16
25
 
17
26
  %tbody
18
27
  - @readers.each do |reader|
@@ -23,16 +32,24 @@
23
32
  = link_to gravatar_for(reader, {:size => 32}, {:class => 'avatar avatar_32x32'}), edit_admin_reader_url(reader)
24
33
  = link_to reader.name, edit_admin_reader_url(reader), :class => reader.trusted? ? '' : 'untrusted'
25
34
  %span.info
26
- = "(#{reader.login})"
35
+ = "#{reader.login}"
27
36
  - unless reader.notes.blank?
28
37
  %p.admin_notes
29
38
  %strong
30
39
  note:
31
40
  = reader.notes
32
41
 
42
+ - tbody.email_cell do
43
+ %td.reader_groups
44
+ = mail_to reader.email
45
+
46
+ - tbody.groups_cell do
47
+ %td.reader_groups
48
+ = reader.groups.collect{|g| link_to(g.name, admin_group_url(g)) }.join("\n")
49
+
33
50
  - tbody.description_cell do
34
51
  %td.reader_description
35
- = truncate_words(scrub_html(reader.description), 24)
52
+ = truncate_words(scrub_html(reader.description), 8)
36
53
 
37
54
  - tbody.modify_cell do
38
55
  %td.actions
@@ -5,6 +5,12 @@
5
5
  - content_for :title do
6
6
  = @reader.name
7
7
 
8
+ - content_for :introduction do
9
+ = @reader.description
10
+ %p
11
+ = link_to t('reader_extension.edit_profile'), reader_edit_profile_url
12
+
13
+
8
14
  - content_for :breadcrumbs do
9
15
  = yield :breadhead
10
16
  = t('reader_extension.separator')
@@ -7,8 +7,8 @@ Radiant.config do |config|
7
7
  reader.define 'public?', :default => false
8
8
  reader.define 'directory_visibility', :select_from => %w{public private grouped none}, :allow_blank => false, :default => 'private'
9
9
  reader.define 'share_details?', :default => false
10
- reader.define 'profiles_path', :default => ""
11
- reader.define 'preferences_path', :default => ""
10
+ reader.define 'profiles_path', :default => "directory"
11
+ reader.define 'preferences_path', :default => "account"
12
12
  reader.define 'login_to', :default => "dashboard"
13
13
  end
14
14
  config.namespace('email') do |email|
@@ -10,7 +10,7 @@ en:
10
10
  role: "Role"
11
11
  admin: "admin?"
12
12
  reader:
13
- description: "Biog or remarks"
13
+ description: "Explain yourself"
14
14
  email: "Email address"
15
15
  forename: "Forename"
16
16
  honorific: "Title or rank"
@@ -80,7 +80,12 @@ en:
80
80
  messages: "Messages"
81
81
  reader: "reader"
82
82
  reader_extension:
83
+ access: "Access"
84
+ access_control: "Restrict access"
83
85
  access_denied: "Not allowed!"
86
+ access_open: "Open"
87
+ access_restricted: "Restricted"
88
+ access_restricted_to: "only visible to %{groups}"
84
89
  account_settings: "Account settings"
85
90
  account_updated: "Your account has been updated"
86
91
  activate_account: "Activate your account"
@@ -104,7 +109,9 @@ en:
104
109
  and_try_again: "and try again."
105
110
  any_option: "<any>"
106
111
  at: "at"
107
- belongs_to_group: 'This message belongs to the <a href="%{href}">%{name}</a> group.'
112
+ belongs_to_groups:
113
+ one: 'This message is confined to the %{links} group.'
114
+ other: 'This message is confined to the %{links} groups.'
108
115
  belongs_to_these_groups: "This message is sent to these groups:"
109
116
  bold_required: "Fields with bold headings are required and will cause grumbling if left blank."
110
117
  but_not_active: 'but your account is not yet activated. Please check your email for our activation message.'
@@ -254,11 +261,14 @@ en:
254
261
  invitation: "when someone is invited to visit the site."
255
262
  password_reset: "when someone asks to reset their password."
256
263
  welcome: "when someone completes the registration and email-confirmation process."
257
- message_group_adhoc: 'It is restricted to members of the <a href="%{href}">%{name}</a> group.'
264
+ message_group_adhoc:
265
+ one: 'It is restricted to members of the %{links} group.'
266
+ other: 'It is restricted to members of the %{links} groups.'
258
267
  message_group_administrative: "It is sent automatically"
259
268
  message_preview_introduction: "This is a snapshot of the message that was delivered to you %{date}. If it contains instructions they may now be out of date."
260
269
  mistaken_access_error: "If you think that's a mistake, and that you should be allowed to do whatever it was you just tried to do, please contact your site administrator."
261
270
  must_be_empty: "must be empty"
271
+ name_and_login: "Name and Login"
262
272
  navigation:
263
273
  account: "Preferences"
264
274
  activate: "Activate account"
@@ -296,6 +306,7 @@ en:
296
306
  or_edit_preferences: 'You can also <a href="%{url}">edit your account preferences</a>.'
297
307
  or_edit_profile: 'You can also <a href="%{url}">edit your profile</a> to add more information about yourself.'
298
308
  other_messages: "Ad-hoc messages"
309
+ page_access_explanation: "To restrict access to one or more groups, select them from the list below."
299
310
  page_not_public: "The page you have requested is not public. Please log in. If your account has the necessary permission you will be taken straight there."
300
311
  page_permission_denied: "You don't have permission to see the page that you have requested."
301
312
  page_private: "Sorry: you don't have permission to view that page."
@@ -355,6 +366,7 @@ en:
355
366
  return_to_page: "return to the page you were looking at before you started registering"
356
367
  select_all: "Select all"
357
368
  selected_people: "Selected people"
369
+ self_description: "Self-description"
358
370
  send_it_again: "send it again"
359
371
  send_message: "Send message"
360
372
  send_reset_button: "send me instructions"
@@ -363,6 +375,7 @@ en:
363
375
  sent_to_group: "sent automatically to the %{name} group"
364
376
  sent_to_these_groups: "sent automatically to these groups"
365
377
  separator: " &raquo; "
378
+ set_access: "Set access"
366
379
  set_message_function: "Message function"
367
380
  set_message_groups: "Message groups"
368
381
  set_new_password: "set new password"
@@ -5,9 +5,9 @@ class GroupsNestedSet < ActiveRecord::Migration
5
5
  add_column :groups, :lft, :integer
6
6
  add_column :groups, :rgt, :integer
7
7
 
8
- Group.reset_column_information
9
- Group.rebuild!
10
- Group.all.each {|g| g.save }
8
+ # Group.reset_column_information
9
+ # Group.rebuild!
10
+ # Group.all.each {|g| g.save }
11
11
  end
12
12
 
13
13
  def self.down
@@ -1,5 +1,5 @@
1
1
  module RadiantReaderExtension
2
- VERSION = '3.0.5'
2
+ VERSION = '3.0.7'
3
3
  SUMMARY = %q{Reader/viewer/visitor registration, login and access-control for Radiant CMS}
4
4
  DESCRIPTION = %q{Provides reader/member/user registration and management functions including password-reminder, group-based page access control and administrative email.}
5
5
  URL = "http://radiant.spanner.org/reader"
@@ -33,8 +33,8 @@ module ReaderAdminUI
33
33
  edit.form_bottom.concat %w{edit_timestamp edit_buttons}
34
34
  end
35
35
  reader.index = Radiant::AdminUI::RegionSet.new do |index|
36
- index.thead.concat %w{title_header description_header modify_header}
37
- index.tbody.concat %w{title_cell description_cell modify_cell}
36
+ index.thead.concat %w{title_header email_header groups_header description_header modify_header}
37
+ index.tbody.concat %w{title_cell email_cell groups_cell description_cell modify_cell}
38
38
  index.bottom.concat %w{buttons}
39
39
  end
40
40
  reader.remove = reader.index
@@ -7,6 +7,42 @@ Toggle.SelectAllBehavior = Behavior.create(Toggle.CheckboxBehavior, {
7
7
  }
8
8
  });
9
9
 
10
+ // This checkbox, when checked, will check and disable all others within the same containing element.
11
+ // It's useful in a tree view when the checked property will be inherited.
12
+ // For now I'm also using it to populate a hidden form field, but something more general would be preferable.
13
+ //
14
+ Treebox = Behavior.create({
15
+ onclick: function(e) {
16
+ this.toggle();
17
+ },
18
+ toggle: function() {
19
+ var state = this.element.checked;
20
+ this.element.up('li').down('ul').select('input').each(function (el) {
21
+ el.checked = state;
22
+ el.disabled = state == true;
23
+ });
24
+ }
25
+ });
26
+
27
+ GroupSelection = Behavior.create({
28
+ onsubmit : function(e) {
29
+ if (e) e.stop();
30
+ var group_list = this.element.getInputs('checkbox').collect(function(i) { if (i.checked && !i.disabled) return i.value; }).compact();
31
+ console.log('group_list: ', group_list);
32
+ if (group_list.length == 0) {
33
+ $('group_status_flag').removeClassName('restricted');
34
+ $('group_status_flag').addClassName('unrestricted');
35
+ $('group_status_flag').update('Open');
36
+ } else {
37
+ $('group_status_flag').removeClassName('unrestricted');
38
+ $('group_status_flag').addClassName('restricted');
39
+ $('group_status_flag').update('Restricted');
40
+ }
41
+ $('page_group_ids').value = group_list.join(',');
42
+ this.element.closePopup();
43
+ }
44
+ });
45
+
10
46
  // This is a normal remote link that replaces itself with the response.
11
47
  //
12
48
  Remote.UpdatingLink = Behavior.create(Remote.Base, {
@@ -47,5 +83,7 @@ Event.addBehavior({
47
83
  'input.select_all': Toggle.SelectAllBehavior(),
48
84
  'a.fake_checkbox': Remote.UpdatingLink(),
49
85
  'a.inplace': Remote.UpdatingLink(),
50
- 'form.inplace': Remote.UpdatingForm()
86
+ 'form.inplace': Remote.UpdatingForm(),
87
+ 'input.treebox': Treebox(),
88
+ 'form.group_selection': GroupSelection()
51
89
  });
data/reader_extension.rb CHANGED
@@ -24,6 +24,9 @@ class ReaderExtension < Radiant::Extension
24
24
  end
25
25
 
26
26
  admin.page.edit.add :layout, "page_groups"
27
+ admin.page.edit.add :main, "groups_popup", :after => 'edit_popups'
28
+ admin.page.index.add :sitemap_head, "groups_column_header", :after => 'status_column_header'
29
+ admin.page.index.add :node, "groups_column", :after => 'status_column'
27
30
 
28
31
  tab("Readers") do
29
32
  add_item("Readers", "/admin/readers")
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: radiant-reader-extension
3
3
  version: !ruby/object:Gem::Version
4
- hash: 13
4
+ hash: 9
5
5
  prerelease:
6
6
  segments:
7
7
  - 3
8
8
  - 0
9
- - 5
10
- version: 3.0.5
9
+ - 7
10
+ version: 3.0.7
11
11
  platform: ruby
12
12
  authors:
13
13
  - William Ross
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-09-08 00:00:00 +01:00
19
- default_executable:
18
+ date: 2011-09-27 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: radiant-layouts-extension
@@ -219,6 +218,9 @@ files:
219
218
  - app/views/admin/messages/new.html.haml
220
219
  - app/views/admin/messages/preview.html.haml
221
220
  - app/views/admin/messages/show.html.haml
221
+ - app/views/admin/pages/_groups_column.html.haml
222
+ - app/views/admin/pages/_groups_column_header.html.haml
223
+ - app/views/admin/pages/_groups_popup.html.haml
222
224
  - app/views/admin/pages/_listed.html.haml
223
225
  - app/views/admin/pages/_page_groups.html.haml
224
226
  - app/views/admin/permissions/_page.html.haml
@@ -349,11 +351,10 @@ files:
349
351
  - spec/models/reader_spec.rb
350
352
  - spec/spec.opts
351
353
  - spec/spec_helper.rb
352
- has_rdoc: true
353
354
  homepage: http://radiant.spanner.org/reader
354
355
  licenses: []
355
356
 
356
- post_install_message: "\n Add this to your radiant project with:\n\n config.gem 'radiant-reader-extension', :version => '~> 3.0.5'\n\n and if you haven't already, remember to enable ActionMailer in your\n project's config/environment.rb.\n "
357
+ post_install_message: "\n Add this to your radiant project with:\n\n config.gem 'radiant-reader-extension', :version => '~> 3.0.7'\n\n and if you haven't already, remember to enable ActionMailer in your\n project's config/environment.rb.\n "
357
358
  rdoc_options: []
358
359
 
359
360
  require_paths:
@@ -379,7 +380,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
379
380
  requirements: []
380
381
 
381
382
  rubyforge_project:
382
- rubygems_version: 1.5.3
383
+ rubygems_version: 1.8.10
383
384
  signing_key:
384
385
  specification_version: 3
385
386
  summary: Reader/viewer/visitor registration, login and access-control for Radiant CMS