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
@@ -0,0 +1,125 @@
|
|
1
|
+
module GroupedModel
|
2
|
+
def self.included(base)
|
3
|
+
base.extend ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def has_groups?
|
8
|
+
false
|
9
|
+
end
|
10
|
+
alias :has_group? :has_groups?
|
11
|
+
|
12
|
+
def has_groups(options={})
|
13
|
+
return if has_groups?
|
14
|
+
|
15
|
+
class_eval {
|
16
|
+
include GroupedModel::GroupedInstanceMethods
|
17
|
+
|
18
|
+
def self.has_groups?
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.visible
|
23
|
+
ungrouped
|
24
|
+
end
|
25
|
+
}
|
26
|
+
|
27
|
+
has_many :permissions, :as => :permitted
|
28
|
+
has_many :groups, :through => :permissions
|
29
|
+
Group.define_retrieval_methods(self.to_s)
|
30
|
+
|
31
|
+
named_scope :visible_to, lambda { |reader|
|
32
|
+
conditions = "pp.group_id IS NULL"
|
33
|
+
if reader && reader.groups.any?
|
34
|
+
ids = reader.group_ids
|
35
|
+
conditions = ["#{conditions} OR pp.group_id IS NULL OR pp.group_id IN(#{ids.map{"?"}.join(',')})", *ids]
|
36
|
+
end
|
37
|
+
{
|
38
|
+
:joins => "LEFT OUTER JOIN permissions as pp on pp.permitted_id = #{self.table_name}.id AND pp.permitted_type = '#{self.to_s}'",
|
39
|
+
:group => column_names.map { |n| self.table_name + '.' + n }.join(','),
|
40
|
+
:conditions => conditions,
|
41
|
+
:readonly => false
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
named_scope :ungrouped, {
|
46
|
+
:select => "#{self.table_name}.*, count(pp.id) as group_count",
|
47
|
+
:joins => "LEFT OUTER JOIN permissions as pp on pp.permitted_id = #{self.table_name}.id AND pp.permitted_type = '#{self.to_s}'",
|
48
|
+
:having => "group_count = 0",
|
49
|
+
:group => column_names.map { |n| self.table_name + '.' + n }.join(','), # postgres requires that we group by all selected (but not aggregated) columns
|
50
|
+
:readonly => false
|
51
|
+
} do
|
52
|
+
def count
|
53
|
+
length
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
named_scope :grouped, {
|
58
|
+
:select => "#{self.table_name}.*, count(pp.id) as group_count",
|
59
|
+
:joins => "LEFT OUTER JOIN permissions as pp on pp.permitted_id = #{self.table_name}.id AND pp.permitted_type = '#{self.to_s}'",
|
60
|
+
:having => "group_count > 0",
|
61
|
+
:group => column_names.map { |n| self.table_name + '.' + n }.join(','),
|
62
|
+
:readonly => false
|
63
|
+
} do
|
64
|
+
def count
|
65
|
+
length
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
named_scope :belonging_to, lambda { |group|
|
70
|
+
{
|
71
|
+
:joins => "INNER JOIN permissions as pp on pp.permitted_id = #{self.table_name}.id AND pp.permitted_type = '#{self.to_s}'",
|
72
|
+
:group => column_names.map { |n| self.table_name + '.' + n }.join(','),
|
73
|
+
:conditions => ["pp.group_id = ?", group.id],
|
74
|
+
:readonly => false
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
end
|
79
|
+
alias :has_group :has_groups
|
80
|
+
end
|
81
|
+
|
82
|
+
module GroupedInstanceMethods
|
83
|
+
|
84
|
+
# in GroupedPage this is chained to include inherited groups
|
85
|
+
def permitted_groups
|
86
|
+
groups
|
87
|
+
end
|
88
|
+
|
89
|
+
def visible_to?(reader)
|
90
|
+
Rails.logger.warn "grouped_model#visible_to?"
|
91
|
+
return true if self.permitted_groups.empty?
|
92
|
+
return false if reader.nil?
|
93
|
+
return true if reader.is_admin?
|
94
|
+
return (reader.groups & self.permitted_groups).any?
|
95
|
+
end
|
96
|
+
|
97
|
+
def group
|
98
|
+
if self.permitted_groups.length == 1
|
99
|
+
self.permitted_groups.first
|
100
|
+
else
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def visible?
|
106
|
+
permitted_groups.empty?
|
107
|
+
end
|
108
|
+
|
109
|
+
def permitted_readers
|
110
|
+
permitted_groups.any? ? Reader.in_groups(permitted_groups) : Reader.all
|
111
|
+
end
|
112
|
+
|
113
|
+
def has_group?(group)
|
114
|
+
return self.permitted_groups.include?(group)
|
115
|
+
end
|
116
|
+
|
117
|
+
def permit(group)
|
118
|
+
self.groups << group unless self.has_group?(group)
|
119
|
+
end
|
120
|
+
|
121
|
+
def group_ids=(ids)
|
122
|
+
self.groups = Group.from_list(ids)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/lib/grouped_page.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module GroupedPage
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval {
|
5
|
+
has_groups
|
6
|
+
has_one :homegroup, :foreign_key => 'homepage_id', :class_name => 'Group'
|
7
|
+
include InstanceMethods
|
8
|
+
alias_method_chain :permitted_groups, :inheritance
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceMethods
|
13
|
+
|
14
|
+
attr_reader :inherited_groups
|
15
|
+
def inherited_groups
|
16
|
+
@inherited_groups ||= self.parent ? Group.attached_to(self.ancestors) : []
|
17
|
+
end
|
18
|
+
|
19
|
+
def permitted_groups_with_inheritance
|
20
|
+
permitted_groups_without_inheritance + inherited_groups
|
21
|
+
end
|
22
|
+
|
23
|
+
def cache?
|
24
|
+
self.permitted_groups.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_inherited_group?(group)
|
28
|
+
return self.inherited_groups.include?(group)
|
29
|
+
end
|
30
|
+
|
31
|
+
def group_is_inherited?(group)
|
32
|
+
return self.has_inherited_group?(group) && !self.has_group?(group)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
|
data/lib/message_tags.rb
ADDED
@@ -0,0 +1,183 @@
|
|
1
|
+
module MessageTags
|
2
|
+
include Radiant::Taggable
|
3
|
+
include ReaderHelper
|
4
|
+
|
5
|
+
class TagError < StandardError; end
|
6
|
+
|
7
|
+
# I can see this causing problems: will change soon
|
8
|
+
|
9
|
+
desc %{
|
10
|
+
The root 'site' tag is not meant to be called directly.
|
11
|
+
All it does is to prepare the way for eg.
|
12
|
+
<pre><code><r:site:url /></code></pre>
|
13
|
+
}
|
14
|
+
tag 'site' do |tag|
|
15
|
+
raise TagError, "r:site currently only works in email" unless @mailer_vars
|
16
|
+
raise TagError, "no site" unless tag.locals.site = @mailer_vars[:@site]
|
17
|
+
tag.expand
|
18
|
+
end
|
19
|
+
tag 'site:name' do |tag|
|
20
|
+
if defined?(Site) && tag.locals.site.is_a?(Site)
|
21
|
+
tag.locals.site.name
|
22
|
+
else
|
23
|
+
tag.locals.site[:name]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
tag 'site:url' do |tag|
|
27
|
+
if defined?(Site) && tag.locals.site.is_a?(Site)
|
28
|
+
tag.locals.site.base_domain
|
29
|
+
else
|
30
|
+
tag.locals.site[:url]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
tag 'site:login_url' do |tag|
|
34
|
+
reader_login_url(:host => @mailer_vars[:@host])
|
35
|
+
end
|
36
|
+
|
37
|
+
desc %{
|
38
|
+
The root 'recipient' tag is not meant to be called directly.
|
39
|
+
All it does is summon a reader object so that its fields can be displayed with eg.
|
40
|
+
<pre><code><r:recipient:name /></code></pre>
|
41
|
+
}
|
42
|
+
tag 'recipient' do |tag|
|
43
|
+
raise TagError, "r:recipient only works in email" unless @mailer_vars
|
44
|
+
raise TagError, "no recipient" unless tag.locals.recipient = @mailer_vars[:@reader]
|
45
|
+
tag.expand
|
46
|
+
end
|
47
|
+
|
48
|
+
[:name, :forename, :email, :description, :login].each do |field|
|
49
|
+
desc %{
|
50
|
+
Only for use in email messages. Displays the #{field} field of the reader currently being emailed.
|
51
|
+
<pre><code><r:recipient:#{field} /></code></pre>
|
52
|
+
}
|
53
|
+
tag "recipient:#{field}" do |tag|
|
54
|
+
tag.locals.recipient.send(field)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
desc %{
|
59
|
+
Only for use in email messages. Displays the password of the reader currently being emailed, if we still have it.
|
60
|
+
|
61
|
+
(After the first successful login we forget the cleartext version of their password, so you only want to use this
|
62
|
+
tag in welcome and activation messages.)
|
63
|
+
|
64
|
+
<pre><code><r:recipient:url /></code></pre>
|
65
|
+
}
|
66
|
+
tag "recipient:password" do |tag|
|
67
|
+
tag.locals.recipient.clear_password || "<encrypted>"
|
68
|
+
end
|
69
|
+
|
70
|
+
desc %{
|
71
|
+
Only for use in email messages. Displays the me-page url of the reader currently being emailed.
|
72
|
+
<pre><code><r:recipient:url /></code></pre>
|
73
|
+
}
|
74
|
+
tag "recipient:url" do |tag|
|
75
|
+
reader_url(tag.locals.recipient, :host => @mailer_vars[:@host])
|
76
|
+
end
|
77
|
+
|
78
|
+
desc %{
|
79
|
+
Only for use in email messages. Displays the preferences url of the reader currently being emailed.
|
80
|
+
<pre><code><r:recipient:url /></code></pre>
|
81
|
+
}
|
82
|
+
tag "recipient:edit_url" do |tag|
|
83
|
+
edit_reader_url(tag.locals.recipient, :host => @mailer_vars[:@host])
|
84
|
+
end
|
85
|
+
|
86
|
+
desc %{
|
87
|
+
Only for use in email messages. Displays the address that will activate the current reader account.
|
88
|
+
<pre><code><r:recipient:activation_url /></code></pre>
|
89
|
+
}
|
90
|
+
tag "recipient:activation_url" do |tag|
|
91
|
+
activate_me_url(tag.locals.recipient, :activation_code => tag.locals.recipient.perishable_token, :host => @mailer_vars[:@host])
|
92
|
+
end
|
93
|
+
|
94
|
+
desc %{
|
95
|
+
Only for use in email messages. Displays the address that will bring up a new-password form for the current reader account.
|
96
|
+
<pre><code><r:recipient:repassword_url /></code></pre>
|
97
|
+
}
|
98
|
+
tag "recipient:repassword_url" do |tag|
|
99
|
+
repassword_me_url(tag.locals.recipient, :confirmation_code => tag.locals.recipient.perishable_token, :host => @mailer_vars[:@host])
|
100
|
+
end
|
101
|
+
|
102
|
+
desc %{
|
103
|
+
The root 'sender' tag is not meant to be called directly.
|
104
|
+
All it does is summon a sender object so that its fields can be displayed with eg.
|
105
|
+
<pre><code><r:sender:name /></code></pre>
|
106
|
+
}
|
107
|
+
tag 'sender' do |tag|
|
108
|
+
raise TagError, "r:sender only works in email" unless @mailer_vars
|
109
|
+
tag.expand
|
110
|
+
end
|
111
|
+
|
112
|
+
desc %{
|
113
|
+
Only for use in email messages. Displays the name of the email-sender (which is probably configured in `email.name`)
|
114
|
+
<pre><code><r:sender:name /></code></pre>
|
115
|
+
}
|
116
|
+
tag "sender:name" do |tag|
|
117
|
+
@mailer_vars['sender']
|
118
|
+
end
|
119
|
+
|
120
|
+
desc %{
|
121
|
+
Only for use in email messages. Displays the address of the email-sender (which is probably configured in `email.address`)
|
122
|
+
<pre><code><r:sender:address /></code></pre>
|
123
|
+
}
|
124
|
+
tag "sender:address" do |tag|
|
125
|
+
@mailer_vars['reply_to']
|
126
|
+
end
|
127
|
+
|
128
|
+
# and for referring to messages on pages
|
129
|
+
# at the moment this only works inside r:reader:messages:each or r:group:messages:each,
|
130
|
+
# both of which are defined in reader_group
|
131
|
+
# but soon there will be a conditional r:messages:each tag here too
|
132
|
+
|
133
|
+
desc %{
|
134
|
+
The root 'message' tag is not meant to be called directly.
|
135
|
+
All it does is summon a message object so that its fields can be displayed with eg.
|
136
|
+
<pre><code><r:message:subject /></code></pre>
|
137
|
+
}
|
138
|
+
tag 'message' do |tag|
|
139
|
+
raise TagError, "no message!" unless tag.locals.message
|
140
|
+
tag.expand
|
141
|
+
end
|
142
|
+
|
143
|
+
desc %{
|
144
|
+
Displays the message subject.
|
145
|
+
|
146
|
+
<pre><code><r:message:subject /></code></pre>
|
147
|
+
}
|
148
|
+
tag "message:subject" do |tag|
|
149
|
+
tag.locals.message.subject
|
150
|
+
end
|
151
|
+
|
152
|
+
desc %{
|
153
|
+
Displays the formatted message body.
|
154
|
+
|
155
|
+
<pre><code><r:message:body /></code></pre>
|
156
|
+
}
|
157
|
+
tag "message:body" do |tag|
|
158
|
+
tag.locals.message.filtered_body
|
159
|
+
end
|
160
|
+
|
161
|
+
desc %{
|
162
|
+
Returns the url of the show-message page.
|
163
|
+
|
164
|
+
<pre><code><r:message:url /></code></pre>
|
165
|
+
}
|
166
|
+
tag "message:url" do |tag|
|
167
|
+
preview_message_path(tag.locals.message)
|
168
|
+
end
|
169
|
+
|
170
|
+
desc %{
|
171
|
+
Displays a link to the show-message page.
|
172
|
+
|
173
|
+
<pre><code><r:message:link /></code></pre>
|
174
|
+
}
|
175
|
+
tag "message:link" do |tag|
|
176
|
+
options = tag.attr.dup
|
177
|
+
attributes = options.inject('') { |s, (k, v)| s << %{#{k.downcase}="#{v}" } }.strip
|
178
|
+
attributes = " #{attributes}" unless attributes.empty?
|
179
|
+
text = tag.double? ? tag.expand : tag.render('message:subject')
|
180
|
+
%{<a href="#{tag.render('message:url')}"#{attributes}>#{text}</a>}
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module RadiantReaderExtension
|
2
|
+
VERSION = '2.0.0.rc4'
|
3
|
+
SUMMARY = %q{Reader/viewer/visitor registration, login and access-control for Radiant CMS}
|
4
|
+
DESCRIPTION = %q{Provides reader/member/user registration and management functions including password-reminder, group-based page access control and administrative email.}
|
5
|
+
URL = "http://radiant.spanner.org/reader"
|
6
|
+
AUTHORS = ["William Ross"]
|
7
|
+
EMAIL = ["radiant@spanner.org"]
|
8
|
+
end
|
data/lib/reader_admin_ui.rb
CHANGED
@@ -3,13 +3,15 @@ module ReaderAdminUI
|
|
3
3
|
def self.included(base)
|
4
4
|
base.class_eval do
|
5
5
|
|
6
|
-
attr_accessor :reader, :message, :reader_configuration
|
6
|
+
attr_accessor :reader, :message, :group, :reader_configuration
|
7
7
|
alias_method :readers, :reader
|
8
8
|
alias_method :messages, :message
|
9
|
+
alias_method :groups, :group
|
9
10
|
|
10
11
|
def load_reader_extension_regions
|
11
12
|
@reader = load_default_reader_regions
|
12
13
|
@message = load_default_message_regions
|
14
|
+
@group = load_default_group_regions
|
13
15
|
@reader_configuration = load_default_reader_configuration_regions
|
14
16
|
end
|
15
17
|
|
@@ -22,10 +24,10 @@ module ReaderAdminUI
|
|
22
24
|
protected
|
23
25
|
|
24
26
|
def load_default_reader_regions
|
25
|
-
|
27
|
+
OpenStruct.new.tap do |reader|
|
26
28
|
reader.edit = Radiant::AdminUI::RegionSet.new do |edit|
|
27
29
|
edit.main.concat %w{edit_header edit_form}
|
28
|
-
edit.form.concat %w{edit_name edit_email edit_username edit_password edit_description edit_notes}
|
30
|
+
edit.form.concat %w{edit_name edit_email edit_username edit_password reader_groups edit_description edit_notes}
|
29
31
|
edit.form_bottom.concat %w{edit_timestamp edit_buttons}
|
30
32
|
end
|
31
33
|
reader.index = Radiant::AdminUI::RegionSet.new do |index|
|
@@ -39,7 +41,7 @@ module ReaderAdminUI
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def load_default_reader_configuration_regions
|
42
|
-
|
44
|
+
OpenStruct.new.tap do |reader_configuration|
|
43
45
|
reader_configuration.show = Radiant::AdminUI::RegionSet.new do |show|
|
44
46
|
show.settings.concat %w{administration}
|
45
47
|
show.messages.concat %w{administration}
|
@@ -53,10 +55,10 @@ module ReaderAdminUI
|
|
53
55
|
end
|
54
56
|
|
55
57
|
def load_default_message_regions
|
56
|
-
|
58
|
+
OpenStruct.new.tap do |message|
|
57
59
|
message.edit = Radiant::AdminUI::RegionSet.new do |edit|
|
58
60
|
edit.main.concat %w{edit_header edit_form edit_footer}
|
59
|
-
edit.form.concat %w{edit_subject edit_body}
|
61
|
+
edit.form.concat %w{edit_subject edit_body edit_group}
|
60
62
|
edit.form_bottom.concat %w{edit_timestamp edit_buttons}
|
61
63
|
end
|
62
64
|
message.index = Radiant::AdminUI::RegionSet.new do |index|
|
@@ -73,6 +75,27 @@ module ReaderAdminUI
|
|
73
75
|
message.new = message.edit
|
74
76
|
end
|
75
77
|
end
|
78
|
+
|
79
|
+
def load_default_group_regions
|
80
|
+
OpenStruct.new.tap do |group|
|
81
|
+
group.edit = Radiant::AdminUI::RegionSet.new do |edit|
|
82
|
+
edit.main.concat %w{edit_header edit_form}
|
83
|
+
edit.form.concat %w{edit_group edit_timestamp edit_buttons}
|
84
|
+
end
|
85
|
+
group.show = Radiant::AdminUI::RegionSet.new do |show|
|
86
|
+
show.header.concat %w{title}
|
87
|
+
show.main.concat %w{messages pages members}
|
88
|
+
show.footer.concat %w{notes javascript}
|
89
|
+
end
|
90
|
+
group.index = Radiant::AdminUI::RegionSet.new do |index|
|
91
|
+
index.thead.concat %w{name_header home_header members_header pages_header modify_header}
|
92
|
+
index.tbody.concat %w{name_cell home_cell members_cell pages_cell modify_cell}
|
93
|
+
index.bottom.concat %w{buttons}
|
94
|
+
end
|
95
|
+
group.remove = group.index
|
96
|
+
group.new = group.edit
|
97
|
+
end
|
98
|
+
end
|
76
99
|
end
|
77
100
|
end
|
78
101
|
end
|
data/lib/reader_tags.rb
CHANGED
@@ -1,183 +1,19 @@
|
|
1
1
|
module ReaderTags
|
2
2
|
include Radiant::Taggable
|
3
3
|
include ReaderHelper
|
4
|
+
include GroupTags
|
5
|
+
include MessageTags
|
4
6
|
|
5
7
|
class TagError < StandardError; end
|
6
8
|
|
7
|
-
# I
|
9
|
+
# I need to find a better way to do this, but this gives a starting point
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
All it does is to prepare the way for eg.
|
12
|
-
<pre><code><r:site:url /></code></pre>
|
13
|
-
}
|
14
|
-
tag 'site' do |tag|
|
15
|
-
raise TagError, "r:site currently only works in email" unless @mailer_vars
|
16
|
-
raise TagError, "no site" unless tag.locals.site = @mailer_vars[:@site]
|
17
|
-
tag.expand
|
18
|
-
end
|
19
|
-
tag 'site:name' do |tag|
|
20
|
-
if defined?(Site) && tag.locals.site.is_a?(Site)
|
21
|
-
tag.locals.site.name
|
22
|
-
else
|
23
|
-
tag.locals.site[:name]
|
24
|
-
end
|
25
|
-
end
|
26
|
-
tag 'site:url' do |tag|
|
27
|
-
if defined?(Site) && tag.locals.site.is_a?(Site)
|
28
|
-
tag.locals.site.base_domain
|
29
|
-
else
|
30
|
-
tag.locals.site[:url]
|
31
|
-
end
|
32
|
-
end
|
33
|
-
tag 'site:login_url' do |tag|
|
34
|
-
reader_login_url(:host => @mailer_vars[:@host])
|
35
|
-
end
|
36
|
-
|
37
|
-
desc %{
|
38
|
-
The root 'recipient' tag is not meant to be called directly.
|
39
|
-
All it does is summon a reader object so that its fields can be displayed with eg.
|
40
|
-
<pre><code><r:recipient:name /></code></pre>
|
41
|
-
}
|
42
|
-
tag 'recipient' do |tag|
|
43
|
-
raise TagError, "r:recipient only works in email" unless @mailer_vars
|
44
|
-
raise TagError, "no recipient" unless tag.locals.recipient = @mailer_vars[:@reader]
|
45
|
-
tag.expand
|
46
|
-
end
|
47
|
-
|
48
|
-
[:name, :forename, :email, :description, :login].each do |field|
|
49
|
-
desc %{
|
50
|
-
Only for use in email messages. Displays the #{field} field of the reader currently being emailed.
|
51
|
-
<pre><code><r:recipient:#{field} /></code></pre>
|
52
|
-
}
|
53
|
-
tag "recipient:#{field}" do |tag|
|
54
|
-
tag.locals.recipient.send(field)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
desc %{
|
59
|
-
Only for use in email messages. Displays the password of the reader currently being emailed, if we still have it.
|
60
|
-
|
61
|
-
(After the first successful login we forget the cleartext version of their password, so you only want to use this
|
62
|
-
tag in welcome and activation messages.)
|
63
|
-
|
64
|
-
<pre><code><r:recipient:url /></code></pre>
|
65
|
-
}
|
66
|
-
tag "recipient:password" do |tag|
|
67
|
-
tag.locals.recipient.clear_password || "<encrypted>"
|
68
|
-
end
|
69
|
-
|
70
|
-
desc %{
|
71
|
-
Only for use in email messages. Displays the me-page url of the reader currently being emailed.
|
72
|
-
<pre><code><r:recipient:url /></code></pre>
|
73
|
-
}
|
74
|
-
tag "recipient:url" do |tag|
|
75
|
-
reader_url(tag.locals.recipient, :host => @mailer_vars[:@host])
|
76
|
-
end
|
77
|
-
|
78
|
-
desc %{
|
79
|
-
Only for use in email messages. Displays the preferences url of the reader currently being emailed.
|
80
|
-
<pre><code><r:recipient:url /></code></pre>
|
81
|
-
}
|
82
|
-
tag "recipient:edit_url" do |tag|
|
83
|
-
edit_reader_url(tag.locals.recipient, :host => @mailer_vars[:@host])
|
84
|
-
end
|
85
|
-
|
86
|
-
desc %{
|
87
|
-
Only for use in email messages. Displays the address that will activate the current reader account.
|
88
|
-
<pre><code><r:recipient:activation_url /></code></pre>
|
89
|
-
}
|
90
|
-
tag "recipient:activation_url" do |tag|
|
91
|
-
activate_me_url(tag.locals.recipient, :activation_code => tag.locals.recipient.perishable_token, :host => @mailer_vars[:@host])
|
92
|
-
end
|
93
|
-
|
94
|
-
desc %{
|
95
|
-
Only for use in email messages. Displays the address that will bring up a new-password form for the current reader account.
|
96
|
-
<pre><code><r:recipient:repassword_url /></code></pre>
|
97
|
-
}
|
98
|
-
tag "recipient:repassword_url" do |tag|
|
99
|
-
repassword_me_url(tag.locals.recipient, :confirmation_code => tag.locals.recipient.perishable_token, :host => @mailer_vars[:@host])
|
100
|
-
end
|
101
|
-
|
102
|
-
desc %{
|
103
|
-
The root 'sender' tag is not meant to be called directly.
|
104
|
-
All it does is summon a sender object so that its fields can be displayed with eg.
|
105
|
-
<pre><code><r:sender:name /></code></pre>
|
106
|
-
}
|
107
|
-
tag 'sender' do |tag|
|
108
|
-
raise TagError, "r:sender only works in email" unless @mailer_vars
|
109
|
-
tag.expand
|
11
|
+
tag 'reader_css' do |tag|
|
12
|
+
%{<link rel="stylesheet" href="/stylesheets/reader.css" media="all" />}
|
110
13
|
end
|
111
14
|
|
112
|
-
|
113
|
-
|
114
|
-
<pre><code><r:sender:name /></code></pre>
|
115
|
-
}
|
116
|
-
tag "sender:name" do |tag|
|
117
|
-
@mailer_vars['sender']
|
118
|
-
end
|
119
|
-
|
120
|
-
desc %{
|
121
|
-
Only for use in email messages. Displays the address of the email-sender (which is probably configured in `email.address`)
|
122
|
-
<pre><code><r:sender:address /></code></pre>
|
123
|
-
}
|
124
|
-
tag "sender:address" do |tag|
|
125
|
-
@mailer_vars['reply_to']
|
126
|
-
end
|
127
|
-
|
128
|
-
# and for referring to messages on pages
|
129
|
-
# at the moment this only works inside r:reader:messages:each or r:group:messages:each,
|
130
|
-
# both of which are defined in reader_group
|
131
|
-
# but soon there will be a conditional r:messages:each tag here too
|
132
|
-
|
133
|
-
desc %{
|
134
|
-
The root 'message' tag is not meant to be called directly.
|
135
|
-
All it does is summon a message object so that its fields can be displayed with eg.
|
136
|
-
<pre><code><r:message:subject /></code></pre>
|
137
|
-
}
|
138
|
-
tag 'message' do |tag|
|
139
|
-
raise TagError, "no message!" unless tag.locals.message
|
140
|
-
tag.expand
|
141
|
-
end
|
142
|
-
|
143
|
-
desc %{
|
144
|
-
Displays the message subject.
|
145
|
-
|
146
|
-
<pre><code><r:message:subject /></code></pre>
|
147
|
-
}
|
148
|
-
tag "message:subject" do |tag|
|
149
|
-
tag.locals.message.subject
|
150
|
-
end
|
151
|
-
|
152
|
-
desc %{
|
153
|
-
Displays the formatted message body.
|
154
|
-
|
155
|
-
<pre><code><r:message:body /></code></pre>
|
156
|
-
}
|
157
|
-
tag "message:body" do |tag|
|
158
|
-
tag.locals.message.filtered_body
|
159
|
-
end
|
160
|
-
|
161
|
-
desc %{
|
162
|
-
Returns the url of the show-message page.
|
163
|
-
|
164
|
-
<pre><code><r:message:url /></code></pre>
|
165
|
-
}
|
166
|
-
tag "message:url" do |tag|
|
167
|
-
preview_message_path(tag.locals.message)
|
168
|
-
end
|
169
|
-
|
170
|
-
desc %{
|
171
|
-
Displays a link to the show-message page.
|
172
|
-
|
173
|
-
<pre><code><r:message:link /></code></pre>
|
174
|
-
}
|
175
|
-
tag "message:link" do |tag|
|
176
|
-
options = tag.attr.dup
|
177
|
-
attributes = options.inject('') { |s, (k, v)| s << %{#{k.downcase}="#{v}" } }.strip
|
178
|
-
attributes = " #{attributes}" unless attributes.empty?
|
179
|
-
text = tag.double? ? tag.expand : tag.render('message:subject')
|
180
|
-
%{<a href="#{tag.render('message:url')}"#{attributes}>#{text}</a>}
|
15
|
+
tag 'reader_js' do |tag|
|
16
|
+
%{<script type="text/javascript" src="/javascripts/reader.js"></script>}
|
181
17
|
end
|
182
18
|
|
183
19
|
desc %{
|
@@ -295,16 +131,4 @@ module ReaderTags
|
|
295
131
|
tag "unless_reader" do |tag|
|
296
132
|
tag.expand unless Reader.current && !tag.locals.page.cache?
|
297
133
|
end
|
298
|
-
|
299
|
-
# work in progress
|
300
|
-
tag "truncated" do |tag|
|
301
|
-
limit = tag.attr['limit'] || 64
|
302
|
-
omission = tag.attr['omission'] || '…'
|
303
|
-
content = tag.expand
|
304
|
-
|
305
|
-
Rails.logger.warn "!! truncating #{content} to #{limit}#{omission}"
|
306
|
-
|
307
|
-
truncate_words(content, limit, omission)
|
308
|
-
end
|
309
|
-
|
310
134
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2011 Ryan Grove <ryan@wonko.com>
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
# of this software and associated documentation files (the 'Software'), to deal
|
6
|
+
# in the Software without restriction, including without limitation the rights
|
7
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
# copies of the Software, and to permit persons to whom the Software is
|
9
|
+
# furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
# The above copyright notice and this permission notice shall be included in all
|
12
|
+
# copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
# SOFTWARE.
|
21
|
+
#++
|
22
|
+
|
23
|
+
class Sanitize
|
24
|
+
module Config
|
25
|
+
GENEROUS = {
|
26
|
+
:elements => %w[
|
27
|
+
a b blockquote br caption cite code dd del dl dt em h1 h2 h3 h4 h5 h6 i img li ol p pre small span strike strong sub sup table tbody td th thead tr u ul
|
28
|
+
],
|
29
|
+
|
30
|
+
:attributes => {
|
31
|
+
:all => ['dir', 'lang', 'title', 'class'],
|
32
|
+
'a' => ['href'],
|
33
|
+
'blockquote' => ['cite'],
|
34
|
+
'img' => ['align', 'alt', 'height', 'src', 'width'],
|
35
|
+
'ol' => ['start', 'reversed', 'type'],
|
36
|
+
'ul' => ['type'],
|
37
|
+
'th' => ['colspan', 'rowspan'],
|
38
|
+
'td' => ['colspan', 'rowspan']
|
39
|
+
},
|
40
|
+
|
41
|
+
:protocols => {
|
42
|
+
'a' => {'href' => ['ftp', 'http', 'https', 'mailto', :relative]},
|
43
|
+
'blockquote' => {'cite' => ['http', 'https', :relative]},
|
44
|
+
'del' => {'cite' => ['http', 'https', :relative]},
|
45
|
+
'img' => {'src' => ['http', 'https', :relative]},
|
46
|
+
}
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|