radiant-reader_group-extension 0.9.0
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.
- 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
|