radiant-reader-extension 3.0.0.rc4 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +105 -38
- data/Rakefile +4 -4
- data/app/controllers/accounts_controller.rb +24 -11
- data/app/controllers/admin/groups_controller.rb +15 -0
- data/app/controllers/admin/memberships_controller.rb +13 -7
- data/app/controllers/admin/messages_controller.rb +1 -0
- data/app/controllers/admin/permissions_controller.rb +15 -8
- data/app/controllers/groups_controller.rb +6 -4
- data/app/controllers/password_resets_controller.rb +1 -1
- data/app/controllers/reader_action_controller.rb +7 -51
- data/app/controllers/reader_sessions_controller.rb +9 -11
- data/app/helpers/reader_helper.rb +23 -3
- data/app/models/group.rb +45 -16
- data/app/models/message.rb +4 -11
- data/app/models/permission.rb +4 -0
- data/app/models/reader.rb +61 -26
- data/app/models/reader_notifier.rb +2 -2
- data/app/models/reader_page.rb +9 -5
- data/app/views/accounts/{_memberships.html.haml → _choose_memberships.html.haml} +0 -0
- data/app/views/accounts/_form.html.haml +9 -11
- data/app/views/accounts/_preamble.html.haml +14 -0
- data/app/views/accounts/_profile_form.html.haml +13 -29
- data/app/views/accounts/dashboard.html.haml +0 -1
- data/app/views/accounts/edit.html.haml +3 -3
- data/app/views/accounts/edit_profile.html.haml +10 -10
- data/app/views/admin/groups/_chooser.html.haml +8 -0
- data/app/views/admin/groups/_form.html.haml +7 -5
- data/app/views/admin/groups/_group.html.haml +29 -0
- data/app/views/admin/groups/index.html.haml +2 -28
- data/app/views/admin/groups/show.html.haml +3 -2
- data/app/views/admin/memberships/_reader.html.haml +2 -6
- data/app/views/admin/messages/_form.html.haml +10 -11
- data/app/views/admin/messages/_list_function.haml +2 -3
- data/app/views/admin/messages/{index.haml → index.html.haml} +21 -11
- data/app/views/admin/pages/_page_groups.html.haml +5 -11
- data/app/views/admin/permissions/_page.html.haml +6 -12
- data/app/views/admin/reader_configuration/edit.html.haml +2 -0
- data/app/views/admin/reader_configuration/show.html.haml +2 -0
- data/app/views/groups/_group.html.haml +12 -0
- data/app/views/groups/show.html.haml +10 -3
- data/app/views/readers/_description.html.haml +3 -0
- data/app/views/readers/_groups.html.haml +9 -0
- data/app/views/{accounts → readers}/_links.html.haml +2 -2
- data/app/views/readers/_list.html.haml +23 -0
- data/app/views/{accounts/_groups.html.haml → readers/_memberships.html.haml} +0 -1
- data/app/views/{accounts/_reader.html.haml → readers/_mugshot.html.haml} +1 -1
- data/app/views/readers/_people.html.haml +6 -0
- data/app/views/readers/_profile.html.haml +30 -0
- data/app/views/readers/_reader.html.haml +28 -0
- data/app/views/readers/index.html.haml +20 -0
- data/app/views/{accounts → readers}/show.html.haml +1 -2
- data/app/views/shared/_standard_reader_parts.html.haml +1 -1
- data/app/views/shared/not_allowed.html.haml +16 -0
- data/config/initializers/formats.rb +1 -2
- data/config/initializers/radiant_config.rb +5 -2
- data/config/locales/en.yml +181 -140
- data/config/routes.rb +25 -16
- data/db/migrate/001_create_readers.rb +0 -1
- data/db/migrate/20090921125653_reader_messages.rb +0 -1
- data/db/migrate/20090921125654_group_messages.rb +0 -1
- data/db/migrate/20110812111934_groups_nested_set.rb +19 -0
- data/db/migrate/20110814070858_message_has_many_groups.rb +14 -0
- data/db/migrate/20110905194602_group_ancestry.rb +23 -0
- data/lib/controller_extensions.rb +49 -0
- data/lib/grouped_model.rb +49 -8
- data/lib/grouped_page.rb +17 -5
- data/lib/message_tags.rb +21 -3
- data/lib/radiant-reader-extension.rb +1 -1
- data/lib/reader_admin_ui.rb +7 -8
- data/lib/reader_tags.rb +1 -1
- data/lib/site_controller_extensions.rb +7 -18
- data/public/images/furniture/csv.png +0 -0
- data/public/images/furniture/csv_tiny.png +0 -0
- data/public/images/furniture/vcard.png +0 -0
- data/public/images/furniture/vcard_tiny.png +0 -0
- data/public/javascripts/admin/reader.js +22 -1
- data/public/stylesheets/sass/admin/reader_group.sass +23 -22
- data/public/stylesheets/sass/reader.sass +81 -17
- data/radiant-reader-extension.gemspec +3 -1
- data/reader_extension.rb +7 -9
- data/spec/controllers/accounts_controller_spec.rb +8 -22
- data/spec/controllers/admin/messages_controller_spec.rb +0 -12
- data/spec/datasets/readers_dataset.rb +41 -38
- data/spec/lib/reader_tags_spec.rb +1 -1
- data/spec/models/group_spec.rb +89 -22
- data/spec/models/message_spec.rb +1 -1
- data/spec/models/reader_notifier_spec.rb +1 -1
- data/spec/models/reader_page_spec.rb +34 -18
- data/spec/models/reader_spec.rb +0 -1
- data/spec/spec.opts +4 -3
- metadata +51 -28
- data/app/views/accounts/_contributions.html.haml +0 -2
- data/app/views/accounts/_description.html.haml +0 -2
- data/app/views/accounts/_list.html.haml +0 -17
- data/app/views/accounts/_profile.html.haml +0 -29
- data/app/views/accounts/index.html.haml +0 -23
- data/app/views/groups/_all.html.haml +0 -10
- data/app/views/site/not_allowed.html.haml +0 -4
- data/db/migrate/20100922152338_lock_versions.rb +0 -9
- data/db/migrate/20101004074945_unlock_version.rb +0 -9
data/README.md
CHANGED
@@ -2,82 +2,150 @@
|
|
2
2
|
|
3
3
|
This is a framework that takes care of all the dull bits of registering, activating, reminding, logging in and editing preferences for your site visitors.
|
4
4
|
|
5
|
-
It uses authlogic to handle sessions and provides complete interfaces both for the administrator and the visitor. The admin interface is
|
5
|
+
It uses authlogic to handle sessions and provides complete interfaces both for the administrator and the visitor. The admin interface is simple and fits in with radiant. The visitor interface is more friendly (and incidentally includes a trick email field - so-called inverse captcha - that should prevent spam signups).
|
6
6
|
|
7
7
|
The visitors are referred to as 'readers' here. Readers never see the admin interface, but your site authors and admins are automatically given reader status.
|
8
8
|
|
9
|
-
|
9
|
+
## Status
|
10
10
|
|
11
|
-
|
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.
|
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
|
|
15
|
-
|
15
|
+
## Note on internationalisation and customisation
|
16
16
|
|
17
|
-
|
17
|
+
The locale strings here are generally defined in a functional rather than grammatical way. That is, they have labels like `activation_required_explanation` rather than being assembled out of lexical units. This is partly because for flexibility of translation, but also because it gives you an easy way to change the text on functional pages like reader-preferences and registration forms.
|
18
18
|
|
19
|
-
|
19
|
+
## Requirements
|
20
20
|
|
21
|
-
|
22
|
-
* Uses the new configuration interface;
|
23
|
-
* Messaging much simplified and now intended to be purely administrative.
|
24
|
-
* ajaxable status panel returned by `reader_session_url` (ie. you just have to call /reader_session.js over xmlhttp to get a sensible welcome and control block)
|
21
|
+
Versions 3.x of reader are designed to work with radiant 1 and will not work with older versions. There's a '0.9.1' tag in the repository for the last release that will.
|
25
22
|
|
26
|
-
|
23
|
+
Since you now have to install reader as a gem, all of its gem-based dependencies will be taken care of for you, but you may need some system libraries. We use Sanitize to whitelist html input. Sanitize uses Nogogiri to parse html, and Nokogiri needs `libxml2` and `libxslt` to do that. If you've installed imagemagick to work with radiant assets, it's very likely that you have those libraries already. If not, you will need to install them before you can install the reader gem.
|
27
24
|
|
28
|
-
|
25
|
+
## Installation
|
29
26
|
|
30
|
-
|
27
|
+
Install the gem:
|
31
28
|
|
32
|
-
|
29
|
+
sudo gem install radiant-reader-extension
|
33
30
|
|
34
|
-
|
31
|
+
add it to your application's Gemfile:
|
35
32
|
|
36
|
-
|
33
|
+
gem 'authlogic', "~> 2.1.6"
|
34
|
+
gem radiant-reader-extension, '~>2.0.0'
|
37
35
|
|
38
|
-
|
36
|
+
and then you can bring over assets and create data tables:
|
39
37
|
|
40
|
-
|
38
|
+
rake radiant:extensions:update_all
|
39
|
+
rake radiant:extensions:reader:migrate
|
40
|
+
rake radiant:extensions:reader:update
|
41
41
|
|
42
|
-
|
42
|
+
## Configuration
|
43
43
|
|
44
|
-
|
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
|
-
|
46
|
+
## Usage
|
47
47
|
|
48
|
-
|
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:
|
49
49
|
|
50
|
-
|
50
|
+
* registration
|
51
|
+
* honeypot spam trap
|
52
|
+
* activation by email confirmation
|
53
|
+
* logging in and out
|
54
|
+
* password reminders
|
55
|
+
* edit account preferences
|
56
|
+
* edit profile
|
57
|
+
* dashboard view on login
|
58
|
+
* configurable members directory with csv and vcard export
|
59
|
+
* administrative email messages for welcome, invitation, etc
|
60
|
+
* ad-hoc email messages to some or all readers
|
51
61
|
|
52
|
-
|
53
|
-
|
54
|
-
or for more control:
|
62
|
+
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).
|
55
63
|
|
56
|
-
|
64
|
+
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.
|
57
65
|
|
58
|
-
|
66
|
+
The group-scoping mechanism is easily extended to other classes:
|
59
67
|
|
60
|
-
|
61
|
-
|
68
|
+
class Widget < ActiveRecord::Base
|
69
|
+
has_groups
|
70
|
+
...
|
71
|
+
end
|
62
72
|
|
63
|
-
|
73
|
+
So the forum extension, for example, includes the ability to make a forum visible only to members of selected groups.
|
64
74
|
|
65
|
-
|
75
|
+
For more reader-facing usefulness please see our [forum extension](http://github.com/spanner/radiant-forum-extension) for discussions and page/blog comments and [downloads extension](http://github.com/spanner/radiant-downloads-extension) for secure access-controlled file downloads. We also have extensions for public submission of calendar events and assets, which will emerge here soon.
|
66
76
|
|
67
77
|
## Layouts
|
68
78
|
|
69
|
-
We use the
|
79
|
+
We use the `layouts` extension to wrap the appearance of your public site around the views produced by the reader extension. You can configure this with the dropdown list on the reader configuration page.
|
80
|
+
|
81
|
+
The laying-out is achieved by defining lots of fake page parts in the reader views. All your layout has to do is include those page parts with the usual `<r:content />` calls.
|
82
|
+
|
83
|
+
* `<r:content />` on its own will hold the main page content: login form, activation form, dashboard or whatever.
|
84
|
+
* `<r:title />` is always the page title
|
85
|
+
* `<r:content part="introduction" />` will provide a separate opening paragraph for layouts that require it
|
86
|
+
* `<r:content part="sidebar" />` will (sometimes) provide relevant marginal content
|
87
|
+
* `<r:content part="breadhead" />` is a more minimal breadcrumb trail that omits the present page and is suitable for use above the page title
|
88
|
+
* `<r:content part="controls" />` will show a standard 'hello [name]' block with login and logout and so on, but only on an uncached page. If the page is cached it will render an empty div with class 'remote_controls' that you can populate with javascipt. An ajax call to `/reader_session/show` will return the same controls block.
|
89
|
+
* `<r:content part="signals" />` will render any confirmation or error flashes. Not suitable for cached pages.
|
90
|
+
* `<r:content part="person" />` will render a gravatar and link for the current reader
|
91
|
+
|
92
|
+
You don't really need anything but the main title and content tags:
|
70
93
|
|
71
|
-
|
94
|
+
<h1><r:title /></h1>
|
95
|
+
<r:content />
|
96
|
+
|
97
|
+
will do just fine to start with.
|
98
|
+
|
99
|
+
## CSS and Javascript
|
100
|
+
|
101
|
+
Some standard formatting and interaction is included for you to build upon.
|
102
|
+
|
103
|
+
`/javascripts/reader.js` includes some rather basic jquery code to handle retrieving remote content (such as the control block mentioned above), fading out flashes and errors and adding a bit of responsiveness to the reader-facing forms.
|
104
|
+
|
105
|
+
`/stylesheets/sass/reader.sass` includes the default formatting of reader-facing forms and lists. It could probably stand to be reorganised a bit but you should find it a useful starting point and I recommend that you override it selectively rather than replacing it completely. There are two ways to do that:
|
106
|
+
|
107
|
+
* @import 'reader.sass' at the top of your (SASS-based) stylesheet within radiant
|
108
|
+
* link to /stylesheets/reader.css in the old-fashioned way and then bring in your own stylesheets any way you like.
|
109
|
+
|
110
|
+
Or you can replace all this with your own, of course.
|
111
|
+
|
112
|
+
## ReaderPages
|
113
|
+
|
114
|
+
You can also provide a more customised directory service by creating a ReaderPage and populating it with the many `r:readers` and `r:reader` tags that are defined here.
|
115
|
+
|
116
|
+
## Directory Visibility
|
117
|
+
|
118
|
+
There are four levels of directory visibility, and the behaviour of your site is set by the `reader.directory_visibility` configuration entry:
|
119
|
+
|
120
|
+
* *none* is the default. No reader details are shown to anybody.
|
121
|
+
* *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
|
+
* *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.
|
72
124
|
|
73
125
|
## Using readers in other extensions
|
74
126
|
|
75
|
-
|
127
|
+
All the reader pages (both public and administrative) are sharded in the AdminUI. The public-facing administration and directory pages are all in `admin.accounts`, since the admin-facing views are already in `admin.readers`.
|
76
128
|
|
77
129
|
Most of your reader-facing controllers will want to inherit from `ReaderActionController`.
|
78
130
|
|
79
131
|
Marking a reader as untrusted does nothing here apart from making them go red, but we assume that in other extensions it will have some limiting effect.
|
80
132
|
|
133
|
+
## Latest changes
|
134
|
+
|
135
|
+
This version requires edge radiant, or radiant 1 when it becomes available.
|
136
|
+
|
137
|
+
New ReaderPages provide flexible directory services with configurable access control. The old controller and page parts mechanism is likely to be phased out gradually both here and in the forum in favour of more orthodox radiant page-types. We will always need to use the layout-wrapper approach for login and registration forms, though.
|
138
|
+
|
139
|
+
Right now we are **not compatible with multi_site or the sites extension**: that's mostly because neither is radiant edge: it will all be sorted out in time for the release of v1, which isn't far away.
|
140
|
+
|
141
|
+
Also:
|
142
|
+
|
143
|
+
* groups hierarchical
|
144
|
+
* public interface internationalized;
|
145
|
+
* Uses the new configuration interface;
|
146
|
+
* Messaging much simplified and now intended to be purely administrative.
|
147
|
+
* ajaxable status panel returned by `reader_session_url` (ie. you just have to call /reader_session.js over xmlhttp to get a sensible welcome and control block)
|
148
|
+
|
81
149
|
## See also
|
82
150
|
|
83
151
|
* [reader_group](http://github.com/spanner/radiant-reader_group-extension)
|
@@ -91,7 +159,6 @@ Marking a reader as untrusted does nothing here apart from making them go red, b
|
|
91
159
|
|
92
160
|
## Author and copyright
|
93
161
|
|
94
|
-
* Copyright spanner ltd 2007-
|
162
|
+
* Copyright spanner ltd 2007-11.
|
95
163
|
* Released under the same terms as Rails and/or Radiant.
|
96
164
|
* Contact will at spanner.org
|
97
|
-
|
data/Rakefile
CHANGED
@@ -16,11 +16,11 @@ unless defined? RADIANT_ROOT
|
|
16
16
|
end
|
17
17
|
|
18
18
|
require 'rake'
|
19
|
-
require '
|
19
|
+
require 'rdoc/task'
|
20
20
|
require 'rake/testtask'
|
21
21
|
|
22
|
-
rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
|
23
|
-
$LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
|
22
|
+
# rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
|
23
|
+
# $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
|
24
24
|
require 'spec/rake/spectask'
|
25
25
|
require 'cucumber'
|
26
26
|
require 'cucumber/rake/task'
|
@@ -101,7 +101,7 @@ namespace :spec do
|
|
101
101
|
end
|
102
102
|
|
103
103
|
desc 'Generate documentation for the reader extension.'
|
104
|
-
|
104
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
105
105
|
rdoc.rdoc_dir = 'rdoc'
|
106
106
|
rdoc.title = 'ReaderExtension'
|
107
107
|
rdoc.options << '--line-numbers' << '--inline-source'
|
@@ -2,17 +2,20 @@ class AccountsController < ReaderActionController
|
|
2
2
|
helper :reader
|
3
3
|
|
4
4
|
before_filter :check_registration_allowed, :only => [:new, :create, :activate]
|
5
|
+
before_filter :no_removing, :only => [:remove, :destroy]
|
5
6
|
before_filter :i_am_me, :only => [:show, :edit, :edit_profile]
|
6
|
-
before_filter :require_reader, :except => [:new, :create, :activate]
|
7
7
|
before_filter :default_to_self, :only => [:show]
|
8
8
|
before_filter :restrict_to_self, :only => [:edit, :edit_profile, :update, :resend_activation]
|
9
|
-
before_filter :
|
9
|
+
before_filter :get_readers_and_groups, :only => [:index, :show]
|
10
|
+
before_filter :require_reader, :except => [:new, :create, :activate]
|
11
|
+
before_filter :require_reader_visibility
|
10
12
|
before_filter :ensure_groups_subscribable, :only => [:update, :create]
|
11
13
|
|
12
14
|
def index
|
13
|
-
@readers = Reader.visible_to(current_reader)
|
14
15
|
respond_to do |format|
|
15
|
-
format.html {
|
16
|
+
format.html {
|
17
|
+
render :template => 'readers/index'
|
18
|
+
}
|
16
19
|
format.csv {
|
17
20
|
send_data generate_csv(@readers), :type => 'text/csv; charset=utf-8; header=present', :filename => "everyone.csv"
|
18
21
|
}
|
@@ -23,9 +26,10 @@ class AccountsController < ReaderActionController
|
|
23
26
|
end
|
24
27
|
|
25
28
|
def show
|
26
|
-
@reader = Reader.find(params[:id])
|
27
29
|
respond_to do |format|
|
28
|
-
format.html
|
30
|
+
format.html {
|
31
|
+
render :template => 'readers/show'
|
32
|
+
}
|
29
33
|
format.vcard {
|
30
34
|
send_data @reader.vcard.to_s, :filename => "#{@reader.filename}.vcf"
|
31
35
|
}
|
@@ -88,7 +92,7 @@ class AccountsController < ReaderActionController
|
|
88
92
|
@reader.clear_password = params[:reader][:password] if params[:reader][:password]
|
89
93
|
if @reader.save
|
90
94
|
flash[:notice] = t('reader_extension.account_updated')
|
91
|
-
redirect_to
|
95
|
+
redirect_to reader_dashboard_url
|
92
96
|
else
|
93
97
|
render :action => 'edit'
|
94
98
|
end
|
@@ -105,7 +109,7 @@ protected
|
|
105
109
|
end
|
106
110
|
|
107
111
|
def restrict_to_self
|
108
|
-
flash[:error] = t("reader_extension.cannot_edit_others") if params[:id] && params[:id] != current_reader.id
|
112
|
+
flash[:error] = t("reader_extension.cannot_edit_others") if params[:id] && params[:id] != current_reader.id.to_s
|
109
113
|
@reader = current_reader
|
110
114
|
end
|
111
115
|
|
@@ -136,15 +140,24 @@ protected
|
|
136
140
|
|
137
141
|
private
|
138
142
|
|
143
|
+
def get_readers_and_groups
|
144
|
+
@readers = Reader.visible_to(current_reader)
|
145
|
+
@groups = Group.roots.visible_to(current_reader)
|
146
|
+
@reader = Reader.find(params[:id]) if params[:id]
|
147
|
+
end
|
148
|
+
|
149
|
+
def require_reader_visibility
|
150
|
+
# more useful than a 404 but perhaps too informative?
|
151
|
+
raise ReaderError::AccessDenied, "You do not have permission to see that person." if @reader && !@reader.visible_to?(current_reader)
|
152
|
+
end
|
153
|
+
|
139
154
|
def ensure_groups_subscribable
|
140
155
|
if params[:reader] && params[:reader][:group_ids]
|
141
156
|
params[:reader][:group_ids].each do |g|
|
142
|
-
raise
|
157
|
+
raise ReaderError::AccessDenied, "One of those groups is not public and does not accept subscriptions." unless Group.find(g).public?
|
143
158
|
end
|
144
159
|
end
|
145
160
|
true
|
146
|
-
rescue ActiveRecord::RecordNotFound
|
147
|
-
false
|
148
161
|
end
|
149
162
|
|
150
163
|
end
|
@@ -1,8 +1,23 @@
|
|
1
1
|
class Admin::GroupsController < Admin::ResourceController
|
2
|
+
helper :reader
|
3
|
+
paginate_models
|
2
4
|
skip_before_filter :load_model
|
3
5
|
before_filter :load_model, :except => :index # we want the filter to run before :show too
|
4
6
|
|
5
7
|
def show
|
6
8
|
|
7
9
|
end
|
10
|
+
|
11
|
+
def load_models
|
12
|
+
self.models = paginated? ? model_class.roots.paginate(pagination_parameters) : model_class.roots.all
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_model
|
16
|
+
self.model = if params[:id]
|
17
|
+
model_class.find(params[:id])
|
18
|
+
else
|
19
|
+
model_class.new(:parent_id => params[:parent_id])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
8
23
|
end
|
@@ -1,14 +1,12 @@
|
|
1
1
|
class Admin::MembershipsController < ApplicationController
|
2
2
|
|
3
|
-
before_filter :
|
3
|
+
before_filter :find_reader_and_group
|
4
4
|
|
5
5
|
def index
|
6
6
|
redirect_to admin_group_url(@group)
|
7
7
|
end
|
8
8
|
|
9
9
|
def create
|
10
|
-
@reader = Reader.find(params[:reader_id])
|
11
|
-
raise ActiveRecord::RecordNotFound unless @reader
|
12
10
|
@membership = Membership.find_or_create_by_reader_id_and_group_id(@reader.id, @group.id)
|
13
11
|
respond_to do |format|
|
14
12
|
format.html {
|
@@ -20,7 +18,7 @@ class Admin::MembershipsController < ApplicationController
|
|
20
18
|
end
|
21
19
|
|
22
20
|
def destroy
|
23
|
-
@membership
|
21
|
+
@membership ||= @group.memberships.find(params[:id])
|
24
22
|
@reader = @membership.reader
|
25
23
|
@membership.delete if @membership
|
26
24
|
respond_to do |format|
|
@@ -32,11 +30,19 @@ class Admin::MembershipsController < ApplicationController
|
|
32
30
|
end
|
33
31
|
end
|
34
32
|
|
33
|
+
def toggle
|
34
|
+
if @membership = Membership.find_by_reader_id_and_group_id(@reader.id, @group.id)
|
35
|
+
destroy
|
36
|
+
else
|
37
|
+
create
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
35
41
|
protected
|
36
42
|
|
37
|
-
def
|
43
|
+
def find_reader_and_group
|
38
44
|
@group = Group.find(params[:group_id])
|
39
|
-
|
45
|
+
@reader = Reader.find(params[:reader_id]) if params[:reader_id]
|
40
46
|
end
|
41
|
-
|
47
|
+
|
42
48
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class Admin::PermissionsController < ApplicationController
|
2
2
|
|
3
|
-
before_filter :
|
3
|
+
before_filter :find_page_and_group
|
4
4
|
|
5
5
|
def index
|
6
6
|
redirect_to admin_group_url(@group)
|
@@ -8,12 +8,11 @@ class Admin::PermissionsController < ApplicationController
|
|
8
8
|
|
9
9
|
def create
|
10
10
|
@page = Page.find(params[:page_id])
|
11
|
-
raise ActiveRecord::RecordNotFound unless @page
|
12
11
|
scope = @group.permissions.for(@page)
|
13
12
|
@permission = scope.first || scope.create!
|
14
13
|
respond_to do |format|
|
15
14
|
format.html {
|
16
|
-
flash[:notice] = "#{@page.
|
15
|
+
flash[:notice] = "#{@page.title} bound to group #{@group.name}"
|
17
16
|
redirect_to admin_group_url(@group)
|
18
17
|
}
|
19
18
|
format.js { render :partial => 'page' }
|
@@ -21,23 +20,31 @@ class Admin::PermissionsController < ApplicationController
|
|
21
20
|
end
|
22
21
|
|
23
22
|
def destroy
|
24
|
-
@permission
|
23
|
+
@permission ||= @group.permissions.find(params[:id])
|
25
24
|
@page = @permission.permitted
|
26
25
|
@permission.delete if @permission
|
27
26
|
respond_to do |format|
|
28
27
|
format.html {
|
29
|
-
flash[:notice] = "#{@page.
|
28
|
+
flash[:notice] = "#{@page.title} released from group #{@group.name}"
|
30
29
|
redirect_to admin_group_url(@group)
|
31
30
|
}
|
32
31
|
format.js { render :partial => 'page' }
|
33
32
|
end
|
34
33
|
end
|
35
34
|
|
35
|
+
def toggle
|
36
|
+
if @permission = @group.permission_for(@page)
|
37
|
+
destroy
|
38
|
+
else
|
39
|
+
create
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
36
43
|
protected
|
37
44
|
|
38
|
-
def
|
45
|
+
def find_page_and_group
|
39
46
|
@group = Group.find(params[:group_id])
|
40
|
-
|
47
|
+
@page = Page.find(params[:page_id]) if params[:page_id]
|
41
48
|
end
|
42
|
-
|
49
|
+
|
43
50
|
end
|
@@ -16,7 +16,7 @@ class GroupsController < ReaderActionController
|
|
16
16
|
send_data generate_csv(@readers), :type => 'text/csv; charset=utf-8; header=present', :filename => "#{@group.filename}.csv"
|
17
17
|
}
|
18
18
|
format.vcard {
|
19
|
-
send_data @readers
|
19
|
+
send_data generate_vcard(@readers), :filename => "#{@group.filename}.vcf"
|
20
20
|
}
|
21
21
|
end
|
22
22
|
end
|
@@ -24,12 +24,14 @@ class GroupsController < ReaderActionController
|
|
24
24
|
private
|
25
25
|
|
26
26
|
def get_group_or_groups
|
27
|
-
@groups = Group.visible_to(current_reader)
|
28
|
-
@group =
|
27
|
+
@groups = Group.roots.visible_to(current_reader)
|
28
|
+
@group = Group.find(params[:id]) if params[:id]
|
29
29
|
end
|
30
30
|
|
31
31
|
def require_group_visibility
|
32
|
-
|
32
|
+
if @group && !@group.visible_to?(current_reader) # nb. @groups is a smaller set
|
33
|
+
raise ReaderError::AccessDenied, "That group is not public and you are not in it."
|
34
|
+
end
|
33
35
|
end
|
34
36
|
|
35
37
|
end
|