radiant-reader-extension 0.9.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|