radiant-reader_group-extension 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/.gitignore +2 -0
  2. data/README.markdown +44 -0
  3. data/Rakefile +137 -0
  4. data/VERSION +1 -0
  5. data/app/controllers/admin/group_invitations_controller.rb +84 -0
  6. data/app/controllers/admin/groups_controller.rb +4 -0
  7. data/app/controllers/admin/memberships_controller.rb +42 -0
  8. data/app/controllers/admin/permissions_controller.rb +42 -0
  9. data/app/helpers/admin/groups_helper.rb +36 -0
  10. data/app/models/group.rb +43 -0
  11. data/app/models/membership.rb +13 -0
  12. data/app/models/permission.rb +13 -0
  13. data/app/views/admin/group_invitations/new.html.haml +45 -0
  14. data/app/views/admin/group_invitations/preview.html.haml +63 -0
  15. data/app/views/admin/groups/_add_readers.html.haml +0 -0
  16. data/app/views/admin/groups/_form.html.haml +61 -0
  17. data/app/views/admin/groups/_list_head.html.haml +12 -0
  18. data/app/views/admin/groups/_listed.html.haml +25 -0
  19. data/app/views/admin/groups/edit.html.haml +8 -0
  20. data/app/views/admin/groups/index.html.haml +19 -0
  21. data/app/views/admin/groups/new.html.haml +6 -0
  22. data/app/views/admin/groups/remove.html.haml +31 -0
  23. data/app/views/admin/groups/show.html.haml +41 -0
  24. data/app/views/admin/memberships/_reader.html.haml +9 -0
  25. data/app/views/admin/messages/_list_notes.html.haml +9 -0
  26. data/app/views/admin/messages/_message_description.html.haml +7 -0
  27. data/app/views/admin/messages/_message_group.html.haml +3 -0
  28. data/app/views/admin/pages/_listed.html.haml +16 -0
  29. data/app/views/admin/pages/_page_groups.html.haml +17 -0
  30. data/app/views/admin/permissions/_page.html.haml +24 -0
  31. data/app/views/admin/reader_settings/_group_welcomes.html.haml +11 -0
  32. data/app/views/admin/readers/_reader_groups.html.haml +7 -0
  33. data/app/views/messages/show.html.haml +11 -0
  34. data/app/views/reader_activations/_on_activation.html.haml +10 -0
  35. data/app/views/readers/_memberships.html.haml +11 -0
  36. data/app/views/site/not_allowed.html.haml +4 -0
  37. data/config/routes.rb +8 -0
  38. data/db/migrate/001_create_groups.rb +32 -0
  39. data/db/migrate/20090921125654_group_messages.rb +9 -0
  40. data/db/migrate/20091120083119_groups_public.rb +11 -0
  41. data/lib/admin_messages_controller_extensions.rb +15 -0
  42. data/lib/group_message_tags.rb +82 -0
  43. data/lib/group_ui.rb +37 -0
  44. data/lib/grouped_message.rb +38 -0
  45. data/lib/grouped_model.rb +100 -0
  46. data/lib/grouped_page.rb +59 -0
  47. data/lib/grouped_reader.rb +63 -0
  48. data/lib/reader_activations_controller_extensions.rb +21 -0
  49. data/lib/reader_notifier_extensions.rb +14 -0
  50. data/lib/reader_sessions_controller_extensions.rb +21 -0
  51. data/lib/readers_controller_extensions.rb +22 -0
  52. data/lib/site_controller_extensions.rb +37 -0
  53. data/lib/tasks/reader_group_extension_tasks.rake +28 -0
  54. data/pkg/radiant-reader_group-extension-0.9.0.gem +0 -0
  55. data/public/images/admin/chk_auto.png +0 -0
  56. data/public/images/admin/chk_off.png +0 -0
  57. data/public/images/admin/chk_on.png +0 -0
  58. data/public/images/admin/edit.png +0 -0
  59. data/public/images/admin/error.png +0 -0
  60. data/public/images/admin/message.png +0 -0
  61. data/public/images/admin/new-group.png +0 -0
  62. data/public/images/admin/populate.png +0 -0
  63. data/public/images/admin/rdo_off.png +0 -0
  64. data/public/images/admin/rdo_on.png +0 -0
  65. data/public/stylesheets/sass/admin/group.sass +66 -0
  66. data/radiant-reader_group-extension.gemspec +134 -0
  67. data/reader_group_extension.rb +53 -0
  68. data/spec/controllers/readers_controller_spec.rb +44 -0
  69. data/spec/controllers/site_controller_spec.rb +64 -0
  70. data/spec/datasets/group_messages_dataset.rb +32 -0
  71. data/spec/datasets/group_readers_dataset.rb +49 -0
  72. data/spec/datasets/group_sites_dataset.rb +11 -0
  73. data/spec/datasets/groups_dataset.rb +48 -0
  74. data/spec/models/group_spec.rb +45 -0
  75. data/spec/models/message_spec.rb +42 -0
  76. data/spec/models/page_spec.rb +53 -0
  77. data/spec/models/reader_spec.rb +16 -0
  78. data/spec/spec.opts +6 -0
  79. data/spec/spec_helper.rb +36 -0
  80. metadata +184 -0
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ spec/spec_report.html
data/README.markdown ADDED
@@ -0,0 +1,44 @@
1
+ # Reader Group Extension
2
+
3
+ The basic purpose of this extension is to control access to pages in your public site. It allows you to create a group of readers, and to make pages 9and other site elements) visible only to selected groups. It also provides a useful - and now quite shiny - group-messaging interface and a batch-import function for inviting readers.
4
+
5
+ In combination with our other extensions it also lets you control access to forums, downloads and assets. I hope other people will find the framework useful and apply it to their own requirements.
6
+
7
+ This extension doesn't group your users or affect the admin interface at all, apart from adding (quite a lot of) machinery for looking after groups. As always, readers have their own self-management interface that looks like the rest of your site. They never see the admin pages.
8
+
9
+ This works with multi_site. If you use [our fork](https://github.com/spanner/radiant-paperclipped_multisite-extension/tree) then readers and groups are automatically site-scoped.
10
+
11
+ ## Latest
12
+
13
+ * groups can be marked subscribable, which puts a checkbox to subscribe or unsubscribe on the readers' registration and preference forms. Migration required.
14
+ * messages can each have a different layout
15
+ * group-mailer moved into Reader as general purpose reader-mailer, now using radiant layouts for styled group mailouts
16
+ * group access control consolidated in `is_grouped` function to simplify maintenance of other extensions
17
+ * invitations factored out, made reasonably restful
18
+
19
+ ## Status
20
+
21
+ This has been brought across from a previous version that grouped users instead of working in the reader framework, so it's a mixture of the well-used and the just-invented, but the tests are fairly comprehensive. It's in use on a couple of biggish sites and seems fairly robust.
22
+
23
+ ## Requirements
24
+
25
+ The [reader](https://github.com/spanner/radiant-reader-extension/tree) and [submenu](https://github.com/spanner/radiant-submenu-extension/tree) extensions.
26
+
27
+ ## Installation
28
+
29
+ Once you've got the reader extension in, the rest is easy:
30
+
31
+ git submodule add git://github.com/spanner/radiant-reader_group-extension.git vendor/extensions/reader_group
32
+ rake radiant:extensions:reader_group:migrate
33
+ rake radiant:extensions:reader_group:update
34
+
35
+ ## Bugs and comments
36
+
37
+ In [lighthouse](http://spanner.lighthouseapp.com/projects/26912-radiant-extensions), please, or for little things an email or github message is always welcome.
38
+
39
+ ## Author and copyright
40
+
41
+ * Copyright spanner ltd 2007-9.
42
+ * Released under the same terms as Rails and/or Radiant.
43
+ * Contact will at spanner.org
44
+
data/Rakefile ADDED
@@ -0,0 +1,137 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gem|
4
+ gem.name = "radiant-reader_group-extension"
5
+ gem.summary = %Q{Group-based access control for the radiant CMS}
6
+ gem.description = %Q{Adds group-based page access control to radiant.}
7
+ gem.email = "will@spanner.org"
8
+ gem.homepage = "http://github.com/spanner/radiant-reader_group-extension"
9
+ gem.authors = ["spanner"]
10
+ gem.add_dependency "radiant", ">= 0.9.0"
11
+ gem.add_dependency 'radiant-reader-extension'
12
+ end
13
+ rescue LoadError
14
+ puts "Jeweler (or a dependency) not available. This is only required if you plan to package reader_group as a gem."
15
+ end
16
+
17
+ # In rails 1.2, plugins aren't available in the path until they're loaded.
18
+ # Check to see if the rspec plugin is installed first and require
19
+ # it if it is. If not, use the gem version.
20
+
21
+ # Determine where the RSpec plugin is by loading the boot
22
+ unless defined? RADIANT_ROOT
23
+ ENV["RAILS_ENV"] = "test"
24
+ case
25
+ when ENV["RADIANT_ENV_FILE"]
26
+ require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
27
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
28
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
29
+ else
30
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
31
+ end
32
+ end
33
+
34
+ require 'rake'
35
+ require 'rake/rdoctask'
36
+ require 'rake/testtask'
37
+
38
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
39
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
40
+ require 'spec/rake/spectask'
41
+ require 'cucumber'
42
+ require 'cucumber/rake/task'
43
+
44
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
45
+ Object.send(:remove_const, :RADIANT_ROOT)
46
+
47
+ extension_root = File.expand_path(File.dirname(__FILE__))
48
+
49
+ task :default => :spec
50
+ task :stats => "spec:statsetup"
51
+
52
+ desc "Run all specs in spec directory"
53
+ Spec::Rake::SpecTask.new(:spec) do |t|
54
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
55
+ t.spec_files = FileList['spec/**/*_spec.rb']
56
+ end
57
+
58
+ task :features => 'spec:integration'
59
+
60
+ namespace :spec do
61
+ desc "Run all specs in spec directory with RCov"
62
+ Spec::Rake::SpecTask.new(:rcov) do |t|
63
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
64
+ t.spec_files = FileList['spec/**/*_spec.rb']
65
+ t.rcov = true
66
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
67
+ end
68
+
69
+ desc "Print Specdoc for all specs"
70
+ Spec::Rake::SpecTask.new(:doc) do |t|
71
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
72
+ t.spec_files = FileList['spec/**/*_spec.rb']
73
+ end
74
+
75
+ [:models, :controllers, :views, :helpers].each do |sub|
76
+ desc "Run the specs under spec/#{sub}"
77
+ Spec::Rake::SpecTask.new(sub) do |t|
78
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
79
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
80
+ end
81
+ end
82
+
83
+ desc "Run the Cucumber features"
84
+ Cucumber::Rake::Task.new(:integration) do |t|
85
+ t.fork = true
86
+ t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'pretty')]
87
+ # t.feature_pattern = "#{extension_root}/features/**/*.feature"
88
+ t.profile = "default"
89
+ end
90
+
91
+ # Setup specs for stats
92
+ task :statsetup do
93
+ require 'code_statistics'
94
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
95
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
96
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
97
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
98
+ ::CodeStatistics::TEST_TYPES << "Model specs"
99
+ ::CodeStatistics::TEST_TYPES << "View specs"
100
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
101
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
102
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
103
+ end
104
+
105
+ namespace :db do
106
+ namespace :fixtures do
107
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
108
+ task :load => :environment do
109
+ require 'active_record/fixtures'
110
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
111
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
112
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ desc 'Generate documentation for the reader_group extension.'
120
+ Rake::RDocTask.new(:rdoc) do |rdoc|
121
+ rdoc.rdoc_dir = 'rdoc'
122
+ rdoc.title = 'ReaderGroupExtension'
123
+ rdoc.options << '--line-numbers' << '--inline-source'
124
+ rdoc.rdoc_files.include('README')
125
+ rdoc.rdoc_files.include('lib/**/*.rb')
126
+ end
127
+
128
+ # For extensions that are in transition
129
+ desc 'Test the reader_group extension.'
130
+ Rake::TestTask.new(:test) do |t|
131
+ t.libs << 'lib'
132
+ t.pattern = 'test/**/*_test.rb'
133
+ t.verbose = true
134
+ end
135
+
136
+ # Load any custom rakefiles for extension
137
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.9.0
@@ -0,0 +1,84 @@
1
+ class Admin::GroupInvitationsController < ApplicationController
2
+ require 'csv'
3
+
4
+ before_filter :find_group, :only => [:new, :create]
5
+
6
+ def new
7
+
8
+ end
9
+
10
+ def create
11
+ if params[:invite_reader] || params[:import_reader]
12
+ notice = []
13
+ if invites = params[:invite_reader]
14
+ invite_counter = 0
15
+ invites.each do |i|
16
+ if reader = Reader.find_by_id(i)
17
+ reader.groups << @group unless reader.is_in?(@group)
18
+ @group.send_welcome_to(reader)
19
+ invite_counter += 1
20
+ end
21
+ end
22
+ notice << "#{invite_counter} existing"
23
+ end
24
+ if imports = params[:import_reader]
25
+ import_counter = 0
26
+ imports.each do |i|
27
+ r = params["reader_#{i}".to_sym]
28
+ r[:password] = r[:password_confirmation] = generate_password
29
+ reader = Reader.new(r)
30
+ reader.clear_password = r[:password]
31
+ if reader.save!
32
+ reader.groups << @group
33
+ reader.send_group_invitation_message(@group)
34
+ import_counter += 1
35
+ end
36
+ notice << "#{import_counter} new"
37
+ end
38
+ end
39
+ flash[:notice] = notice.join(' and ') + " readers invited into the #{@group.name} group"
40
+ redirect_to admin_group_url(@group)
41
+ else
42
+ if params[:readerlist] && @readers = readers_from_csv(params[:readerlist])
43
+ render :action => 'preview'
44
+ else
45
+ render :action => 'new'
46
+ end
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def find_group
53
+ @group = Group.find(params[:group_id])
54
+ end
55
+
56
+ def readers_from_csv(readerdata)
57
+ readers = []
58
+ CSV::StringReader.parse(readerdata).each do |line|
59
+ csv = line.collect {|value| value ? value.gsub(/^ */, '').chomp : ''}
60
+ input = {}
61
+ input[:honorific] = csv.shift if Radiant::Config['reader.use_honorifics?']
62
+ input[:password] = input[:password_confirmation] = generate_password
63
+ [:name, :email, :login, :phone].each {|field| input[field] = csv.shift}
64
+ r = Reader.find_by_email(input[:email]) || Reader.new(input)
65
+ r.login = generate_login(input[:name]) if r.login.blank?
66
+ r.valid? # so that errors can be shown on the confirmation form
67
+ readers << r
68
+ end
69
+ readers
70
+ end
71
+
72
+ def generate_login(name)
73
+ names = name.split
74
+ initials = names.map {|n| n.slice(0,1)}
75
+ initials.pop
76
+ initials.push(names.last).join('_').downcase
77
+ end
78
+
79
+ def generate_password(length=12)
80
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("1".."9").to_a
81
+ Array.new(length, '').collect{chars[rand(chars.size)]}.join
82
+ end
83
+
84
+ end
@@ -0,0 +1,4 @@
1
+ class Admin::GroupsController < Admin::ResourceController
2
+ skip_before_filter :load_model
3
+ before_filter :load_model, :except => :index # we want the filter to run before :show too
4
+ end
@@ -0,0 +1,42 @@
1
+ class Admin::MembershipsController < ApplicationController
2
+
3
+ before_filter :find_group
4
+
5
+ def index
6
+ redirect_to admin_group_url(@group)
7
+ end
8
+
9
+ def create
10
+ @reader = Reader.find(params[:reader_id])
11
+ raise ActiveRecord::RecordNotFound unless @reader
12
+ @membership = Membership.find_or_create_by_reader_id_and_group_id(@reader.id, @group.id)
13
+ respond_to do |format|
14
+ format.html {
15
+ flash[:notice] = "#{@reader.name} added to group #{@group.name}"
16
+ redirect_to admin_group_url(@group)
17
+ }
18
+ format.js { render :partial => 'reader' }
19
+ end
20
+ end
21
+
22
+ def destroy
23
+ @membership = @group.memberships.find(params[:id])
24
+ @reader = @membership.reader
25
+ @membership.delete if @membership
26
+ respond_to do |format|
27
+ format.html {
28
+ flash[:notice] = "#{@reader.name} removed from group #{@group.name}" if @membership
29
+ redirect_to admin_group_url(@group)
30
+ }
31
+ format.js { render :partial => 'reader' }
32
+ end
33
+ end
34
+
35
+ protected
36
+
37
+ def find_group
38
+ @group = Group.find(params[:group_id])
39
+ raise ActiveRecord::RecordNotFound unless @group
40
+ end
41
+
42
+ end
@@ -0,0 +1,42 @@
1
+ class Admin::PermissionsController < ApplicationController
2
+
3
+ before_filter :find_group
4
+
5
+ def index
6
+ redirect_to admin_group_url(@group)
7
+ end
8
+
9
+ def create
10
+ @page = Page.find(params[:page_id])
11
+ raise ActiveRecord::RecordNotFound unless @page
12
+ @permission = Permission.find_or_create_by_page_id_and_group_id(@page.id, @group.id)
13
+ respond_to do |format|
14
+ format.html {
15
+ flash[:notice] = "#{@page.name} bound to group #{@group.name}"
16
+ redirect_to admin_group_url(@group)
17
+ }
18
+ format.js { render :partial => 'page' }
19
+ end
20
+ end
21
+
22
+ def destroy
23
+ @permission = @group.permissions.find(params[:id])
24
+ @page = @permission.page
25
+ @permission.delete if @permission
26
+ respond_to do |format|
27
+ format.html {
28
+ flash[:notice] = "#{@page.name} released from group #{@group.name}"
29
+ redirect_to admin_group_url(@group)
30
+ }
31
+ format.js { render :partial => 'page' }
32
+ end
33
+ end
34
+
35
+ protected
36
+
37
+ def find_group
38
+ @group = Group.find(params[:group_id])
39
+ raise ActiveRecord::RecordNotFound unless @group
40
+ end
41
+
42
+ end
@@ -0,0 +1,36 @@
1
+ module Admin::GroupsHelper
2
+
3
+ def message_preview(subject, body, reader)
4
+ preview = <<EOM
5
+ From: #{current_user.name} &lt;#{current_user.email}&gt;
6
+ To: #{reader.name} &lt;#{reader.email}&gt;
7
+ Date: #{Time.now.to_date.to_s :long}
8
+ <strong>Subject: #{subject}</strong>
9
+
10
+ Dear #{reader.name},
11
+
12
+ #{body}
13
+
14
+ EOM
15
+ simple_format(preview)
16
+ end
17
+
18
+ def choose_page(object, field, select_options={})
19
+ root = Page.respond_to?(:homepage) ? Page.homepage : Page.find_by_parent_id(nil)
20
+ options = page_option_branch(root)
21
+ options.unshift ['<none>', nil]
22
+ select object, field, options, select_options
23
+ end
24
+
25
+ def page_option_branch(page, depth=0)
26
+ options = []
27
+ unless page.title.first == '_'
28
+ options << ["#{". " * depth}#{h(page.title)}", page.id]
29
+ page.children.each do |child|
30
+ options += page_option_branch(child, depth + 1)
31
+ end
32
+ end
33
+ options
34
+ end
35
+
36
+ end
@@ -0,0 +1,43 @@
1
+ class Group < ActiveRecord::Base
2
+
3
+ is_site_scoped if defined? ActiveRecord::SiteNotFound
4
+ default_scope :order => 'name'
5
+
6
+ belongs_to :created_by, :class_name => 'User'
7
+ belongs_to :updated_by, :class_name => 'User'
8
+ belongs_to :homepage, :class_name => 'Page'
9
+
10
+ has_many :messages
11
+ has_many :permissions
12
+ has_many :pages, :through => :permissions
13
+ has_many :memberships
14
+ has_many :readers, :through => :memberships
15
+
16
+ validates_presence_of :name
17
+ validates_uniqueness_of :name
18
+
19
+ named_scope :with_home_page, { :conditions => "homepage_id IS NOT NULL", :include => :homepage }
20
+ named_scope :subscribable, { :conditions => "public = 1" }
21
+ named_scope :unsubscribable, { :conditions => "public = 0" }
22
+
23
+ def url
24
+ homepage.url if homepage
25
+ end
26
+
27
+ def send_welcome_to(reader)
28
+ if reader.activated? # welcomes will be triggered again on activation
29
+ message = messages.for_function('group_welcome').first # only if a group_welcome message exists *belonging to this group*
30
+ message.deliver_to(reader) if message # (the belonging also allows us to mention the group in the message)
31
+ end
32
+ end
33
+
34
+ def permission_for(page)
35
+ self.permissions.for(page).first
36
+ end
37
+
38
+ def membership_for(reader)
39
+ self.memberships.for(reader).first
40
+ end
41
+
42
+ end
43
+
@@ -0,0 +1,13 @@
1
+ class Membership < ActiveRecord::Base
2
+
3
+ belongs_to :group
4
+ belongs_to :reader
5
+
6
+ named_scope :for, lambda { |reader|
7
+ {
8
+ :conditions => ["memberships.reader_id = ?", reader.id]
9
+ }
10
+ }
11
+
12
+ end
13
+
@@ -0,0 +1,13 @@
1
+ class Permission < ActiveRecord::Base
2
+
3
+ belongs_to :group
4
+ belongs_to :page
5
+
6
+ named_scope :for, lambda { |page|
7
+ {
8
+ :conditions => ["permissions.page_id = ?", page.id]
9
+ }
10
+ }
11
+
12
+ end
13
+
@@ -0,0 +1,45 @@
1
+ - include_stylesheet('admin/group')
2
+
3
+ %h1
4
+ Invite people into
5
+ = @group.name
6
+
7
+ %p
8
+ This is a quick way to bring a group of people into the system in one go.
9
+ Enter a comma-separated list of names and email addresses below (one person per line)
10
+ and each of those people will be invited into the system and issued an account with a vaguely adequate username
11
+ and entirely random password. Anyone who is already here will just be added to the group.
12
+
13
+ - if message = @group.messages.for_function('invitation').first
14
+ %p
15
+ %strong
16
+ You may want to check the group's
17
+ = link_to "invitation message", admin_message_url(message)
18
+ before going any further.
19
+
20
+ - form_for :group, @group, :url => admin_group_group_invitations_url(@group), :html => {:id => 'preview_form', :method => 'post'} do
21
+ .form-area
22
+ %p
23
+ %label{:for => "readerlist"}
24
+ List of people
25
+ - if Radiant::Config['reader.use_honorifics?']
26
+ title or rank,
27
+ name, email, [login], [phone]
28
+ %br
29
+ = text_area_tag "readerlist", params[:readerlist], :class => "textarea", :style => "width: 100%; height: 240px;"
30
+
31
+ %p.buttons
32
+ = submit_tag 'preview import', :class => 'button'
33
+ or
34
+ = link_to "Cancel", admin_group_url(@group)
35
+
36
+ %p
37
+ When you press the 'preview import' button, the list will be repeated back to you to show exactly what reader accounts we are going to create and/or invite into this group.
38
+ You can make changes at that stage, but please check the list formatting carefully: be sure there are no commas other than where you want them and that the email addresses are correct.
39
+
40
+ - else
41
+ %p.haserror
42
+ Before you can proceed, you will need to
43
+ = link_to("create an invitation message", new_admin_group_message_url(@group, :function => 'invitation')) + '.'
44
+ for this group.
45
+
@@ -0,0 +1,63 @@
1
+ - include_stylesheet('admin/group')
2
+
3
+ %h1
4
+ Populate:
5
+ = link_to @group.name, admin_group_url(@group)
6
+ = render :partial => 'admin/groups/actions', :locals => {:group => @group}
7
+
8
+ - form_for :group, @group, :url => admin_group_group_invitations_url(@group), :html => {:id => 'confirmation_form', :method => 'post'} do
9
+ .form-area
10
+ %h2 Please check the invitation list
11
+ %ul
12
+ %li Fields in red have validation problems. That usually means an email address or login needs checking. Hover your mouse pointer over the affected field to find out more.
13
+ %li Fields in grey show that we already have that person here (based on their email address). You can still bring them into the group but you can't edit their details here.
14
+ %li Edit anything that needs it, uncheck the box next to anyone that you don't want to invite after all, and hit the 'invite these people' button to send out messages.
15
+ %table#import
16
+ %thead
17
+ %tr
18
+ %th
19
+ - if Radiant::Config['reader.use_honorifics?']
20
+ %th Title or rank
21
+ %th Full name
22
+ %th Email
23
+ %th Login
24
+ %th Phone
25
+ %tbody
26
+ - i = 0
27
+ - @readers.each do |reader|
28
+ - if reader.new_record?
29
+ %tr.import
30
+ %td
31
+ = check_box_tag "import_reader[]", i, reader.valid?
32
+ - if Radiant::Config['reader.use_honorifics?']
33
+ %td
34
+ = text_field_tag "reader_#{i}[honorific]", reader.honorific, :class => "preview#{ ' with_error' if reader.errors.on(:honorific)}", :title => reader.errors.on(:honorific)
35
+ %td
36
+ = text_field_tag "reader_#{i}[name]", reader.name, :class => "preview#{ ' with_error' if reader.errors.on(:name)}", :title => reader.errors.on(:name)
37
+ %td
38
+ = text_field_tag "reader_#{i}[email]", reader.email, :class => "preview#{ ' with_error' if reader.errors.on(:email)}", :title => reader.errors.on(:email)
39
+ %td
40
+ = text_field_tag "reader_#{i}[login]", reader.login, :class => "preview#{ ' with_error' if reader.errors.on(:login)}", :title => reader.errors.on(:login)
41
+ %td
42
+ = text_field_tag "reader_#{i}[phone]", reader.phone, :class => "preview#{ ' with_error' if reader.errors.on(:phone)}", :title => reader.errors.on(:phone)
43
+ - else
44
+ %tr.invite
45
+ %td
46
+ = check_box_tag "invite_reader[]", reader.id, {:checked => true}
47
+ - if Radiant::Config['reader.use_honorifics?']
48
+ %td
49
+ = text_field_tag "reader_#{i}[honorific]", reader.honorific, :class => "preview#{ ' with_error' if reader.errors.on(:honorific)}", :title => reader.errors.on(:honorific), :disabled => true
50
+ %td
51
+ = text_field_tag "reader_#{i}[name]", reader.name, :class => "preview#{ ' with_error' if reader.errors.on(:name)}", :title => reader.errors.on(:name), :disabled => true
52
+ %td
53
+ = text_field_tag "reader_#{i}[email]", reader.email, :class => "preview#{ ' with_error' if reader.errors.on(:email)}", :title => reader.errors.on(:email), :disabled => true
54
+ %td
55
+ = text_field_tag "reader_#{i}[login]", reader.login, :class => "preview#{ ' with_error' if reader.errors.on(:login)}", :title => reader.errors.on(:login), :disabled => true
56
+ %td
57
+ = text_field_tag "reader_#{i}[phone]", reader.phone, :class => "preview#{ ' with_error' if reader.errors.on(:phone)}", :title => reader.errors.on(:phone)
58
+ - i = i + 1
59
+
60
+ %p.buttons
61
+ = submit_tag 'Invite these people into the group', :name => 'confirm', :class => 'button'
62
+ or
63
+ = link_to 'start again', new_admin_group_group_invitation_url(@group)
File without changes
@@ -0,0 +1,61 @@
1
+ - form_for [:admin, @group] do |f|
2
+ .form-area
3
+ = render_region :form_top
4
+ = hidden_field 'group', 'lock_version'
5
+
6
+ - render_region :form do |form|
7
+ - form.edit_group do
8
+ #group
9
+ %p.title
10
+ = f.label :name
11
+ = f.text_field 'name', :maxlength => 100, :class => "textbox"
12
+ %p.homepage
13
+ = f.label :homepage_id, "Group home page:"
14
+ = choose_page 'group', 'homepage_id', {:selected =>@group.homepage_id}
15
+
16
+ - form.edit_timestamp do
17
+ = updated_stamp @group
18
+ - form.edit_buttons do
19
+ %p.buttons
20
+ = save_model_button @group
21
+ = save_model_and_continue_editing_button @group
22
+ or
23
+ = link_to "Cancel", admin_groups_url
24
+
25
+ - form.edit_membership do
26
+ - unless @group.new_record?
27
+ #group_people.box.narrow
28
+ %h3
29
+ Group members
30
+ - readers = Reader.find(:all)
31
+ - total = readers.count
32
+ - column_length = (readers.count-1) / 2
33
+ - columns = [readers[0..column_length], readers[column_length+1..readers.count]]
34
+ - columns.each do |column|
35
+ %ul.column
36
+ - column.each do |reader|
37
+ %div{:id => "reader_holder_#{reader.id}"}
38
+ = render :partial => 'admin/memberships/reader', :object => reader
39
+
40
+ - form.edit_pages do
41
+ - unless @group.new_record?
42
+ #group_pages.box.narrow
43
+ %h3
44
+ Private pages
45
+ %ul
46
+ - page = Page.respond_to?(:homepage) ? Page.homepage : Page.find_by_parent_id(nil)
47
+ %div{:id => "page_holder_#{page.id}"}
48
+ = render :partial => 'admin/permissions/page', :object => page
49
+
50
+ :javascript
51
+ var h1 = $('group_pages').getHeight();
52
+ var h2 = $('group_people').getHeight();
53
+ var h = (h1 > h2) ? h1 : h2
54
+ $('group_people').setStyle({'height': h + 'px'});
55
+ $('group_pages').setStyle({'height': h + 'px'});
56
+
57
+ #footnotes
58
+ %p
59
+ The pages selected on the left are only visible to the people selected on the right.
60
+
61
+
@@ -0,0 +1,12 @@
1
+ %tr
2
+ - render_region :thead do |thead|
3
+ - thead.name_header do
4
+ %th.group Name
5
+ - thead.home_header do
6
+ %th.home Home page
7
+ - thead.members_header do
8
+ %th.members Members
9
+ - thead.pages_header do
10
+ %th.pages Pages
11
+ - thead.modify_header do
12
+ %th.modify Modify