radiant-reader-extension 0.9.2 → 1.0.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/README.md +15 -11
- data/VERSION +1 -1
- data/app/controllers/admin/messages_controller.rb +45 -6
- data/app/controllers/admin/reader_configuration_controller.rb +3 -0
- data/app/controllers/password_resets_controller.rb +8 -10
- data/app/controllers/reader_action_controller.rb +2 -2
- data/app/controllers/reader_activations_controller.rb +6 -7
- data/app/controllers/reader_sessions_controller.rb +3 -3
- data/app/controllers/readers_controller.rb +9 -10
- data/app/models/message.rb +2 -2
- data/app/models/message_function.rb +4 -0
- data/app/models/reader_notifier.rb +10 -7
- data/app/views/admin/messages/_form.html.haml +3 -1
- data/app/views/admin/messages/_list_function.haml +3 -0
- data/app/views/admin/messages/index.haml +42 -0
- data/app/views/admin/messages/preview.html.haml +1 -0
- data/app/views/admin/messages/show.html.haml +72 -0
- data/app/views/admin/reader_configuration/edit.html.haml +41 -0
- data/app/views/admin/reader_configuration/show.html.haml +46 -0
- data/app/views/admin/readers/_form.html.haml +2 -1
- data/app/views/admin/readers/index.html.haml +33 -2
- data/app/views/password_resets/create.html.haml +6 -9
- data/app/views/password_resets/edit.html.haml +26 -30
- data/app/views/password_resets/new.html.haml +10 -11
- data/app/views/reader_activations/show.html.haml +17 -26
- data/app/views/reader_sessions/_login_form.html.haml +19 -25
- data/app/views/reader_sessions/new.html.haml +17 -15
- data/app/views/readers/_flasher.html.haml +2 -2
- data/app/views/readers/_form.html.haml +30 -36
- data/app/views/readers/edit.html.haml +17 -19
- data/app/views/readers/index.html.haml +5 -7
- data/app/views/readers/login.html.haml +6 -5
- data/app/views/readers/new.html.haml +21 -20
- data/app/views/readers/permission_denied.html.haml +13 -9
- data/app/views/readers/show.html.haml +12 -9
- data/config/initializers/radiant_config.rb +12 -0
- data/config/locales/en.yml +147 -0
- data/config/routes.rb +5 -6
- data/db/migrate/20101019094714_message_sent_date.rb +11 -0
- data/lib/reader_admin_ui.rb +25 -10
- data/lib/reader_helper.rb +0 -7
- data/lib/reader_tags.rb +15 -10
- data/public/images/admin/delta.png +0 -0
- data/public/stylesheets/sass/admin/reader.sass +72 -81
- data/radiant-reader-extension.gemspec +13 -19
- data/reader_extension.rb +6 -7
- data/spec/controllers/admin/messages_controller_spec.rb +26 -9
- data/spec/controllers/readers_controller_spec.rb +1 -1
- data/spec/models/message_spec.rb +1 -2
- data/spec/models/reader_notifier_spec.rb +1 -2
- metadata +16 -22
- data/app/controllers/admin/reader_settings_controller.rb +0 -92
- data/app/helpers/admin/reader_settings_helper.rb +0 -36
- data/app/views/admin/reader_settings/_setting.html.haml +0 -24
- data/app/views/admin/reader_settings/edit.html.haml +0 -10
- data/app/views/admin/reader_settings/index.html.haml +0 -35
- data/app/views/admin/reader_settings/show.html.haml +0 -1
- data/app/views/admin/readers/_list_head.html.haml +0 -9
- data/app/views/admin/readers/_listed.html.haml +0 -22
- data/app/views/reader_activations/_activation_required.html.haml +0 -34
- data/app/views/reader_activations/_on_activation.html.haml +0 -4
- data/app/views/readers/create.html.haml +0 -28
- data/app/views/wrappers/_field_errors.html.haml +0 -5
- data/config/settings.rb +0 -9
- data/pkg/radiant-reader-extension-0.9.0.gem +0 -0
- data/public/images/admin/new-message.png +0 -0
- data/public/images/admin/new-reader.png +0 -0
- data/public/javascripts/admin/messages.js +0 -13
data/README.md
CHANGED
@@ -10,21 +10,18 @@ The purpose of this extension is to provide a common core that supports other vi
|
|
10
10
|
|
11
11
|
## Latest
|
12
12
|
|
13
|
+
* **currently requires the `preconfiguration` branch of radiant**
|
14
|
+
* public interface internationalized
|
13
15
|
* New configuration interface
|
14
|
-
|
15
|
-
* Provisionally updated for 0.9, but still being tweaked and tested: not definitely stable yet
|
16
|
-
|
17
|
-
* I'm about to start cleaning out the messaging interface. Some of its extra clutter will be moved into a newsletter extension so that here we can concentrate on making administrative messages easy to edit.
|
16
|
+
* Messaging much simplified: now intended to be purely administrative.
|
18
17
|
|
19
18
|
## Status
|
20
19
|
|
21
|
-
Compatible with radiant 0.9
|
22
|
-
|
23
|
-
Tests are thorough. A lot of our work relies on this extension.
|
20
|
+
Compatible with radiant 0.9.2, which isn't out yet. You can use the preconfiguration branch of radiant edge to try this out. Expect changes.
|
24
21
|
|
25
22
|
## Requirements
|
26
23
|
|
27
|
-
Radiant 0.
|
24
|
+
Radiant 0.9.2. The [layouts](http://github.com/squaretalent/radiant-layouts-extension) and [mailer_layouts](http://github.com/spanner/radiant-mailer_layouts-extension) extensions.
|
28
25
|
|
29
26
|
You also need three gems (in addition to those that radiant requires): authlogic, gravtastic and sanitize. They're declared in the extension so you should be able just to run
|
30
27
|
|
@@ -38,15 +35,22 @@ in your environment.rb before you can migrate anything. Authlogic has to load be
|
|
38
35
|
|
39
36
|
## Installation
|
40
37
|
|
38
|
+
As a gem:
|
39
|
+
|
40
|
+
gem install 'radiant_reader_extension'
|
41
|
+
|
42
|
+
or for more control:
|
43
|
+
|
41
44
|
git submodule add git://github.com/spanner/radiant-reader-extension.git vendor/extensions/reader
|
45
|
+
|
46
|
+
and then:
|
47
|
+
|
42
48
|
rake radiant:extensions:reader:migrate
|
43
49
|
rake radiant:extensions:reader:update
|
44
50
|
|
45
|
-
The update task will install a /stylesheets/admin/reader.css that you can leave alone and a /stylesheets/reader.css that you should call from your reader layout (see below) and will want to improve upon. There is also a very thin /javascripts/reader.js: all it does is fade notifications. The forum extension has a lot more javascripts for you to deplore.
|
46
|
-
|
47
51
|
## Configuration
|
48
52
|
|
49
|
-
If you want to allow public registration, set `reader.allow_registration?` to true
|
53
|
+
If you want to allow public registration, set `reader.allow_registration?` to true. If it is false, then reader accounts can only be created by the administrator.
|
50
54
|
|
51
55
|
Under multi_site Reader adds a `reader_layout` column to the site table and a layout-chooser to the site-edit view. In a single-site installation you will also need these configuration entries:
|
52
56
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
@@ -1,20 +1,59 @@
|
|
1
1
|
class Admin::MessagesController < Admin::ResourceController
|
2
|
+
skip_before_filter :load_model
|
3
|
+
before_filter :load_model, :except => :index # we want the filter to run before :show too
|
2
4
|
before_filter :set_function, :only => :new
|
3
|
-
|
4
|
-
|
5
|
-
|
5
|
+
|
6
|
+
# here :show is the preview/send page
|
7
|
+
def show
|
8
|
+
|
6
9
|
end
|
7
10
|
|
11
|
+
# mock email view called into an iframe in the :show view
|
12
|
+
# the view calls @message.preview, which returns the message body
|
13
|
+
def preview
|
14
|
+
render :layout => false
|
15
|
+
end
|
16
|
+
|
17
|
+
def deliver
|
18
|
+
case params['delivery']
|
19
|
+
when "all"
|
20
|
+
@readers = @message.possible_readers
|
21
|
+
when "inactive"
|
22
|
+
@readers = @message.inactive_readers
|
23
|
+
when "unsent"
|
24
|
+
@readers = @message.undelivered_readers
|
25
|
+
else
|
26
|
+
redirect_to admin_message_url(@message)
|
27
|
+
return
|
28
|
+
end
|
29
|
+
failures = @message.deliver(@readers) || []
|
30
|
+
if failures.any?
|
31
|
+
if failures.length == @readers.length
|
32
|
+
flash[:error] = "all_deliveries_failed"
|
33
|
+
else
|
34
|
+
addresses = failures.map(&:email).to_sentence
|
35
|
+
flash[:notice] = "some_deliveries_failed"
|
36
|
+
end
|
37
|
+
else
|
38
|
+
flash[:notice] = "message_delivered"
|
39
|
+
end
|
40
|
+
redirect_to admin_message_url(@message)
|
41
|
+
end
|
42
|
+
|
8
43
|
protected
|
9
44
|
|
10
45
|
def continue_url(options)
|
11
|
-
|
46
|
+
if action_name == "destroy"
|
47
|
+
redirect_to :back
|
48
|
+
else
|
49
|
+
options[:redirect_to] || (params[:continue] ? {:action => 'edit', :id => model.id} : admin_message_url(model))
|
50
|
+
end
|
12
51
|
end
|
13
52
|
|
14
53
|
def set_function
|
15
54
|
if params[:function]
|
16
|
-
|
55
|
+
model.function_id = params[:function]
|
17
56
|
end
|
18
57
|
end
|
19
|
-
|
58
|
+
|
20
59
|
end
|
@@ -15,24 +15,22 @@ class PasswordResetsController < ApplicationController
|
|
15
15
|
if @reader
|
16
16
|
if @reader.activated?
|
17
17
|
@reader.send_password_reset_message
|
18
|
-
flash[:notice] = "
|
18
|
+
flash[:notice] = "reset_message_sent"
|
19
19
|
render
|
20
20
|
else
|
21
21
|
@reader.send_activation_message
|
22
|
-
flash[:notice] = "
|
22
|
+
flash[:notice] = "activation_message_sent"
|
23
23
|
redirect_to new_reader_activation_url
|
24
24
|
end
|
25
25
|
else
|
26
|
-
@error = flash[:error] = "
|
26
|
+
@error = flash[:error] = "email_unknown"
|
27
27
|
render :action => :new
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
31
|
def edit
|
32
|
-
|
33
|
-
flash[:
|
34
|
-
else
|
35
|
-
flash[:error] = "Sorry: can't find you."
|
32
|
+
unless @reader
|
33
|
+
flash[:error] = 'reset_not_found'
|
36
34
|
end
|
37
35
|
render
|
38
36
|
end
|
@@ -43,14 +41,14 @@ class PasswordResetsController < ApplicationController
|
|
43
41
|
@reader.password_confirmation = params[:reader][:password_confirmation]
|
44
42
|
if @reader.save
|
45
43
|
self.current_reader = @reader
|
46
|
-
flash[:notice] =
|
44
|
+
flash[:notice] = 'password_updated_notice'
|
47
45
|
redirect_to url_for(@reader)
|
48
46
|
else
|
49
|
-
flash[:error] =
|
47
|
+
flash[:error] = 'password_mismatch'
|
50
48
|
render :action => :edit
|
51
49
|
end
|
52
50
|
else
|
53
|
-
flash[:error] =
|
51
|
+
flash[:error] = 'reset_not_found'
|
54
52
|
render :action => :edit # without @reader, this will take us back to the enter-your-code form
|
55
53
|
end
|
56
54
|
end
|
@@ -25,7 +25,7 @@ class ReaderActionController < ApplicationController
|
|
25
25
|
|
26
26
|
def permission_denied
|
27
27
|
session[:return_to] ||= request.referer
|
28
|
-
@title = flash[:error] ||
|
28
|
+
@title = flash[:error] || t('permission_denied')
|
29
29
|
render
|
30
30
|
end
|
31
31
|
|
@@ -75,7 +75,7 @@ protected
|
|
75
75
|
def require_no_reader
|
76
76
|
if set_reader
|
77
77
|
store_location
|
78
|
-
flash[:notice] =
|
78
|
+
flash[:notice] = 'please_log_out'
|
79
79
|
redirect_back_or_to url_for(current_reader)
|
80
80
|
return false
|
81
81
|
end
|
@@ -7,7 +7,7 @@ class ReaderActivationsController < ReaderActionController
|
|
7
7
|
|
8
8
|
radiant_layout { |controller| Radiant::Config['reader.layout'] }
|
9
9
|
|
10
|
-
# this is just fake REST: we're actually working on the reader, not an activation object
|
10
|
+
# this is just fake REST: we're actually working on the reader, not an activation object.
|
11
11
|
# .show sends out an activation message if we can identify the current reader
|
12
12
|
# .update activates the reader, if the token is correct
|
13
13
|
|
@@ -19,7 +19,7 @@ class ReaderActivationsController < ReaderActionController
|
|
19
19
|
if current_reader
|
20
20
|
@reader = current_reader
|
21
21
|
@reader.send_activation_message
|
22
|
-
flash[:notice] = "
|
22
|
+
flash[:notice] = "activation_message_sent"
|
23
23
|
end
|
24
24
|
render :action => 'show'
|
25
25
|
end
|
@@ -28,12 +28,11 @@ class ReaderActivationsController < ReaderActionController
|
|
28
28
|
if @reader
|
29
29
|
@reader.activate!
|
30
30
|
self.current_reader = @reader
|
31
|
-
flash[:notice] = "
|
31
|
+
flash[:notice] = "thanks_activated"
|
32
32
|
redirect_back_or_to default_activated_url
|
33
|
-
|
34
33
|
else
|
35
|
-
@error = "
|
36
|
-
flash[:error] = "
|
34
|
+
@error = "please_check_message"
|
35
|
+
flash[:error] = "activation_failed."
|
37
36
|
render :action => 'show'
|
38
37
|
end
|
39
38
|
end
|
@@ -47,7 +46,7 @@ protected
|
|
47
46
|
|
48
47
|
def check_reader_inactive
|
49
48
|
if @reader && @reader.activated?
|
50
|
-
flash[:notice] = "
|
49
|
+
flash[:notice] = t('hello').titlecase + " #{@reader.name}! " + t('already_active')
|
51
50
|
redirect_back_or_to default_activated_url
|
52
51
|
false
|
53
52
|
end
|
@@ -16,7 +16,7 @@ class ReaderSessionsController < ReaderActionController
|
|
16
16
|
end
|
17
17
|
respond_to do |format|
|
18
18
|
format.html {
|
19
|
-
flash[:notice] = "
|
19
|
+
flash[:notice] = t('hello').titlecase + " #{@reader_session.reader.name}. " + t('welcome_back')
|
20
20
|
redirect_back_or_to default_loggedin_url
|
21
21
|
}
|
22
22
|
format.js {
|
@@ -27,7 +27,7 @@ class ReaderSessionsController < ReaderActionController
|
|
27
27
|
else
|
28
28
|
respond_to do |format|
|
29
29
|
format.html {
|
30
|
-
flash[:error] =
|
30
|
+
flash[:error] = 'login_unknown'
|
31
31
|
render :action => :new
|
32
32
|
}
|
33
33
|
format.js { render :action => :new, :layout => false }
|
@@ -43,7 +43,7 @@ class ReaderSessionsController < ReaderActionController
|
|
43
43
|
session['user_id'] = nil
|
44
44
|
current_user = nil
|
45
45
|
end
|
46
|
-
flash[:notice] =
|
46
|
+
flash[:notice] = 'logout_message'
|
47
47
|
redirect_back_or_to reader_login_url
|
48
48
|
end
|
49
49
|
|
@@ -29,7 +29,6 @@ class ReadersController < ReaderActionController
|
|
29
29
|
render :partial => 'readers/controls'
|
30
30
|
}
|
31
31
|
end
|
32
|
-
|
33
32
|
end
|
34
33
|
|
35
34
|
def new
|
@@ -50,14 +49,14 @@ class ReadersController < ReaderActionController
|
|
50
49
|
@reader.clear_password = params[:reader][:password]
|
51
50
|
|
52
51
|
unless @reader.email.blank?
|
53
|
-
flash[:error] =
|
52
|
+
flash[:error] = 'please_avoid_spam_trap'
|
54
53
|
@reader.email = ''
|
55
|
-
@reader.errors.add(:trap, "
|
54
|
+
@reader.errors.add(:trap, "must_be_empty")
|
56
55
|
render :action => 'new' and return
|
57
56
|
end
|
58
57
|
|
59
58
|
unless @email_field = session[:email_field]
|
60
|
-
flash[:error] =
|
59
|
+
flash[:error] = 'please_use_form'
|
61
60
|
redirect_to new_reader_url and return
|
62
61
|
end
|
63
62
|
|
@@ -76,7 +75,7 @@ class ReadersController < ReaderActionController
|
|
76
75
|
@reader.attributes = params[:reader]
|
77
76
|
@reader.clear_password = params[:reader][:password] if params[:reader][:password]
|
78
77
|
if @reader.save
|
79
|
-
flash[:notice] =
|
78
|
+
flash[:notice] = 'account_updated'
|
80
79
|
redirect_to url_for(@reader)
|
81
80
|
else
|
82
81
|
render :action => 'edit'
|
@@ -90,7 +89,7 @@ protected
|
|
90
89
|
end
|
91
90
|
|
92
91
|
def restrict_to_self
|
93
|
-
flash[:error] = "
|
92
|
+
flash[:error] = "cannot_edit_others" if params[:id] && params[:id] != current_reader.id
|
94
93
|
@reader = current_reader
|
95
94
|
end
|
96
95
|
|
@@ -101,19 +100,19 @@ protected
|
|
101
100
|
@reader.attributes = params[:reader]
|
102
101
|
@reader.valid?
|
103
102
|
|
104
|
-
flash[:error] = '
|
105
|
-
@reader.errors.add(:current_password, "
|
103
|
+
flash[:error] = 'password_incorrect'
|
104
|
+
@reader.errors.add(:current_password, "not_correct")
|
106
105
|
render :action => 'edit' and return false
|
107
106
|
end
|
108
107
|
|
109
108
|
def no_removing
|
110
|
-
flash[:error] =
|
109
|
+
flash[:error] = 'cannot_delete_readers'
|
111
110
|
redirect_to admin_readers_url
|
112
111
|
end
|
113
112
|
|
114
113
|
def check_registration_allowed
|
115
114
|
unless Radiant::Config['reader.allow_registration?']
|
116
|
-
flash[:error] = "
|
115
|
+
flash[:error] = "registration_disallowed"
|
117
116
|
redirect_to reader_login_url
|
118
117
|
false
|
119
118
|
end
|
data/app/models/message.rb
CHANGED
@@ -19,8 +19,8 @@ class Message < ActiveRecord::Base
|
|
19
19
|
|
20
20
|
default_scope :order => 'updated_at DESC, created_at DESC'
|
21
21
|
named_scope :for_function, lambda { |f| {:conditions => ["function_id = ?", f.to_s]} }
|
22
|
-
named_scope :administrative, { :conditions => "function_id IS NOT NULL" }
|
23
|
-
named_scope :ordinary, { :conditions => "function_id IS NULL" }
|
22
|
+
named_scope :administrative, { :conditions => "function_id IS NOT NULL AND NOT function_id = ''" }
|
23
|
+
named_scope :ordinary, { :conditions => "function_id = '' OR function_id IS NULL" }
|
24
24
|
named_scope :published, { :conditions => "status_id >= 100" }
|
25
25
|
|
26
26
|
def filtered_body
|
@@ -1,20 +1,22 @@
|
|
1
1
|
class ReaderNotifier < ActionMailer::Base
|
2
2
|
|
3
3
|
# this sets a default that will be overridden by the layout association of each message as it is sent out
|
4
|
-
radiant_layout
|
4
|
+
radiant_layout lambda { Radiant::Config['email.layout'] || 'email'}
|
5
5
|
|
6
6
|
def message(reader, message, sender=nil)
|
7
7
|
site = reader.site if reader.respond_to?(:site)
|
8
|
-
prefix = site ? site.abbreviation : Radiant::Config['
|
9
|
-
host = site ? site.base_domain : Radiant::Config['site.
|
8
|
+
prefix = site ? site.abbreviation : Radiant::Config['email.prefix']
|
9
|
+
host = site ? site.base_domain : Radiant::Config['site.domain'] || 'www.example.com'
|
10
10
|
default_url_options[:host] = host
|
11
|
-
sender
|
11
|
+
sender = Radiant::Config['email.name'] || "sender_not_configured"
|
12
|
+
sender_address = Radiant::Config['email.address'] || "admin@#{host}"
|
12
13
|
|
13
14
|
message_layout(message.layout) if message.layout
|
14
15
|
content_type("text/html")
|
15
16
|
subject (prefix || '') + message.subject
|
16
17
|
recipients(reader.email)
|
17
|
-
from
|
18
|
+
from ["#{sender} <#{sender_address}>"]
|
19
|
+
reply_to = [sender_address]
|
18
20
|
subject message.subject
|
19
21
|
sent_on(Time.now)
|
20
22
|
|
@@ -23,10 +25,11 @@ class ReaderNotifier < ActionMailer::Base
|
|
23
25
|
:title => message.subject,
|
24
26
|
:message => message.filtered_body,
|
25
27
|
:sender => sender,
|
28
|
+
:reply_to => sender_address,
|
26
29
|
:reader => reader,
|
27
30
|
:site => site || {
|
28
|
-
:name => Radiant::Config['site.
|
29
|
-
:url => Radiant::Config['site.
|
31
|
+
:name => Radiant::Config['site.title'],
|
32
|
+
:url => Radiant::Config['site.domain']
|
30
33
|
}
|
31
34
|
})
|
32
35
|
end
|
@@ -18,6 +18,8 @@
|
|
18
18
|
= form.label :body, "Message Body"
|
19
19
|
= form.text_area :body, :class => 'textarea', :style => 'width: 100%'
|
20
20
|
|
21
|
+
= render_region :body_bottom, :locals => {:form => form}
|
22
|
+
|
21
23
|
- render_region :form_bottom do |form_bottom|
|
22
24
|
- form_bottom.edit_timestamp do
|
23
25
|
= updated_stamp @message
|
@@ -26,4 +28,4 @@
|
|
26
28
|
= save_model_button(@message)
|
27
29
|
= save_model_and_continue_editing_button(@message)
|
28
30
|
or
|
29
|
-
= link_to "cancel",
|
31
|
+
= link_to "cancel", admin_reader_configuration_url
|
@@ -0,0 +1,42 @@
|
|
1
|
+
- include_stylesheet('admin/reader')
|
2
|
+
= render_region :top
|
3
|
+
|
4
|
+
#messages_table.outset
|
5
|
+
%table#messages.index{:cellspacing=>"0", :border=>"0", :cellpadding=>"0"}
|
6
|
+
%thead
|
7
|
+
%tr
|
8
|
+
- render_region :thead do |thead|
|
9
|
+
- thead.subject_header do
|
10
|
+
%th.message Subject
|
11
|
+
- thead.sent_header do
|
12
|
+
%th.message_sent Delivery status
|
13
|
+
- thead.modify_header do
|
14
|
+
%th.modify Modify
|
15
|
+
%tbody
|
16
|
+
- @messages.each do |message|
|
17
|
+
%tr
|
18
|
+
- render_region :tbody do |tbody|
|
19
|
+
- tbody.subject_cell do
|
20
|
+
%td.name
|
21
|
+
= link_to message.subject, admin_message_url(message), :class => message.has_function? ? "functional" : "normal"
|
22
|
+
= render :partial => '/admin/messages/list_function', :locals => {:message => message}
|
23
|
+
|
24
|
+
- tbody.sent_cell do
|
25
|
+
%td.message_sent
|
26
|
+
%p
|
27
|
+
- if message.sent_at
|
28
|
+
= t('last_sent')
|
29
|
+
= l(message.sent_at, :format => :short)
|
30
|
+
- else
|
31
|
+
= t('never_sent')
|
32
|
+
- tbody.modify_cell do
|
33
|
+
%td.actions
|
34
|
+
= link_to( image('delta') + ' ' + t('edit_message'), edit_admin_message_url(message), :class => "action" )
|
35
|
+
= link_to( image('minus') + ' ' + t('delete_message'), admin_message_url(message), {:method => :delete, :class => "action", :confirm => t('really_delete_message', :title => message.subject)})
|
36
|
+
|
37
|
+
- render_region :bottom do |bottom|
|
38
|
+
- bottom.buttons do
|
39
|
+
#actions
|
40
|
+
= pagination_for @messages
|
41
|
+
%ul
|
42
|
+
%li= link_to image('plus') + " " + "new message", new_admin_message_url
|