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
@@ -0,0 +1,25 @@
|
|
1
|
+
%tr.node.level-1
|
2
|
+
- render_region :tbody do |tbody|
|
3
|
+
- tbody.name_cell do
|
4
|
+
%td.name
|
5
|
+
%p
|
6
|
+
= link_to group.name, admin_group_url(group)
|
7
|
+
%br
|
8
|
+
= truncate_words(group.description, 40)
|
9
|
+
- tbody.home_cell do
|
10
|
+
%td.home
|
11
|
+
- if group.homepage
|
12
|
+
= link_to group.homepage.title, edit_admin_page_url(group.homepage)
|
13
|
+
- else
|
14
|
+
none
|
15
|
+
- tbody.members_cell do
|
16
|
+
%td.members
|
17
|
+
= link_to group.readers.count, admin_group_url(group)
|
18
|
+
- tbody.pages_cell do
|
19
|
+
%td.pages
|
20
|
+
= link_to group.pages.count, admin_group_url(group)
|
21
|
+
- tbody.modify_cell do
|
22
|
+
%td.actions
|
23
|
+
= link_to_unless_current image('plus') + ' send invitations', new_admin_group_group_invitation_url(group), :class => 'action'
|
24
|
+
= link_to_unless_current image('minus') + ' remove group', admin_group_url(group, :method => 'delete', :confirm => "are you sure you want to completely remove the #{group.name} group?"), :class => 'action'
|
25
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
- include_stylesheet('admin/group')
|
2
|
+
|
3
|
+
= render_region :top
|
4
|
+
|
5
|
+
#groups_table.outset
|
6
|
+
%table#groups.index{:cellspacing=>"0", :border=>"0", :cellpadding=>"0"}
|
7
|
+
%thead
|
8
|
+
= render :partial => 'list_head'
|
9
|
+
%tbody
|
10
|
+
- @groups.each do |group|
|
11
|
+
= render :partial => 'listed', :locals => {:group => group}
|
12
|
+
|
13
|
+
- render_region :bottom do |bottom|
|
14
|
+
- bottom.buttons do
|
15
|
+
#actions
|
16
|
+
= pagination_for @readers
|
17
|
+
%ul
|
18
|
+
%li
|
19
|
+
= link_to image('plus') + " " + "new group", new_admin_group_url
|
@@ -0,0 +1,31 @@
|
|
1
|
+
- include_stylesheet('admin/group')
|
2
|
+
%h1 Remove Group
|
3
|
+
|
4
|
+
%p
|
5
|
+
Are you sure you want to
|
6
|
+
%strong.warning
|
7
|
+
remove permanently
|
8
|
+
the group
|
9
|
+
= h @group.name
|
10
|
+
?
|
11
|
+
|
12
|
+
%p
|
13
|
+
The group has
|
14
|
+
= @group.readers.count
|
15
|
+
= pluralize(@group.readers.count, 'member')
|
16
|
+
and
|
17
|
+
= @group.pages.count
|
18
|
+
= pluralize(@group.pages.count, 'page')
|
19
|
+
\. The pages and readers will not be deleted - just dissociated from one another - and removing the group association from those pages may make them visible to everyone.
|
20
|
+
|
21
|
+
%table#groups.index{:cellspacing=>"0", :border=>"0", :cellpadding=>"0"}
|
22
|
+
%thead
|
23
|
+
= render :partial => 'list_head'
|
24
|
+
%tbody
|
25
|
+
= render :partial => 'listed', :locals => {:group => @group}
|
26
|
+
|
27
|
+
- form_for [:admin, @group], :html => { :method => 'delete' } do
|
28
|
+
%p.buttons
|
29
|
+
%input.button{:type=>"submit", :value=>"Delete Group"}/
|
30
|
+
or
|
31
|
+
= link_to 'Cancel', admin_groups_url
|
@@ -0,0 +1,41 @@
|
|
1
|
+
- include_stylesheet 'admin/group'
|
2
|
+
- body_classes << "reversed"
|
3
|
+
|
4
|
+
%h1
|
5
|
+
Group:
|
6
|
+
= @group.name
|
7
|
+
|
8
|
+
= textilize(@group.description)
|
9
|
+
|
10
|
+
|
11
|
+
#group_pages.box.narrow
|
12
|
+
%h2
|
13
|
+
Private pages
|
14
|
+
%ul
|
15
|
+
- page = Page.respond_to?(:homepage) ? Page.homepage : Page.find_by_parent_id(nil)
|
16
|
+
%div{:id => "page_holder_#{page.id}"}
|
17
|
+
= render :partial => 'admin/permissions/page', :object => page
|
18
|
+
|
19
|
+
#group_people.box.narrow
|
20
|
+
%h2
|
21
|
+
Group members
|
22
|
+
- readers = Reader.find(:all)
|
23
|
+
- total = readers.count
|
24
|
+
- column_length = (readers.count-1) / 2
|
25
|
+
- columns = [readers[0..column_length], readers[column_length+1..readers.count]]
|
26
|
+
- columns.each do |column|
|
27
|
+
%ul.column
|
28
|
+
- column.each do |reader|
|
29
|
+
%div{:id => "reader_holder_#{reader.id}"}
|
30
|
+
= render :partial => 'admin/memberships/reader', :object => reader
|
31
|
+
|
32
|
+
#footnotes
|
33
|
+
%p
|
34
|
+
The pages selected on the left are only visible to the people selected on the right.
|
35
|
+
|
36
|
+
:javascript
|
37
|
+
var h1 = $('group_pages').getHeight();
|
38
|
+
var h2 = $('group_people').getHeight();
|
39
|
+
var h = (h1 > h2) ? h1 : h2
|
40
|
+
$('group_people').setStyle({'height': h + 'px'});
|
41
|
+
$('group_pages').setStyle({'height': h + 'px'});
|
@@ -0,0 +1,9 @@
|
|
1
|
+
- reader ||= @reader
|
2
|
+
- group ||= @group
|
3
|
+
|
4
|
+
- if membership = group.membership_for(reader)
|
5
|
+
%li{:class => "fake_checkbox checked", :id => "reader_#{reader.id}"}
|
6
|
+
= link_to_remote reader.name, :url => admin_group_membership_url(group, membership), :method => 'delete', :loading => "$('reader_#{reader.id}').addClassName('waiting')", :update => "reader_holder_#{reader.id}"
|
7
|
+
- else
|
8
|
+
%li{:class => "fake_checkbox unchecked", :id => "reader_#{reader.id}"}
|
9
|
+
= link_to_remote reader.name, :url => admin_group_memberships_url(group, :reader_id => reader.id), :loading => "$('reader_#{reader.id}').addClassName('waiting')", :update => "reader_holder_#{reader.id}"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
%tr.node{:id => "page-#{page.id}", :class =>"level-#{level}"}
|
2
|
+
- render_region :page, :locals => {:page => page, :level => level} do |node|
|
3
|
+
- node.title_column do
|
4
|
+
%td.page{:style => "padding-left: #{(level * 22) + 4}px"}
|
5
|
+
%span.w1
|
6
|
+
= image('page', :class => "icon", :alt => 'page-icon', :title => '')
|
7
|
+
%span.title
|
8
|
+
= link_to page.title, edit_admin_page_url(page)
|
9
|
+
- node.add_child_column do
|
10
|
+
%td.add-child
|
11
|
+
= link_to image('add-child', :alt => 'add child'), new_admin_page_child_url(page)
|
12
|
+
- node.remove_column do
|
13
|
+
%td.remove
|
14
|
+
= link_to image('remove', :alt => 'remove page'), remove_admin_page_url(page)
|
15
|
+
- page.children.each do |child|
|
16
|
+
= render :partial => 'admin/pages/listed', :locals => {:page => child, :level => level+1}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
- include_stylesheet('admin/group')
|
2
|
+
= hidden_field_tag "page[group_ids][]", ""
|
3
|
+
|
4
|
+
.row
|
5
|
+
%p
|
6
|
+
Allow access only to:
|
7
|
+
- Group.find(:all).each do |g|
|
8
|
+
= check_box_tag "page[group_ids][]", g.id, @page.has_inherited_group?(g), {:id => "page_group_#{g.id}", :disabled => @page.group_is_inherited?(g)}
|
9
|
+
- if @page.group_is_inherited?(g)
|
10
|
+
%label{:for => "page_group_#{g.id}", :class => 'disabled', :title => "group is attached higher in the page tree: can't be detached here"}
|
11
|
+
= g.name
|
12
|
+
- else
|
13
|
+
%label{:for => "page_group_#{g.id}"}
|
14
|
+
= g.name
|
15
|
+
%br
|
16
|
+
%span.formnote
|
17
|
+
Leave all groups unchecked for public access.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
- page ||= @page
|
2
|
+
- group ||= @group
|
3
|
+
|
4
|
+
- liclass = 'loose'
|
5
|
+
- liclass = 'attached' if page.has_group?(group)
|
6
|
+
- liclass = 'inherited' if page.group_is_inherited?(group)
|
7
|
+
|
8
|
+
- if permission = group.permission_for(page)
|
9
|
+
%li{:class => "fake_checkbox checked", :id => "page_#{page.id}"}
|
10
|
+
= link_to_remote page.title, :url => admin_group_permission_url(group, permission), :method => 'delete', :loading => "$('page_#{page.id}').addClassName('waiting')", :update => "page_holder_#{page.id}"
|
11
|
+
|
12
|
+
- elsif page.has_inherited_group?(group)
|
13
|
+
%li{:class => "fake_checkbox inherited", :id => "page_#{page.id}"}
|
14
|
+
= page.title
|
15
|
+
|
16
|
+
- else
|
17
|
+
%li{:class => "fake_checkbox unchecked", :id => "page_#{page.id}"}
|
18
|
+
= link_to_remote page.title, :url => admin_group_permissions_url(group, :page_id => page.id), :loading => "$('page_#{page.id}').addClassName('waiting')", :update => "page_holder_#{page.id}"
|
19
|
+
|
20
|
+
- if page.children.any?
|
21
|
+
%ul
|
22
|
+
- page.children.each do |child|
|
23
|
+
%div{:id => "page_holder_#{child.id}"}
|
24
|
+
= render :partial => 'admin/permissions/page', :object => child
|
@@ -0,0 +1,11 @@
|
|
1
|
+
- Group.all.each do |group|
|
2
|
+
- [:invitation, :welcome].each do |func|
|
3
|
+
- message = Message.functional(:invitation, group)
|
4
|
+
%p.ruled
|
5
|
+
%label
|
6
|
+
= group.name
|
7
|
+
= func
|
8
|
+
- if message
|
9
|
+
= link_to message.subject, edit_admin_message_url(message)
|
10
|
+
- else
|
11
|
+
= link_to image('plus') + " create message", new_admin_group_message_url(group, :function => func), :class => 'create'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
.message
|
2
|
+
%iframe.message_body{:src => preview_group_message_url(@group, @message)}
|
3
|
+
|
4
|
+
- content_for :pagetitle do
|
5
|
+
= @message.subject
|
6
|
+
|
7
|
+
- content_for :marginalia do
|
8
|
+
margin?
|
9
|
+
|
10
|
+
- content_for :breadhead do
|
11
|
+
= link_to @group.name, @group.homepage.url
|
@@ -0,0 +1,10 @@
|
|
1
|
+
- if homepage = current_reader.find_homepage
|
2
|
+
%p
|
3
|
+
Would you like to go straight to the
|
4
|
+
= link_to homepage.title, homepage.url
|
5
|
+
page?
|
6
|
+
|
7
|
+
- elsif session[:return_to]
|
8
|
+
%p
|
9
|
+
Would you like to
|
10
|
+
= link_to ("return to the page you were looking at before you started registering", session[:return_to]) + '?'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
- if Group.subscribable.any?
|
2
|
+
%h3
|
3
|
+
Subscriptions
|
4
|
+
%p{:style => 'margin-top: 0;'}
|
5
|
+
- Group.subscribable.each do |group|
|
6
|
+
= check_box_tag "reader[group_ids][]", group.id, @reader.is_in?(group), :id => "reader_group_#{group.id}"
|
7
|
+
%label{:for => "reader_group_#{group.id}"}
|
8
|
+
= group.name
|
9
|
+
%span.formnote
|
10
|
+
= group.invitation
|
11
|
+
%br
|
data/config/routes.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
ActionController::Routing::Routes.draw do |map|
|
2
|
+
map.namespace :admin, :path_prefix => 'admin/readers' do |admin|
|
3
|
+
admin.resources :groups, :has_many => [:memberships, :permissions, :group_invitations, :messages]
|
4
|
+
end
|
5
|
+
map.resources :groups, :only => [] do |group|
|
6
|
+
group.resources :messages, :only => [:index, :show], :member => [:preview]
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class CreateGroups < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :groups do |t|
|
4
|
+
t.column :name, :string
|
5
|
+
t.column :description, :text
|
6
|
+
t.column :notes, :text
|
7
|
+
t.column :created_at, :datetime
|
8
|
+
t.column :updated_at, :datetime
|
9
|
+
t.column :created_by_id, :integer
|
10
|
+
t.column :updated_by_id, :integer
|
11
|
+
t.column :homepage_id, :integer
|
12
|
+
t.column :site_id, :integer
|
13
|
+
t.column :lock_version, :integer
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table :memberships do |t|
|
17
|
+
t.column :group_id, :integer
|
18
|
+
t.column :reader_id, :integer
|
19
|
+
end
|
20
|
+
|
21
|
+
create_table :permissions do |t|
|
22
|
+
t.column :group_id, :integer
|
23
|
+
t.column :page_id, :integer
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.down
|
28
|
+
drop_table :groups
|
29
|
+
drop_table :memberships
|
30
|
+
drop_table :permissions
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module GroupMessageTags
|
2
|
+
include Radiant::Taggable
|
3
|
+
|
4
|
+
class TagError < StandardError; end
|
5
|
+
|
6
|
+
desc %{
|
7
|
+
The root 'group' tag is not meant to be called directly.
|
8
|
+
All it does is summon a group object so that its fields can be displayed with eg.
|
9
|
+
<pre><code><r:group:name /></code></pre>
|
10
|
+
|
11
|
+
This tag will not throw an exception if there is no group; it will just disappear.
|
12
|
+
}
|
13
|
+
tag 'group' do |tag|
|
14
|
+
tag.locals.group = @mailer_vars ? @mailer_vars[:@group] : tag.locals.page.group
|
15
|
+
tag.expand if tag.locals.group
|
16
|
+
end
|
17
|
+
|
18
|
+
[:name, :description, :url].each do |field|
|
19
|
+
desc %{
|
20
|
+
Displays the #{field} field of the currently relevant group. Works in email messages too.
|
21
|
+
|
22
|
+
<pre><code><r:group:#{field} /></code></pre>
|
23
|
+
}
|
24
|
+
tag "group:#{field}" do |tag|
|
25
|
+
tag.locals.group.send(field)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
desc %{
|
30
|
+
Expands if this group has messages.
|
31
|
+
|
32
|
+
<pre><code><r:group:if_messages>...</r:group:if_messages /></code></pre>
|
33
|
+
}
|
34
|
+
tag "group:if_messages" do |tag|
|
35
|
+
tag.expand if tag.locals.group.messages.ordinary.published.any?
|
36
|
+
end
|
37
|
+
|
38
|
+
desc %{
|
39
|
+
Expands if this group does not have messages.
|
40
|
+
|
41
|
+
<pre><code><r:group:unless_messages>...</r:group:unless_messages /></code></pre>
|
42
|
+
}
|
43
|
+
tag "group:unless_messages" do |tag|
|
44
|
+
tag.expand unless tag.locals.group.messages.ordinary.published.any?
|
45
|
+
end
|
46
|
+
|
47
|
+
desc %{
|
48
|
+
Loops through the non-functional messages (ie not welcomes and reminders) that belong to this group
|
49
|
+
and that have been sent, though not necessarily to the present reader (which is the point, really).
|
50
|
+
|
51
|
+
<pre><code><r:group:messages:each>...</r:group:messages:each /></code></pre>
|
52
|
+
}
|
53
|
+
tag "group:messages" do |tag|
|
54
|
+
tag.locals.messages = tag.locals.group.messages.ordinary.published
|
55
|
+
tag.expand
|
56
|
+
end
|
57
|
+
tag "group:messages:each" do |tag|
|
58
|
+
result = []
|
59
|
+
tag.locals.messages.each do |message|
|
60
|
+
tag.locals.message = message
|
61
|
+
result << tag.expand
|
62
|
+
end
|
63
|
+
result
|
64
|
+
end
|
65
|
+
|
66
|
+
# overridden to add group scope:
|
67
|
+
|
68
|
+
desc %{
|
69
|
+
Returns the url of the show-message page
|
70
|
+
|
71
|
+
<pre><code><r:message:url /></code></pre>
|
72
|
+
}
|
73
|
+
tag "message:url" do |tag|
|
74
|
+
if tag.locals.group
|
75
|
+
group_message_path(tag.locals.group, tag.locals.message)
|
76
|
+
else
|
77
|
+
message_path(tag.locals.message)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
end
|
data/lib/group_ui.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module GroupUI
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
|
6
|
+
attr_accessor :group
|
7
|
+
alias_method :groups, :group
|
8
|
+
|
9
|
+
def load_default_regions_with_group
|
10
|
+
load_default_regions_without_group
|
11
|
+
@group = load_default_group_regions
|
12
|
+
end
|
13
|
+
|
14
|
+
alias_method_chain :load_default_regions, :group
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def load_default_group_regions
|
19
|
+
returning OpenStruct.new do |group|
|
20
|
+
group.edit = Radiant::AdminUI::RegionSet.new do |edit|
|
21
|
+
edit.main.concat %w{edit_header edit_form}
|
22
|
+
edit.form.concat %w{edit_group edit_timestamp edit_buttons edit_membership edit_pages}
|
23
|
+
end
|
24
|
+
group.index = Radiant::AdminUI::RegionSet.new do |index|
|
25
|
+
index.thead.concat %w{name_header home_header members_header pages_header modify_header}
|
26
|
+
index.tbody.concat %w{name_cell home_cell members_cell pages_cell modify_cell}
|
27
|
+
index.bottom.concat %w{buttons}
|
28
|
+
end
|
29
|
+
group.remove = group.index
|
30
|
+
group.new = group.edit
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module GroupedMessage
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval {
|
5
|
+
is_grouped
|
6
|
+
|
7
|
+
include InstanceMethods
|
8
|
+
alias_method_chain :possible_readers, :group
|
9
|
+
alias_method_chain :inactive_readers, :group
|
10
|
+
|
11
|
+
extend ClassMethods
|
12
|
+
class << self
|
13
|
+
alias_method_chain :functional, :group
|
14
|
+
end
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
module InstanceMethods
|
19
|
+
def possible_readers_with_group
|
20
|
+
group ? group.readers.active : possible_readers_without_group
|
21
|
+
end
|
22
|
+
def inactive_readers_with_group
|
23
|
+
group ? group.readers.inactive : inactive_readers_without_group
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module ClassMethods
|
28
|
+
def functional_with_group(function, group=nil)
|
29
|
+
messages = for_function(function)
|
30
|
+
if group
|
31
|
+
messages.for_group(group).first
|
32
|
+
else
|
33
|
+
messages.ungrouped.first
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module GroupedModel
|
2
|
+
def self.included(base)
|
3
|
+
base.extend ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def is_grouped?
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def is_grouped(options={})
|
12
|
+
return if is_grouped?
|
13
|
+
cattr_accessor :group_recipients, :group_donor
|
14
|
+
|
15
|
+
class_eval {
|
16
|
+
extend GroupedModel::GroupedClassMethods
|
17
|
+
include GroupedModel::GroupedInstanceMethods
|
18
|
+
|
19
|
+
def visible_to?(reader)
|
20
|
+
return true unless group
|
21
|
+
return false unless reader
|
22
|
+
return true if reader.is_user?
|
23
|
+
return true if reader.is_in?(group)
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
|
27
|
+
}
|
28
|
+
|
29
|
+
belongs_to :group
|
30
|
+
named_scope :ungrouped, {:conditions => 'group_id IS NULL'}
|
31
|
+
named_scope :for_group, lambda { |g| {:conditions => ["group_id = ?", g]} }
|
32
|
+
named_scope :visible_to, lambda { |reader|
|
33
|
+
groups = reader.nil? ? [] : reader.groups
|
34
|
+
{:conditions => ["group_id IS NULL OR group_id IN(?)", groups.map(&:id).join(',')]}
|
35
|
+
}
|
36
|
+
|
37
|
+
Group.send(:has_many, self.to_s.pluralize.underscore.intern)
|
38
|
+
|
39
|
+
before_create :get_group
|
40
|
+
after_save :give_group
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module GroupedClassMethods
|
45
|
+
def visible
|
46
|
+
ungrouped
|
47
|
+
end
|
48
|
+
|
49
|
+
def is_grouped?
|
50
|
+
true
|
51
|
+
end
|
52
|
+
|
53
|
+
def gets_group_from(association_name)
|
54
|
+
association = reflect_on_association(association_name)
|
55
|
+
raise StandardError "can't find group source '#{association_name}" unless association
|
56
|
+
raise StandardError "#{association.klass} is not grouped and cannot be a group donor" unless association.klass.is_grouped?
|
57
|
+
self.group_donor = association_name
|
58
|
+
end
|
59
|
+
|
60
|
+
def gives_group_to(associations)
|
61
|
+
associations = [associations] unless associations.is_a?(Array)
|
62
|
+
# shall we force is_grouped here?
|
63
|
+
# shall we assume that gets_group_from follows? and find the association somehow?
|
64
|
+
self.group_recipients ||= []
|
65
|
+
self.group_recipients += associations
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module GroupedInstanceMethods
|
70
|
+
|
71
|
+
def visible?
|
72
|
+
!!group
|
73
|
+
end
|
74
|
+
|
75
|
+
def permitted_groups
|
76
|
+
[group]
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
def get_group
|
82
|
+
if self.class.group_donor && group_source = self.send(self.class.group_donor)
|
83
|
+
self.group = group_source.group
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def give_group
|
88
|
+
if self.class.group_recipients
|
89
|
+
self.class.group_recipients.each do |association|
|
90
|
+
send(association).each do |associate|
|
91
|
+
unless associate.group == group
|
92
|
+
associate.group = group
|
93
|
+
associate.save(false)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|