radiant-reader-extension 1.3.13 → 2.0.0.rc4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -2
- data/Rakefile +0 -19
- data/app/controllers/admin/group_invitations_controller.rb +78 -0
- data/app/controllers/admin/groups_controller.rb +8 -0
- data/app/controllers/admin/memberships_controller.rb +42 -0
- data/app/controllers/admin/messages_controller.rb +8 -3
- data/app/controllers/admin/permissions_controller.rb +42 -0
- data/app/controllers/admin/reader_configuration_controller.rb +0 -1
- data/app/controllers/admin/readers_controller.rb +1 -1
- data/app/controllers/password_resets_controller.rb +5 -5
- data/app/controllers/reader_action_controller.rb +13 -33
- data/app/controllers/reader_activations_controller.rb +4 -8
- data/app/controllers/reader_sessions_controller.rb +15 -26
- data/app/controllers/readers_controller.rb +26 -9
- data/app/helpers/reader_helper.rb +45 -17
- data/app/models/group.rb +80 -0
- data/app/models/membership.rb +13 -0
- data/app/models/message.rb +10 -7
- data/app/models/permission.rb +11 -0
- data/app/models/reader.rb +79 -35
- data/app/models/reader_notifier.rb +1 -0
- data/app/views/admin/group_invitations/new.html.haml +31 -0
- data/app/views/admin/group_invitations/preview.html.haml +58 -0
- data/app/views/admin/groups/_add_readers.html.haml +0 -0
- data/app/views/admin/groups/_form.html.haml +26 -0
- data/app/views/admin/groups/_list_head.html.haml +12 -0
- data/app/views/admin/groups/edit.html.haml +9 -0
- data/app/views/admin/groups/index.html.haml +44 -0
- data/app/views/admin/groups/new.html.haml +7 -0
- data/app/views/admin/groups/remove.html.haml +31 -0
- data/app/views/admin/groups/show.html.haml +74 -0
- data/app/views/admin/memberships/_reader.html.haml +9 -0
- data/app/views/admin/messages/_function.haml +31 -0
- data/app/views/admin/messages/_list_function.haml +7 -3
- data/app/views/admin/messages/_list_notes.html.haml +9 -0
- data/app/views/admin/messages/_message_description.html.haml +5 -1
- data/app/views/admin/messages/_message_group.html.haml +5 -0
- data/app/views/admin/messages/index.haml +4 -4
- data/app/views/admin/messages/show.html.haml +15 -15
- data/app/views/admin/pages/_listed.html.haml +16 -0
- data/app/views/admin/pages/_page_groups.html.haml +13 -0
- data/app/views/admin/permissions/_page.html.haml +24 -0
- data/app/views/admin/reader_configuration/edit.html.haml +3 -1
- data/app/views/admin/reader_configuration/show.html.haml +4 -2
- data/app/views/admin/readers/_form.html.haml +7 -7
- data/app/views/admin/readers/_password_fields.html.haml +6 -6
- data/app/views/admin/readers/_reader_groups.html.haml +7 -0
- data/app/views/admin/readers/edit.html.haml +2 -1
- data/app/views/admin/readers/index.html.haml +5 -2
- data/app/views/password_resets/create.html.haml +13 -8
- data/app/views/password_resets/edit.html.haml +26 -26
- data/app/views/password_resets/new.html.haml +28 -25
- data/app/views/reader_activations/_activation_required.haml +2 -2
- data/app/views/reader_activations/show.html.haml +11 -13
- data/app/views/reader_sessions/_login_form.html.haml +13 -12
- data/app/views/reader_sessions/new.html.haml +6 -8
- data/app/views/readers/_controls.html.haml +11 -9
- data/app/views/readers/_form.html.haml +32 -33
- data/app/views/readers/_memberships.html.haml +11 -0
- data/app/views/readers/edit.html.haml +11 -11
- data/app/views/readers/index.html.haml +9 -10
- data/app/views/readers/login.html.haml +10 -12
- data/app/views/readers/new.html.haml +11 -13
- data/app/views/readers/permission_denied.html.haml +7 -7
- data/app/views/readers/show.html.haml +7 -8
- data/app/views/shared/_standard_reader_parts.html.haml +14 -0
- data/app/views/site/not_allowed.html.haml +4 -0
- data/config/initializers/authlogic_connect_config.rb +12 -0
- data/config/initializers/radiant_config.rb +1 -0
- data/config/locales/en.yml +217 -177
- data/config/routes.rb +5 -0
- data/db/migrate/20090921125654_group_messages.rb +35 -0
- data/db/migrate/20091120083119_groups_public.rb +11 -0
- data/db/migrate/20110214101339_multiple_ownership.rb +13 -0
- data/lib/controller_extensions.rb +1 -1
- data/lib/group_tags.rb +65 -0
- data/lib/grouped_model.rb +125 -0
- data/lib/grouped_page.rb +39 -0
- data/lib/message_tags.rb +183 -0
- data/lib/radiant-reader-extension.rb +8 -0
- data/lib/reader_admin_ui.rb +29 -6
- data/lib/reader_tags.rb +7 -183
- data/lib/sanitize/config/generous.rb +49 -0
- data/lib/site_controller_extensions.rb +35 -0
- data/public/javascripts/reader.js +1 -1
- data/public/stylesheets/sass/reader.sass +18 -8
- data/radiant-reader-extension.gemspec +30 -176
- data/reader_extension.rb +31 -23
- data/spec/controllers/admin/messages_controller_spec.rb +1 -1
- data/spec/controllers/admin/readers_controller_spec.rb +0 -1
- data/spec/controllers/password_resets_controller_spec.rb +1 -1
- data/spec/controllers/reader_activations_controller_spec.rb +1 -1
- data/spec/controllers/readers_controller_spec.rb +67 -40
- data/spec/controllers/site_controller_spec.rb +63 -0
- data/spec/datasets/readers_dataset.rb +100 -11
- data/spec/models/group_spec.rb +46 -0
- data/spec/models/message_spec.rb +40 -15
- data/spec/models/page_spec.rb +81 -0
- data/spec/models/reader_notifier_spec.rb +1 -1
- data/spec/models/reader_spec.rb +17 -12
- metadata +99 -67
- data/.gitignore +0 -2
- data/VERSION +0 -1
- data/app/views/readers/_standard_parts.html.haml +0 -23
- data/spec/datasets/messages_dataset.rb +0 -49
- data/spec/datasets/reader_layouts_dataset.rb +0 -26
- data/spec/datasets/reader_sites_dataset.rb +0 -10
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'sanitize'
|
2
|
+
require "sanitize/config/generous"
|
2
3
|
|
3
4
|
module ReaderHelper
|
4
5
|
def standard_gravatar_for(reader=nil, url=nil)
|
5
6
|
size = Radiant::Config['forum.gravatar_size'] || 40
|
6
7
|
url ||= reader_url(reader)
|
7
8
|
gravatar = gravatar_for(reader, {:size => size}, {:class => 'gravatar offset', :width => size, :height => size})
|
8
|
-
link_to
|
9
|
+
content_tag(:div, link_to(gravatar, url), :class => "speaker")
|
9
10
|
end
|
10
11
|
|
11
12
|
def gravatar_for(reader=nil, gravatar_options={}, img_options ={})
|
@@ -25,28 +26,21 @@ module ReaderHelper
|
|
25
26
|
link_to home_page.title, home_page.url, options
|
26
27
|
end
|
27
28
|
|
28
|
-
def
|
29
|
-
Sanitize.clean(textilize(text)
|
29
|
+
def scrub_html(text)
|
30
|
+
Sanitize.clean(textilize(text))
|
30
31
|
end
|
31
32
|
|
32
|
-
def
|
33
|
-
|
34
|
-
if textiled[0..2] == "<p>" then textiled = textiled[3..-1] end
|
35
|
-
if textiled[-4..-1] == "</p>" then textiled = textiled[0..-5] end
|
36
|
-
textiled
|
33
|
+
def clean_html(text)
|
34
|
+
Sanitize.clean(textilize(text), Sanitize::Config::GENEROUS)
|
37
35
|
end
|
38
36
|
|
39
|
-
def truncate_words(text='', length=
|
37
|
+
def truncate_words(text='', length=24, omission="...")
|
40
38
|
return '' if text.blank?
|
41
39
|
words = text.split
|
42
40
|
omission = '' unless words.size > length
|
43
41
|
words[0..(length-1)].join(" ") + omission
|
44
42
|
end
|
45
43
|
|
46
|
-
def truncate_and_textilize(text, length=64)
|
47
|
-
clean_textilize( truncate_words(text, length) )
|
48
|
-
end
|
49
|
-
|
50
44
|
def pagination_and_summary_for(list, name='')
|
51
45
|
%{<div class="pagination">
|
52
46
|
#{will_paginate list, :container => false}
|
@@ -60,18 +54,52 @@ module ReaderHelper
|
|
60
54
|
def pagination_summary(list, name='')
|
61
55
|
total = list.total_entries
|
62
56
|
if list.empty?
|
63
|
-
%{#{t('no')} #{name.pluralize}}
|
57
|
+
%{#{t('reader_extension.no')} #{name.pluralize}}
|
64
58
|
else
|
65
59
|
name ||= t(list.first.class.to_s.underscore.gsub('_', ' '))
|
66
60
|
if total == 1
|
67
|
-
%{#{t('showing')} #{t('one')} #{name}}
|
61
|
+
%{#{t('reader_extension.showing')} #{t('reader_extension.one')} #{name}}
|
68
62
|
elsif list.current_page == 1 && total < list.per_page
|
69
|
-
%{#{t('all')} #{total} #{name.pluralize}}
|
63
|
+
%{#{t('reader_extension.all')} #{total} #{name.pluralize}}
|
70
64
|
else
|
71
65
|
start = list.offset + 1
|
72
66
|
finish = ((list.offset + list.per_page) < list.total_entries) ? list.offset + list.per_page : list.total_entries
|
73
|
-
%{#{start} #{t('to')} #{finish} #{t('of')} #{total} #{name.pluralize}}
|
67
|
+
%{#{start} #{t('reader_extension.to')} #{finish} #{t('reader_extension.of')} #{total} #{name.pluralize}}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def message_preview(subject, body, reader)
|
73
|
+
preview = <<EOM
|
74
|
+
From: #{current_user.name} <#{current_user.email}>
|
75
|
+
To: #{reader.name} <#{reader.email}>
|
76
|
+
Date: #{Time.now.to_date.to_s :long}
|
77
|
+
<strong>Subject: #{subject}</strong>
|
78
|
+
|
79
|
+
Dear #{reader.name},
|
80
|
+
|
81
|
+
#{body}
|
82
|
+
|
83
|
+
EOM
|
84
|
+
simple_format(preview)
|
85
|
+
end
|
86
|
+
|
87
|
+
def choose_page(object, field, select_options={})
|
88
|
+
root = Page.respond_to?(:homepage) ? Page.homepage : Page.find_by_parent_id(nil)
|
89
|
+
options = page_option_branch(root)
|
90
|
+
options.unshift ['<none>', nil]
|
91
|
+
select object, field, options, select_options
|
92
|
+
end
|
93
|
+
|
94
|
+
def page_option_branch(page, depth=0)
|
95
|
+
options = []
|
96
|
+
unless page.title.first == '_'
|
97
|
+
options << ["#{". " * depth}#{h(page.title)}", page.id]
|
98
|
+
page.children.each do |child|
|
99
|
+
options += page_option_branch(child, depth + 1)
|
74
100
|
end
|
75
101
|
end
|
102
|
+
options
|
76
103
|
end
|
104
|
+
|
77
105
|
end
|
data/app/models/group.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
class Group < ActiveRecord::Base
|
2
|
+
|
3
|
+
has_site if respond_to? :has_site
|
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
|
+
named_scope :from_list, lambda { |ids|
|
24
|
+
{ :conditions => ["groups.id IN (#{ids.map{"?"}.join(',')})", *ids] }
|
25
|
+
}
|
26
|
+
|
27
|
+
named_scope :attached_to, lambda { |objects|
|
28
|
+
conditions = objects.map{|o| "(pp.permitted_type = ? AND pp.permitted_id = ?)" }.join(" OR ")
|
29
|
+
binds = objects.map{|o| [o.class.to_s, o.id]}.flatten
|
30
|
+
{
|
31
|
+
:select => "groups.*, count(pp.group_id) AS pcount",
|
32
|
+
:joins => "INNER JOIN permissions as pp on pp.group_id = groups.id",
|
33
|
+
:conditions => [conditions, *binds],
|
34
|
+
:having => "pcount > 0", # otherwise attached_to([]) returns all groups
|
35
|
+
:group => column_names.map { |n| self.table_name + '.' + n }.join(','),
|
36
|
+
:readonly => false
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
def url
|
41
|
+
homepage.url if homepage
|
42
|
+
end
|
43
|
+
|
44
|
+
def send_welcome_to(reader)
|
45
|
+
if reader.activated? # welcomes are also triggered on activation
|
46
|
+
if message = Message.belonging_to(self).for_function('group_welcome').first # only if a group_welcome message exists *belonging to this group*
|
47
|
+
message.deliver_to(reader)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def admit(reader)
|
53
|
+
self.readers << reader
|
54
|
+
end
|
55
|
+
|
56
|
+
def permission_for(object)
|
57
|
+
self.permissions.for(object).first
|
58
|
+
end
|
59
|
+
|
60
|
+
def membership_for(reader)
|
61
|
+
self.memberships.for(reader).first
|
62
|
+
end
|
63
|
+
|
64
|
+
# we can't has_many through the polymorphic permission relationship, so this is called from has_groups
|
65
|
+
# and for eg. Page, it defines:
|
66
|
+
# Permission.for_pages named_scope
|
67
|
+
# Group.page_permissions => set of permission objects
|
68
|
+
# Group.pages => set of page objects
|
69
|
+
|
70
|
+
def self.define_retrieval_methods(classname)
|
71
|
+
type_scope = "for_#{classname.downcase.pluralize}".intern
|
72
|
+
Permission.send :named_scope, type_scope, :conditions => { :permitted_type => classname }
|
73
|
+
define_method("#{classname.downcase}_permissions") { self.permissions.send type_scope }
|
74
|
+
define_method("#{classname.downcase.pluralize}") { self.send("#{classname.to_s.downcase}_permissions".intern).map(&:permitted) }
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
end
|
80
|
+
|
data/app/models/message.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
class Message < ActiveRecord::Base
|
2
2
|
|
3
|
+
has_groups
|
3
4
|
has_site if respond_to? :has_site
|
4
5
|
|
5
6
|
belongs_to :layout
|
6
7
|
belongs_to :created_by, :class_name => 'User'
|
7
8
|
belongs_to :updated_by, :class_name => 'User'
|
8
9
|
|
9
|
-
has_many :message_readers
|
10
|
-
has_many :readers, :through => :message_readers
|
11
|
-
|
12
10
|
has_many :deliveries, :class_name => 'MessageReader', :conditions => ["message_readers.sent_at IS NOT NULL and message_readers.sent_at <= ?", Time.now.to_s(:db)]
|
13
11
|
has_many :recipients, :through => :deliveries, :source => :reader
|
14
12
|
|
@@ -29,7 +27,7 @@ class Message < ActiveRecord::Base
|
|
29
27
|
|
30
28
|
# has to return a named_scope for chainability
|
31
29
|
def possible_readers
|
32
|
-
Reader.
|
30
|
+
groups.any? ? Reader.in_groups(groups) : Reader.scoped({})
|
33
31
|
end
|
34
32
|
|
35
33
|
def undelivered_readers
|
@@ -57,15 +55,20 @@ class Message < ActiveRecord::Base
|
|
57
55
|
end
|
58
56
|
|
59
57
|
def preview(reader=nil)
|
60
|
-
reader ||= possible_readers.first || Reader.
|
58
|
+
reader ||= possible_readers.first || Reader.for_user(created_by)
|
61
59
|
ReaderNotifier.create_message(reader, self)
|
62
60
|
end
|
63
61
|
|
64
62
|
def function
|
65
63
|
MessageFunction[self.function_id]
|
66
64
|
end
|
67
|
-
def self.functional(function)
|
68
|
-
for_function(
|
65
|
+
def self.functional(function, group=nil)
|
66
|
+
messages = for_function(function)
|
67
|
+
if group
|
68
|
+
messages.belonging_to(group).first
|
69
|
+
else
|
70
|
+
messages.ungrouped.first
|
71
|
+
end
|
69
72
|
end
|
70
73
|
def has_function?
|
71
74
|
!function.nil?
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Permission < ActiveRecord::Base
|
2
|
+
|
3
|
+
belongs_to :group
|
4
|
+
belongs_to :permitted, :polymorphic => true
|
5
|
+
|
6
|
+
named_scope :for, lambda { |object|
|
7
|
+
{ :conditions => ["permissions.permitted_id = ? and permissions.permitted_type = ?", object.id, object.class.to_s] }
|
8
|
+
}
|
9
|
+
|
10
|
+
end
|
11
|
+
|
data/app/models/reader.rb
CHANGED
@@ -5,37 +5,39 @@ class Reader < ActiveRecord::Base
|
|
5
5
|
@@user_columns = [:name, :email, :login, :created_at, :password, :notes]
|
6
6
|
cattr_accessor :user_columns
|
7
7
|
cattr_accessor :current
|
8
|
-
|
9
|
-
|
10
|
-
has_site if respond_to? :has_site
|
8
|
+
attr_accessor :email_field # used in blocking spam registrations
|
11
9
|
|
12
10
|
acts_as_authentic do |config|
|
13
11
|
config.validations_scope = :site_id if defined? Site
|
14
12
|
config.transition_from_restful_authentication = true
|
15
13
|
config.validate_email_field = false
|
16
14
|
config.validate_login_field = false
|
15
|
+
config.validate_password_field = false
|
17
16
|
end
|
18
17
|
|
19
18
|
belongs_to :user
|
20
19
|
belongs_to :created_by, :class_name => 'User'
|
21
20
|
belongs_to :updated_by, :class_name => 'User'
|
22
|
-
|
23
21
|
has_many :message_readers
|
24
22
|
has_many :messages, :through => :message_readers
|
23
|
+
has_many :memberships
|
24
|
+
has_many :groups, :through => :memberships
|
25
|
+
accepts_nested_attributes_for :memberships
|
25
26
|
|
26
|
-
attr_accessor :current_password # used for authentication on update
|
27
|
-
attr_accessor :email_field # used in blocking spam registrations
|
28
|
-
|
29
27
|
before_update :update_user
|
30
28
|
|
31
|
-
validates_presence_of :name, :email
|
32
|
-
|
29
|
+
validates_presence_of :name, :email
|
30
|
+
validates_length_of :name, :maximum => 100, :allow_nil => true
|
31
|
+
validates_length_of :password, :minimum => 6, :allow_nil => false, :unless => :existing_reader_keeping_password?
|
32
|
+
# validates_format_of :password, :with => /[^A-Za-z]/, :unless => :existing_reader_keeping_password? # we have to match radiant so that users can log in both ways
|
33
|
+
validates_confirmation_of :password, :unless => :existing_reader_keeping_password?
|
34
|
+
validates_uniqueness_of :login, :allow_blank => true
|
33
35
|
validate :email_must_not_be_in_use
|
34
36
|
|
35
37
|
include RFC822
|
36
|
-
validates_format_of :email, :with => RFC822_valid
|
37
|
-
validates_length_of :name, :maximum => 100, :allow_nil => true
|
38
|
+
validates_format_of :email, :with => RFC822_valid
|
38
39
|
|
40
|
+
default_scope :order => 'name ASC'
|
39
41
|
named_scope :any
|
40
42
|
named_scope :active, :conditions => "activated_at IS NOT NULL"
|
41
43
|
named_scope :inactive, :conditions => "activated_at IS NULL"
|
@@ -49,9 +51,34 @@ class Reader < ActiveRecord::Base
|
|
49
51
|
end
|
50
52
|
}
|
51
53
|
|
54
|
+
named_scope :in_groups, lambda { |groups|
|
55
|
+
{
|
56
|
+
:select => "readers.*",
|
57
|
+
:joins => "INNER JOIN memberships as mm on mm.reader_id = readers.id",
|
58
|
+
:conditions => ["mm.group_id IN (#{groups.map{'?'}.join(',')})", *groups.map{|g| g.is_a?(Group) ? g.id : g}],
|
59
|
+
:group => "mm.reader_id"
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
52
63
|
def self.find_by_login_or_email(login_or_email)
|
53
64
|
reader = find(:first, :conditions => ["login = ? OR email = ?", login_or_email, login_or_email])
|
54
65
|
end
|
66
|
+
|
67
|
+
def self.for_user(user)
|
68
|
+
if user.respond_to?(:site) && site = Page.current_site
|
69
|
+
reader = self.find_or_create_by_site_id_and_user_id(site.id, user.id)
|
70
|
+
else
|
71
|
+
reader = self.find_or_create_by_user_id(user.id)
|
72
|
+
end
|
73
|
+
if reader.new_record?
|
74
|
+
user_columns.each { |att| reader.send("#{att.to_s}=", user.send(att)) }
|
75
|
+
reader.crypted_password = user.password
|
76
|
+
reader.password_salt = user.salt
|
77
|
+
reader.activated_at = reader.created_at
|
78
|
+
reader.save(false)
|
79
|
+
end
|
80
|
+
reader
|
81
|
+
end
|
55
82
|
|
56
83
|
def forename
|
57
84
|
read_attribute(:forename) || name.split(/\s/).first
|
@@ -60,7 +87,8 @@ class Reader < ActiveRecord::Base
|
|
60
87
|
def activate!
|
61
88
|
self.activated_at = Time.now.utc
|
62
89
|
self.save!
|
63
|
-
|
90
|
+
send_welcome_message
|
91
|
+
send_group_welcomes
|
64
92
|
end
|
65
93
|
|
66
94
|
def activated?
|
@@ -81,9 +109,9 @@ class Reader < ActiveRecord::Base
|
|
81
109
|
}
|
82
110
|
end
|
83
111
|
|
84
|
-
def send_functional_message(function)
|
112
|
+
def send_functional_message(function, group=nil)
|
85
113
|
reset_perishable_token!
|
86
|
-
message = Message.functional(function)
|
114
|
+
message = Message.functional(function, group) # returns the standard functional message if no group is supplied, or no group message exists
|
87
115
|
raise StandardError, "No #{function} message could be found" unless message
|
88
116
|
message.deliver_to(self)
|
89
117
|
end
|
@@ -99,46 +127,54 @@ class Reader < ActiveRecord::Base
|
|
99
127
|
def is_admin?
|
100
128
|
is_user? && self.user.admin?
|
101
129
|
end
|
102
|
-
|
103
|
-
def self.find_or_create_for_user(user)
|
104
|
-
if user.respond_to?(:site) && site = Page.current_site
|
105
|
-
reader = self.find_or_create_by_site_id_and_user_id(site.id, user.id)
|
106
|
-
else
|
107
|
-
reader = self.find_or_create_by_user_id(user.id)
|
108
|
-
end
|
109
|
-
if reader.new_record?
|
110
|
-
user_columns.each { |att| reader.send("#{att.to_s}=", user.send(att)) }
|
111
|
-
reader.crypted_password = user.password
|
112
|
-
reader.password_salt = user.salt
|
113
|
-
reader.activated_at = reader.created_at
|
114
|
-
reader.save(false)
|
115
|
-
end
|
116
|
-
reader
|
117
|
-
end
|
118
|
-
|
130
|
+
|
119
131
|
def create_password!
|
120
132
|
self.clear_password = self.randomize_password # randomize_password is provided by authlogic
|
121
133
|
self.save! unless self.new_record?
|
122
134
|
self.clear_password
|
123
135
|
end
|
124
136
|
|
137
|
+
def find_homepage
|
138
|
+
if homegroup = groups.with_home_page.first
|
139
|
+
homegroup.homepage
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def can_see? (this)
|
144
|
+
permitted_groups = this.permitted_groups
|
145
|
+
permitted_groups.empty? or in_any_of_these_groups?(permitted_groups)
|
146
|
+
end
|
147
|
+
|
148
|
+
def in_any_of_these_groups? (grouplist)
|
149
|
+
(grouplist & groups).any?
|
150
|
+
end
|
151
|
+
|
152
|
+
def is_in? (group)
|
153
|
+
groups.include?(group)
|
154
|
+
end
|
155
|
+
|
156
|
+
# has_group? is ambiguous: with no argument it means 'is this reader grouped at all?'.
|
157
|
+
def has_group?(group=nil)
|
158
|
+
group.nil? ? groups.any? : is_in?(group)
|
159
|
+
end
|
160
|
+
|
125
161
|
private
|
126
162
|
|
127
163
|
def email_must_not_be_in_use
|
128
164
|
reader = Reader.find_by_email(self.email) # the finds will be site-scoped if appropriate
|
129
165
|
user = User.find_by_email(self.email)
|
130
166
|
if user && user != self.user
|
131
|
-
errors.add
|
167
|
+
errors.add :value, :taken_by_author
|
132
168
|
elsif reader && reader != self
|
133
|
-
errors.add
|
169
|
+
errors.add :value, :taken
|
134
170
|
else
|
135
171
|
return true
|
136
172
|
end
|
137
173
|
return false
|
138
174
|
end
|
139
175
|
|
140
|
-
def
|
141
|
-
new_record?
|
176
|
+
def existing_reader_keeping_password?
|
177
|
+
!new_record? && !password_changed?
|
142
178
|
end
|
143
179
|
|
144
180
|
def update_user
|
@@ -148,5 +184,13 @@ private
|
|
148
184
|
self.user.save! if self.user.changed?
|
149
185
|
end
|
150
186
|
end
|
187
|
+
|
188
|
+
def send_group_welcomes
|
189
|
+
groups.each { |g| g.send_welcome_to(self) }
|
190
|
+
end
|
191
|
+
|
192
|
+
def send_group_invitation_message(group=nil)
|
193
|
+
send_functional_message('invitation', group)
|
194
|
+
end
|
151
195
|
|
152
196
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
- include_stylesheet('admin/reader_group')
|
2
|
+
|
3
|
+
%h1
|
4
|
+
= t('reader_extension.invite_into_group', :name => @group.name)
|
5
|
+
|
6
|
+
- if message = @group.messages.for_function('invitation').first
|
7
|
+
|
8
|
+
- form_for :group, @group, :url => admin_group_group_invitations_url(@group), :html => {:id => 'preview_form', :method => 'post'} do
|
9
|
+
.form-area
|
10
|
+
%p
|
11
|
+
%label{:for => "readerlist"}
|
12
|
+
List of people
|
13
|
+
%span.formnote
|
14
|
+
- if Radiant::Config['reader.use_honorifics?']
|
15
|
+
title or rank,
|
16
|
+
name, email, [login], [phone]
|
17
|
+
= text_area_tag "readerlist", params[:readerlist], :class => "textarea", :style => "width: 100%; height: 240px;"
|
18
|
+
|
19
|
+
%p.buttons
|
20
|
+
= submit_tag 'preview import', :class => 'button'
|
21
|
+
or
|
22
|
+
= link_to "Cancel", admin_group_url(@group)
|
23
|
+
|
24
|
+
%p
|
25
|
+
= t('reader_extension.invitation_instructions')
|
26
|
+
|
27
|
+
- else
|
28
|
+
%p
|
29
|
+
= t('reader_extension.no_invitation_message')
|
30
|
+
= link_to image('plus') + ' ' + t("reader_extension.create_invitation_message"), new_admin_group_message_url(@group, :function => 'invitation'), :class => "action"
|
31
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
- include_stylesheet('admin/reader_group')
|
2
|
+
|
3
|
+
%h1
|
4
|
+
= t('reader_extension.check_invitation_list', :name => @group.name)
|
5
|
+
|
6
|
+
- form_for :group, @group, :url => admin_group_group_invitations_url(@group), :html => {:id => 'confirmation_form', :method => 'post'} do
|
7
|
+
%p
|
8
|
+
= t('reader_extension.invitation_preview_instructions')
|
9
|
+
|
10
|
+
%table#import
|
11
|
+
%thead
|
12
|
+
%tr
|
13
|
+
%th
|
14
|
+
- if Radiant::Config['reader.use_honorifics?']
|
15
|
+
%th= t('reader_extension.honorific')
|
16
|
+
%th= t('reader_extension.full_name')
|
17
|
+
%th= t('reader_extension.email')
|
18
|
+
%th= t('reader_extension.optional_login')
|
19
|
+
%th= t('reader_extension.optional_phone')
|
20
|
+
%tbody
|
21
|
+
- i = 0
|
22
|
+
- @readers.each do |reader|
|
23
|
+
- if reader.new_record?
|
24
|
+
%tr.import
|
25
|
+
%td
|
26
|
+
= check_box_tag "import_reader[]", i, reader.valid?
|
27
|
+
- if Radiant::Config['reader.use_honorifics?']
|
28
|
+
%td
|
29
|
+
= text_field_tag "reader_#{i}[honorific]", reader.honorific, :class => "preview#{ ' with_error' if reader.errors.on(:honorific)}", :title => reader.errors.on(:honorific)
|
30
|
+
%td
|
31
|
+
= text_field_tag "reader_#{i}[name]", reader.name, :class => "preview#{ ' with_error' if reader.errors.on(:name)}", :title => reader.errors.on(:name)
|
32
|
+
%td
|
33
|
+
= text_field_tag "reader_#{i}[email]", reader.email, :class => "preview#{ ' with_error' if reader.errors.on(:email)}", :title => reader.errors.on(:email)
|
34
|
+
%td
|
35
|
+
= text_field_tag "reader_#{i}[login]", reader.login, :class => "preview#{ ' with_error' if reader.errors.on(:login)}", :title => reader.errors.on(:login)
|
36
|
+
%td
|
37
|
+
= text_field_tag "reader_#{i}[phone]", reader.phone, :class => "preview#{ ' with_error' if reader.errors.on(:phone)}", :title => reader.errors.on(:phone)
|
38
|
+
- else
|
39
|
+
%tr.invite
|
40
|
+
%td
|
41
|
+
= check_box_tag "invite_reader[]", reader.id, {:checked => true}
|
42
|
+
- if Radiant::Config['reader.use_honorifics?']
|
43
|
+
%td
|
44
|
+
= text_field_tag "reader_#{i}[honorific]", reader.honorific, :class => "preview#{ ' with_error' if reader.errors.on(:honorific)}", :title => reader.errors.on(:honorific), :disabled => true
|
45
|
+
%td
|
46
|
+
= text_field_tag "reader_#{i}[name]", reader.name, :class => "preview#{ ' with_error' if reader.errors.on(:name)}", :title => reader.errors.on(:name), :disabled => true
|
47
|
+
%td
|
48
|
+
= text_field_tag "reader_#{i}[email]", reader.email, :class => "preview#{ ' with_error' if reader.errors.on(:email)}", :title => reader.errors.on(:email), :disabled => true
|
49
|
+
%td
|
50
|
+
= text_field_tag "reader_#{i}[login]", reader.login, :class => "preview#{ ' with_error' if reader.errors.on(:login)}", :title => reader.errors.on(:login), :disabled => true
|
51
|
+
%td
|
52
|
+
= text_field_tag "reader_#{i}[phone]", reader.phone, :class => "preview#{ ' with_error' if reader.errors.on(:phone)}", :title => reader.errors.on(:phone)
|
53
|
+
- i = i + 1
|
54
|
+
|
55
|
+
%p.buttons
|
56
|
+
= submit_tag 'Invite these people into the group', :name => 'confirm', :class => 'button'
|
57
|
+
or
|
58
|
+
= link_to 'start again', new_admin_group_group_invitation_url(@group)
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
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.description
|
13
|
+
= f.label :description
|
14
|
+
= f.text_area 'description'
|
15
|
+
%p.homepage
|
16
|
+
= f.label :homepage_id, "Group home page:"
|
17
|
+
= choose_page 'group', 'homepage_id', {:selected =>@group.homepage_id}
|
18
|
+
|
19
|
+
- form.edit_timestamp do
|
20
|
+
= updated_stamp @group
|
21
|
+
- form.edit_buttons do
|
22
|
+
%p.buttons
|
23
|
+
= save_model_button @group
|
24
|
+
= save_model_and_continue_editing_button @group
|
25
|
+
or
|
26
|
+
= link_to "Cancel", admin_groups_url
|
@@ -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
|
@@ -0,0 +1,44 @@
|
|
1
|
+
- include_stylesheet('admin/reader_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
|
+
%tr
|
12
|
+
- render_region :tbody do |tbody|
|
13
|
+
- tbody.name_cell do
|
14
|
+
%td.name
|
15
|
+
%p
|
16
|
+
= link_to group.name, admin_group_url(group)
|
17
|
+
%br
|
18
|
+
%span.notes
|
19
|
+
= group.description
|
20
|
+
- tbody.home_cell do
|
21
|
+
%td.home
|
22
|
+
- if group.homepage
|
23
|
+
= link_to group.homepage.title, edit_admin_page_url(group.homepage)
|
24
|
+
- else
|
25
|
+
= t('reader_extension.none')
|
26
|
+
- tbody.members_cell do
|
27
|
+
%td.members
|
28
|
+
= group.readers.count
|
29
|
+
- tbody.pages_cell do
|
30
|
+
%td.pages
|
31
|
+
= group.pages.count
|
32
|
+
- tbody.modify_cell do
|
33
|
+
%td.actions
|
34
|
+
= link_to_unless_current image('plus') + ' ' + t('reader_extension.add_members'), new_admin_group_group_invitation_url(group), :class => 'action'
|
35
|
+
= link_to_unless_current image('delta') + ' ' + t('reader_extension.edit_group'), edit_admin_group_url(group), :class => 'action'
|
36
|
+
= link_to_unless_current image('minus') + ' ' + t('reader_extension.delete_group'), admin_group_url(group), :method => 'delete', :confirm => t("reader_extension.really_delete_group", :name => group.name), :class => 'action'
|
37
|
+
|
38
|
+
- render_region :bottom do |bottom|
|
39
|
+
- bottom.buttons do
|
40
|
+
#actions
|
41
|
+
= pagination_for @readers
|
42
|
+
%ul
|
43
|
+
%li
|
44
|
+
= link_to image('plus') + " " + t("reader_extension.new_group"), new_admin_group_url
|