radiant-reader_group-extension 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/README.markdown +44 -0
- data/Rakefile +137 -0
- data/VERSION +1 -0
- data/app/controllers/admin/group_invitations_controller.rb +84 -0
- data/app/controllers/admin/groups_controller.rb +4 -0
- data/app/controllers/admin/memberships_controller.rb +42 -0
- data/app/controllers/admin/permissions_controller.rb +42 -0
- data/app/helpers/admin/groups_helper.rb +36 -0
- data/app/models/group.rb +43 -0
- data/app/models/membership.rb +13 -0
- data/app/models/permission.rb +13 -0
- data/app/views/admin/group_invitations/new.html.haml +45 -0
- data/app/views/admin/group_invitations/preview.html.haml +63 -0
- data/app/views/admin/groups/_add_readers.html.haml +0 -0
- data/app/views/admin/groups/_form.html.haml +61 -0
- data/app/views/admin/groups/_list_head.html.haml +12 -0
- data/app/views/admin/groups/_listed.html.haml +25 -0
- data/app/views/admin/groups/edit.html.haml +8 -0
- data/app/views/admin/groups/index.html.haml +19 -0
- data/app/views/admin/groups/new.html.haml +6 -0
- data/app/views/admin/groups/remove.html.haml +31 -0
- data/app/views/admin/groups/show.html.haml +41 -0
- data/app/views/admin/memberships/_reader.html.haml +9 -0
- data/app/views/admin/messages/_list_notes.html.haml +9 -0
- data/app/views/admin/messages/_message_description.html.haml +7 -0
- data/app/views/admin/messages/_message_group.html.haml +3 -0
- data/app/views/admin/pages/_listed.html.haml +16 -0
- data/app/views/admin/pages/_page_groups.html.haml +17 -0
- data/app/views/admin/permissions/_page.html.haml +24 -0
- data/app/views/admin/reader_settings/_group_welcomes.html.haml +11 -0
- data/app/views/admin/readers/_reader_groups.html.haml +7 -0
- data/app/views/messages/show.html.haml +11 -0
- data/app/views/reader_activations/_on_activation.html.haml +10 -0
- data/app/views/readers/_memberships.html.haml +11 -0
- data/app/views/site/not_allowed.html.haml +4 -0
- data/config/routes.rb +8 -0
- data/db/migrate/001_create_groups.rb +32 -0
- data/db/migrate/20090921125654_group_messages.rb +9 -0
- data/db/migrate/20091120083119_groups_public.rb +11 -0
- data/lib/admin_messages_controller_extensions.rb +15 -0
- data/lib/group_message_tags.rb +82 -0
- data/lib/group_ui.rb +37 -0
- data/lib/grouped_message.rb +38 -0
- data/lib/grouped_model.rb +100 -0
- data/lib/grouped_page.rb +59 -0
- data/lib/grouped_reader.rb +63 -0
- data/lib/reader_activations_controller_extensions.rb +21 -0
- data/lib/reader_notifier_extensions.rb +14 -0
- data/lib/reader_sessions_controller_extensions.rb +21 -0
- data/lib/readers_controller_extensions.rb +22 -0
- data/lib/site_controller_extensions.rb +37 -0
- data/lib/tasks/reader_group_extension_tasks.rake +28 -0
- data/pkg/radiant-reader_group-extension-0.9.0.gem +0 -0
- data/public/images/admin/chk_auto.png +0 -0
- data/public/images/admin/chk_off.png +0 -0
- data/public/images/admin/chk_on.png +0 -0
- data/public/images/admin/edit.png +0 -0
- data/public/images/admin/error.png +0 -0
- data/public/images/admin/message.png +0 -0
- data/public/images/admin/new-group.png +0 -0
- data/public/images/admin/populate.png +0 -0
- data/public/images/admin/rdo_off.png +0 -0
- data/public/images/admin/rdo_on.png +0 -0
- data/public/stylesheets/sass/admin/group.sass +66 -0
- data/radiant-reader_group-extension.gemspec +134 -0
- data/reader_group_extension.rb +53 -0
- data/spec/controllers/readers_controller_spec.rb +44 -0
- data/spec/controllers/site_controller_spec.rb +64 -0
- data/spec/datasets/group_messages_dataset.rb +32 -0
- data/spec/datasets/group_readers_dataset.rb +49 -0
- data/spec/datasets/group_sites_dataset.rb +11 -0
- data/spec/datasets/groups_dataset.rb +48 -0
- data/spec/models/group_spec.rb +45 -0
- data/spec/models/message_spec.rb +42 -0
- data/spec/models/page_spec.rb +53 -0
- data/spec/models/reader_spec.rb +16 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +36 -0
- metadata +184 -0
data/lib/grouped_page.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module GroupedPage
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval {
|
5
|
+
has_many :permissions
|
6
|
+
has_many :groups, :through => :permissions
|
7
|
+
has_one :group, :foreign_key => 'homepage_id'
|
8
|
+
include InstanceMethods
|
9
|
+
|
10
|
+
# any page with a group-marker is never cached
|
11
|
+
# so that we can continue to return cache hits without care
|
12
|
+
# this check is regrettably expensive
|
13
|
+
|
14
|
+
def cache?
|
15
|
+
self.inherited_groups.empty?
|
16
|
+
end
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
module InstanceMethods
|
21
|
+
|
22
|
+
def visible_to?(reader)
|
23
|
+
permitted_groups = self.inherited_groups
|
24
|
+
return true if permitted_groups.empty?
|
25
|
+
return false if reader.nil?
|
26
|
+
return true if reader.is_admin?
|
27
|
+
return reader.in_any_of_these_groups?(permitted_groups)
|
28
|
+
end
|
29
|
+
|
30
|
+
# this is all very inefficient recursive stuff
|
31
|
+
# but to do it in one pass we'd have to build a list of pages anyway
|
32
|
+
# so there isn't much to gain unless we shift to a different kind of tree
|
33
|
+
|
34
|
+
def inherited_groups
|
35
|
+
if (self.parent.nil?)
|
36
|
+
self.groups
|
37
|
+
else
|
38
|
+
self.groups + self.parent.inherited_groups
|
39
|
+
end
|
40
|
+
end
|
41
|
+
alias permitted_groups inherited_groups
|
42
|
+
|
43
|
+
def has_group?(group)
|
44
|
+
return self.groups.include?(group)
|
45
|
+
end
|
46
|
+
|
47
|
+
def has_inherited_group?(group)
|
48
|
+
return self.inherited_groups.include?(group)
|
49
|
+
end
|
50
|
+
|
51
|
+
def group_is_inherited?(group)
|
52
|
+
return self.has_inherited_group?(group) && !self.has_group?(group)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module GroupedReader
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval {
|
5
|
+
has_many :memberships
|
6
|
+
has_many :groups, :through => :memberships
|
7
|
+
include InstanceMethods
|
8
|
+
alias_method_chain :activate!, :group
|
9
|
+
alias_method_chain :send_functional_message, :group
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
module InstanceMethods
|
14
|
+
|
15
|
+
def find_homepage
|
16
|
+
if homegroup = groups.with_home_page.first
|
17
|
+
homegroup.homepage
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def can_see? (this)
|
22
|
+
permitted_groups = this.permitted_groups
|
23
|
+
permitted_groups.empty? or in_any_of_these_groups?(permitted_groups)
|
24
|
+
end
|
25
|
+
|
26
|
+
def in_any_of_these_groups? (grouplist)
|
27
|
+
(grouplist & groups).any?
|
28
|
+
end
|
29
|
+
|
30
|
+
def is_in? (group)
|
31
|
+
groups.include?(group)
|
32
|
+
end
|
33
|
+
|
34
|
+
# has_group? is ambiguous: with no argument it means 'is this reader grouped at all?'.
|
35
|
+
def has_group?(group=nil)
|
36
|
+
group.nil? ? groups.any? : is_in?(group)
|
37
|
+
end
|
38
|
+
|
39
|
+
# if group-welcome messages exist for this reader's memberships, they will be sent on activation
|
40
|
+
def activate_with_group!
|
41
|
+
send_group_welcomes if activate_without_group!
|
42
|
+
end
|
43
|
+
|
44
|
+
# there may be versions of the functional (eg welcome) messages specific to a group
|
45
|
+
# (which has to be passed through, so this currently only happens when sending out group invitations but ought to be useful elsewhere too)
|
46
|
+
def send_functional_message_with_group(function, group=nil)
|
47
|
+
reset_perishable_token!
|
48
|
+
message = Message.functional(function, group) # returns the standard functional message if no group is supplied, or no group message exists
|
49
|
+
message.deliver_to(self) if message
|
50
|
+
end
|
51
|
+
|
52
|
+
def send_group_invitation_message(group=nil)
|
53
|
+
send_functional_message_with_group('invitation', group)
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def send_group_welcomes
|
59
|
+
groups.each { |g| g.send_welcome_to(self) }
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ReaderActivationsControllerExtensions
|
2
|
+
def self.included(base)
|
3
|
+
|
4
|
+
base.class_eval {
|
5
|
+
|
6
|
+
def default_activated_url_with_group
|
7
|
+
if page = @reader.find_homepage
|
8
|
+
page.url
|
9
|
+
else
|
10
|
+
default_activated_url_without_group
|
11
|
+
end
|
12
|
+
end
|
13
|
+
alias_method_chain :default_activated_url, :group
|
14
|
+
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ReaderNotifierExtensions
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval {
|
5
|
+
|
6
|
+
def message_with_group( reader, message, sender=nil )
|
7
|
+
message_without_group( reader, message, sender )
|
8
|
+
@body[:group] = message.group
|
9
|
+
end
|
10
|
+
alias_method_chain :message, :group
|
11
|
+
|
12
|
+
}
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ReaderSessionsControllerExtensions
|
2
|
+
def self.included(base)
|
3
|
+
|
4
|
+
base.class_eval {
|
5
|
+
|
6
|
+
def default_loggedin_url_with_group
|
7
|
+
if page = @reader_session.reader.find_homepage
|
8
|
+
page.url
|
9
|
+
else
|
10
|
+
default_loggedin_url_without_group
|
11
|
+
end
|
12
|
+
end
|
13
|
+
alias_method_chain :default_loggedin_url, :group
|
14
|
+
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ReadersControllerExtensions
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval { before_filter :ensure_groups_subscribable, :only => [:update, :create] }
|
5
|
+
base.add_form_partial 'readers/memberships'
|
6
|
+
end
|
7
|
+
|
8
|
+
def ensure_groups_subscribable
|
9
|
+
if params[:reader] && params[:reader][:group_ids]
|
10
|
+
params[:reader][:group_ids].each do |g|
|
11
|
+
raise ActiveRecord::RecordNotFound unless Group.find(g).public?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
true
|
15
|
+
rescue ActiveRecord::RecordNotFound
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module SiteControllerExtensions
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval {
|
5
|
+
# to control access without ruining the cache we have set Page.cache? = false
|
6
|
+
# for any page that has a group association. This should prevent the relatively
|
7
|
+
# few private pages from being cached, and it remains safe to return any cached
|
8
|
+
# page we find.
|
9
|
+
|
10
|
+
def find_page_with_group_check(url)
|
11
|
+
page = find_page_without_group_check(url)
|
12
|
+
raise ReaderGroup::PermissionDenied if page && !page.visible_to?(current_reader)
|
13
|
+
page
|
14
|
+
end
|
15
|
+
|
16
|
+
def show_page_with_group_check
|
17
|
+
show_page_without_group_check
|
18
|
+
rescue ReaderGroup::PermissionDenied
|
19
|
+
if current_reader
|
20
|
+
flash[:error] = "Sorry: you don't have permission to see that page."
|
21
|
+
redirect_to reader_permission_denied_url
|
22
|
+
else
|
23
|
+
flash[:explanation] = "The page you have requested is not public. Please log in, and if your account has the necessary permission you will be taken straight there."
|
24
|
+
flash[:error] = "Please log in."
|
25
|
+
store_location
|
26
|
+
redirect_to reader_login_url
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method_chain :find_page, :group_check
|
31
|
+
alias_method_chain :show_page, :group_check
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
namespace :radiant do
|
2
|
+
namespace :extensions do
|
3
|
+
namespace :reader_group do
|
4
|
+
|
5
|
+
desc "Runs the migration of the Reader Group extension"
|
6
|
+
task :migrate => :environment do
|
7
|
+
require 'radiant/extension_migrator'
|
8
|
+
if ENV["VERSION"]
|
9
|
+
ReaderGroupExtension.migrator.migrate(ENV["VERSION"].to_i)
|
10
|
+
else
|
11
|
+
ReaderGroupExtension.migrator.migrate
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Copies public assets of the Reader Group to the instance public/ directory."
|
16
|
+
task :update => :environment do
|
17
|
+
is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
|
18
|
+
puts "Copying assets from ReaderGroupExtension"
|
19
|
+
Dir[ReaderGroupExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
|
20
|
+
path = file.sub(ReaderGroupExtension.root, '')
|
21
|
+
directory = File.dirname(path)
|
22
|
+
mkdir_p RAILS_ROOT + directory
|
23
|
+
cp file, RAILS_ROOT + path
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,66 @@
|
|
1
|
+
@import compass
|
2
|
+
|
3
|
+
body.reversed
|
4
|
+
#content
|
5
|
+
form
|
6
|
+
p.homepage
|
7
|
+
margin: 0
|
8
|
+
label
|
9
|
+
display: inline
|
10
|
+
|
11
|
+
#group_pages, #group_people
|
12
|
+
position: relative
|
13
|
+
float: left
|
14
|
+
overflow: hidden
|
15
|
+
ul
|
16
|
+
li.fake_checkbox
|
17
|
+
margin: 10px 0
|
18
|
+
padding-left: 30px
|
19
|
+
background:
|
20
|
+
image: none
|
21
|
+
repeat: no-repeat
|
22
|
+
position: 4px center
|
23
|
+
a
|
24
|
+
text-decoration: none
|
25
|
+
&.checked
|
26
|
+
background-image: url(/images/admin/chk_on.png)
|
27
|
+
a
|
28
|
+
color: #5da454
|
29
|
+
font-weight: bold
|
30
|
+
&.unchecked
|
31
|
+
background-image: url(/images/admin/chk_off.png)
|
32
|
+
a
|
33
|
+
color: #999
|
34
|
+
font-weight: normal
|
35
|
+
&.waiting
|
36
|
+
background-image: url(/images/admin/spinner.gif)
|
37
|
+
a
|
38
|
+
color: #8c8d8e
|
39
|
+
&.failed
|
40
|
+
background-image: url(/images/admin/error.png)
|
41
|
+
a
|
42
|
+
color: #c00
|
43
|
+
&.inherited
|
44
|
+
background-image: url(/images/admin/chk_auto.png)
|
45
|
+
color: #80aa79
|
46
|
+
input
|
47
|
+
position: absolute
|
48
|
+
left: -999px
|
49
|
+
|
50
|
+
#group_pages
|
51
|
+
width: 30%
|
52
|
+
float: left
|
53
|
+
margin-right: 2%
|
54
|
+
ul
|
55
|
+
ul
|
56
|
+
padding-left: 20px
|
57
|
+
|
58
|
+
#group_people
|
59
|
+
float: right
|
60
|
+
width: 62%
|
61
|
+
ul
|
62
|
+
float: left
|
63
|
+
width: 49%
|
64
|
+
|
65
|
+
#footnotes
|
66
|
+
clear: both
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{radiant-reader_group-extension}
|
8
|
+
s.version = "0.9.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["spanner"]
|
12
|
+
s.date = %q{2010-10-04}
|
13
|
+
s.description = %q{Adds group-based page access control to radiant.}
|
14
|
+
s.email = %q{will@spanner.org}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.markdown"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"README.markdown",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"app/controllers/admin/group_invitations_controller.rb",
|
24
|
+
"app/controllers/admin/groups_controller.rb",
|
25
|
+
"app/controllers/admin/memberships_controller.rb",
|
26
|
+
"app/controllers/admin/permissions_controller.rb",
|
27
|
+
"app/helpers/admin/groups_helper.rb",
|
28
|
+
"app/models/group.rb",
|
29
|
+
"app/models/membership.rb",
|
30
|
+
"app/models/permission.rb",
|
31
|
+
"app/views/admin/group_invitations/new.html.haml",
|
32
|
+
"app/views/admin/group_invitations/preview.html.haml",
|
33
|
+
"app/views/admin/groups/_add_readers.html.haml",
|
34
|
+
"app/views/admin/groups/_form.html.haml",
|
35
|
+
"app/views/admin/groups/_list_head.html.haml",
|
36
|
+
"app/views/admin/groups/_listed.html.haml",
|
37
|
+
"app/views/admin/groups/edit.html.haml",
|
38
|
+
"app/views/admin/groups/index.html.haml",
|
39
|
+
"app/views/admin/groups/new.html.haml",
|
40
|
+
"app/views/admin/groups/remove.html.haml",
|
41
|
+
"app/views/admin/groups/show.html.haml",
|
42
|
+
"app/views/admin/memberships/_reader.html.haml",
|
43
|
+
"app/views/admin/messages/_list_notes.html.haml",
|
44
|
+
"app/views/admin/messages/_message_description.html.haml",
|
45
|
+
"app/views/admin/messages/_message_group.html.haml",
|
46
|
+
"app/views/admin/pages/_listed.html.haml",
|
47
|
+
"app/views/admin/pages/_page_groups.html.haml",
|
48
|
+
"app/views/admin/permissions/_page.html.haml",
|
49
|
+
"app/views/admin/reader_settings/_group_welcomes.html.haml",
|
50
|
+
"app/views/admin/readers/_reader_groups.html.haml",
|
51
|
+
"app/views/messages/show.html.haml",
|
52
|
+
"app/views/reader_activations/_on_activation.html.haml",
|
53
|
+
"app/views/readers/_memberships.html.haml",
|
54
|
+
"app/views/site/not_allowed.html.haml",
|
55
|
+
"config/routes.rb",
|
56
|
+
"db/migrate/001_create_groups.rb",
|
57
|
+
"db/migrate/20090921125654_group_messages.rb",
|
58
|
+
"db/migrate/20091120083119_groups_public.rb",
|
59
|
+
"lib/admin_messages_controller_extensions.rb",
|
60
|
+
"lib/group_message_tags.rb",
|
61
|
+
"lib/group_ui.rb",
|
62
|
+
"lib/grouped_message.rb",
|
63
|
+
"lib/grouped_model.rb",
|
64
|
+
"lib/grouped_page.rb",
|
65
|
+
"lib/grouped_reader.rb",
|
66
|
+
"lib/reader_activations_controller_extensions.rb",
|
67
|
+
"lib/reader_notifier_extensions.rb",
|
68
|
+
"lib/reader_sessions_controller_extensions.rb",
|
69
|
+
"lib/readers_controller_extensions.rb",
|
70
|
+
"lib/site_controller_extensions.rb",
|
71
|
+
"lib/tasks/reader_group_extension_tasks.rake",
|
72
|
+
"pkg/radiant-reader_group-extension-0.9.0.gem",
|
73
|
+
"public/images/admin/chk_auto.png",
|
74
|
+
"public/images/admin/chk_off.png",
|
75
|
+
"public/images/admin/chk_on.png",
|
76
|
+
"public/images/admin/edit.png",
|
77
|
+
"public/images/admin/error.png",
|
78
|
+
"public/images/admin/message.png",
|
79
|
+
"public/images/admin/new-group.png",
|
80
|
+
"public/images/admin/populate.png",
|
81
|
+
"public/images/admin/rdo_off.png",
|
82
|
+
"public/images/admin/rdo_on.png",
|
83
|
+
"public/stylesheets/sass/admin/group.sass",
|
84
|
+
"radiant-reader_group-extension.gemspec",
|
85
|
+
"reader_group_extension.rb",
|
86
|
+
"spec/controllers/readers_controller_spec.rb",
|
87
|
+
"spec/controllers/site_controller_spec.rb",
|
88
|
+
"spec/datasets/group_messages_dataset.rb",
|
89
|
+
"spec/datasets/group_readers_dataset.rb",
|
90
|
+
"spec/datasets/group_sites_dataset.rb",
|
91
|
+
"spec/datasets/groups_dataset.rb",
|
92
|
+
"spec/models/group_spec.rb",
|
93
|
+
"spec/models/message_spec.rb",
|
94
|
+
"spec/models/page_spec.rb",
|
95
|
+
"spec/models/reader_spec.rb",
|
96
|
+
"spec/spec.opts",
|
97
|
+
"spec/spec_helper.rb"
|
98
|
+
]
|
99
|
+
s.homepage = %q{http://github.com/spanner/radiant-reader_group-extension}
|
100
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
101
|
+
s.require_paths = ["lib"]
|
102
|
+
s.rubygems_version = %q{1.3.7}
|
103
|
+
s.summary = %q{Group-based access control for the radiant CMS}
|
104
|
+
s.test_files = [
|
105
|
+
"spec/controllers/readers_controller_spec.rb",
|
106
|
+
"spec/controllers/site_controller_spec.rb",
|
107
|
+
"spec/datasets/group_messages_dataset.rb",
|
108
|
+
"spec/datasets/group_readers_dataset.rb",
|
109
|
+
"spec/datasets/group_sites_dataset.rb",
|
110
|
+
"spec/datasets/groups_dataset.rb",
|
111
|
+
"spec/models/group_spec.rb",
|
112
|
+
"spec/models/message_spec.rb",
|
113
|
+
"spec/models/page_spec.rb",
|
114
|
+
"spec/models/reader_spec.rb",
|
115
|
+
"spec/spec_helper.rb"
|
116
|
+
]
|
117
|
+
|
118
|
+
if s.respond_to? :specification_version then
|
119
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
120
|
+
s.specification_version = 3
|
121
|
+
|
122
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
123
|
+
s.add_runtime_dependency(%q<radiant>, [">= 0.9.0"])
|
124
|
+
s.add_runtime_dependency(%q<radiant-reader-extension>, [">= 0"])
|
125
|
+
else
|
126
|
+
s.add_dependency(%q<radiant>, [">= 0.9.0"])
|
127
|
+
s.add_dependency(%q<radiant-reader-extension>, [">= 0"])
|
128
|
+
end
|
129
|
+
else
|
130
|
+
s.add_dependency(%q<radiant>, [">= 0.9.0"])
|
131
|
+
s.add_dependency(%q<radiant-reader-extension>, [">= 0"])
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_dependency 'application_controller'
|
2
|
+
|
3
|
+
module ReaderGroup
|
4
|
+
class Exception < StandardError
|
5
|
+
def initialize(message = "Sorry: group problem"); super end
|
6
|
+
end
|
7
|
+
class PermissionDenied < Exception
|
8
|
+
def initialize(message = "Sorry: you don't have access to that"); super end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class ReaderGroupExtension < Radiant::Extension
|
13
|
+
version "0.9.0"
|
14
|
+
description "Page (and other) access control for site readers and groups"
|
15
|
+
url "http://spanner.org/radiant/reader_group"
|
16
|
+
|
17
|
+
def activate
|
18
|
+
Group
|
19
|
+
ActiveRecord::Base.send :include, GroupedModel # is_grouped mechanism for any model that can belong_to a group
|
20
|
+
|
21
|
+
Reader.send :include, GroupedReader # defines group associations
|
22
|
+
Page.send :include, GroupedPage # group associations and visibility decisions
|
23
|
+
Message.send :include, GroupedMessage # group association
|
24
|
+
|
25
|
+
ReaderNotifier.send :include, ReaderNotifierExtensions # a couple of new message types
|
26
|
+
SiteController.send :include, SiteControllerExtensions # access control based on group membership
|
27
|
+
ReadersController.send :include, ReadersControllerExtensions # offer subscription to public groups
|
28
|
+
Admin::MessagesController.send :include, AdminMessagesControllerExtensions # supports specification of group on newing of message
|
29
|
+
ReaderSessionsController.send :include, ReaderSessionsControllerExtensions # sends newly logged-in readers to a group home page if one can be found
|
30
|
+
ReaderActivationsController.send :include, ReaderActivationsControllerExtensions # sends newly activated readers to a group home page if one can be found
|
31
|
+
UserActionObserver.instance.send :add_observer!, Group # the usual date-stamping and ownership
|
32
|
+
Page.send :include, GroupMessageTags # extra tags for talking about groups in mailouts
|
33
|
+
|
34
|
+
|
35
|
+
unless defined? admin.group # to avoid duplicate partials
|
36
|
+
Radiant::AdminUI.send :include, GroupUI
|
37
|
+
admin.group = Radiant::AdminUI.load_default_group_regions
|
38
|
+
admin.page.edit.add :parts_bottom, "page_groups", :before => "edit_timestamp"
|
39
|
+
admin.reader.edit.add :form, "reader_groups", :before => "edit_password"
|
40
|
+
admin.message.edit.add :form, "message_group", :before => "edit_subject"
|
41
|
+
admin.reader_setting.index.add :messages, "group_welcomes", :after => "administration"
|
42
|
+
end
|
43
|
+
|
44
|
+
tab("Readers") do
|
45
|
+
add_item 'Groups', '/admin/readers/groups', :before => 'Settings'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def deactivate
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe ReadersController do
|
4
|
+
dataset :groups
|
5
|
+
dataset :pages
|
6
|
+
|
7
|
+
before do
|
8
|
+
controller.stub!(:request).and_return(request)
|
9
|
+
Page.current_site = sites(:test) if defined? Site
|
10
|
+
request.env["HTTP_REFERER"] = 'http://test.host/referer!'
|
11
|
+
end
|
12
|
+
|
13
|
+
# all we're really testing here is the chaining of Reader.homepage
|
14
|
+
# but from a reader pov it's the login behaviour that matters
|
15
|
+
|
16
|
+
describe "a logged-in reader requesting a login form" do
|
17
|
+
before do
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "who has a homed group" do
|
21
|
+
before do
|
22
|
+
login_as_reader(:normal)
|
23
|
+
get :login
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should be redirected to the group's home page" do
|
27
|
+
response.should be_redirect
|
28
|
+
response.should redirect_to(groups(:homed).homepage.url)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "who doesn't have a homed group" do
|
33
|
+
before do
|
34
|
+
login_as_reader(:another)
|
35
|
+
get :login
|
36
|
+
end
|
37
|
+
it "should be redirected to that reader's page" do
|
38
|
+
response.should be_redirect
|
39
|
+
response.should redirect_to(reader_url(readers(:another)))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe SiteController do
|
4
|
+
dataset :groups
|
5
|
+
dataset :pages
|
6
|
+
|
7
|
+
before do
|
8
|
+
controller.stub!(:request).and_return(request)
|
9
|
+
Page.current_site = sites(:test) if defined? Site
|
10
|
+
request.env["HTTP_REFERER"] = 'http://test.host/referer!'
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "with no reader" do
|
14
|
+
before do
|
15
|
+
logout_reader
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "getting an ungrouped page" do
|
19
|
+
it "should render the page" do
|
20
|
+
get :show_page, :url => ''
|
21
|
+
response.should be_success
|
22
|
+
response.body.should == 'Hello world!'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "getting a grouped page" do
|
27
|
+
it "should redirect to login" do
|
28
|
+
get :show_page, :url => 'parent/'
|
29
|
+
response.should be_redirect
|
30
|
+
response.should redirect_to(reader_login_url)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "with a reader" do
|
36
|
+
before do
|
37
|
+
login_as_reader(:normal)
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "getting an ungrouped page" do
|
41
|
+
it "should render the page" do
|
42
|
+
get :show_page, :url => ''
|
43
|
+
response.should be_success
|
44
|
+
response.body.should == 'Hello world!'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "getting a grouped page to which she has access" do
|
49
|
+
it "should render the page" do
|
50
|
+
get :show_page, :url => 'parent/'
|
51
|
+
response.should be_success
|
52
|
+
response.body.should == 'Parent body.'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "getting a grouped page to which she doesn't have access" do
|
57
|
+
it "should redirect to the permission-denied page" do
|
58
|
+
get :show_page, :url => 'news/'
|
59
|
+
response.should be_redirect
|
60
|
+
response.should redirect_to(reader_permission_denied_url)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|