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.
Files changed (68) hide show
  1. data/README.md +15 -11
  2. data/VERSION +1 -1
  3. data/app/controllers/admin/messages_controller.rb +45 -6
  4. data/app/controllers/admin/reader_configuration_controller.rb +3 -0
  5. data/app/controllers/password_resets_controller.rb +8 -10
  6. data/app/controllers/reader_action_controller.rb +2 -2
  7. data/app/controllers/reader_activations_controller.rb +6 -7
  8. data/app/controllers/reader_sessions_controller.rb +3 -3
  9. data/app/controllers/readers_controller.rb +9 -10
  10. data/app/models/message.rb +2 -2
  11. data/app/models/message_function.rb +4 -0
  12. data/app/models/reader_notifier.rb +10 -7
  13. data/app/views/admin/messages/_form.html.haml +3 -1
  14. data/app/views/admin/messages/_list_function.haml +3 -0
  15. data/app/views/admin/messages/index.haml +42 -0
  16. data/app/views/admin/messages/preview.html.haml +1 -0
  17. data/app/views/admin/messages/show.html.haml +72 -0
  18. data/app/views/admin/reader_configuration/edit.html.haml +41 -0
  19. data/app/views/admin/reader_configuration/show.html.haml +46 -0
  20. data/app/views/admin/readers/_form.html.haml +2 -1
  21. data/app/views/admin/readers/index.html.haml +33 -2
  22. data/app/views/password_resets/create.html.haml +6 -9
  23. data/app/views/password_resets/edit.html.haml +26 -30
  24. data/app/views/password_resets/new.html.haml +10 -11
  25. data/app/views/reader_activations/show.html.haml +17 -26
  26. data/app/views/reader_sessions/_login_form.html.haml +19 -25
  27. data/app/views/reader_sessions/new.html.haml +17 -15
  28. data/app/views/readers/_flasher.html.haml +2 -2
  29. data/app/views/readers/_form.html.haml +30 -36
  30. data/app/views/readers/edit.html.haml +17 -19
  31. data/app/views/readers/index.html.haml +5 -7
  32. data/app/views/readers/login.html.haml +6 -5
  33. data/app/views/readers/new.html.haml +21 -20
  34. data/app/views/readers/permission_denied.html.haml +13 -9
  35. data/app/views/readers/show.html.haml +12 -9
  36. data/config/initializers/radiant_config.rb +12 -0
  37. data/config/locales/en.yml +147 -0
  38. data/config/routes.rb +5 -6
  39. data/db/migrate/20101019094714_message_sent_date.rb +11 -0
  40. data/lib/reader_admin_ui.rb +25 -10
  41. data/lib/reader_helper.rb +0 -7
  42. data/lib/reader_tags.rb +15 -10
  43. data/public/images/admin/delta.png +0 -0
  44. data/public/stylesheets/sass/admin/reader.sass +72 -81
  45. data/radiant-reader-extension.gemspec +13 -19
  46. data/reader_extension.rb +6 -7
  47. data/spec/controllers/admin/messages_controller_spec.rb +26 -9
  48. data/spec/controllers/readers_controller_spec.rb +1 -1
  49. data/spec/models/message_spec.rb +1 -2
  50. data/spec/models/reader_notifier_spec.rb +1 -2
  51. metadata +16 -22
  52. data/app/controllers/admin/reader_settings_controller.rb +0 -92
  53. data/app/helpers/admin/reader_settings_helper.rb +0 -36
  54. data/app/views/admin/reader_settings/_setting.html.haml +0 -24
  55. data/app/views/admin/reader_settings/edit.html.haml +0 -10
  56. data/app/views/admin/reader_settings/index.html.haml +0 -35
  57. data/app/views/admin/reader_settings/show.html.haml +0 -1
  58. data/app/views/admin/readers/_list_head.html.haml +0 -9
  59. data/app/views/admin/readers/_listed.html.haml +0 -22
  60. data/app/views/reader_activations/_activation_required.html.haml +0 -34
  61. data/app/views/reader_activations/_on_activation.html.haml +0 -4
  62. data/app/views/readers/create.html.haml +0 -28
  63. data/app/views/wrappers/_field_errors.html.haml +0 -5
  64. data/config/settings.rb +0 -9
  65. data/pkg/radiant-reader-extension-0.9.0.gem +0 -0
  66. data/public/images/admin/new-message.png +0 -0
  67. data/public/images/admin/new-reader.png +0 -0
  68. 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 but currently undergoing some renovation.
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.8.1 (we need the new config machinery) or 0.9. [share_layouts](http://github.com/spanner/radiant-share-layouts-extension) (currently you need our version, which works with ActionMailer too). If you're on 0.8.1 you will probably want the [submenu](https://github.com/spanner/radiant-submenu-extension/tree) extension too.
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 in your configuration. If it is false, then reader accounts can only be created by the administrator.
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.9.2
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
- def index
5
- redirect_to admin_reader_settings_url
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
- admin_reader_settings_url
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
- @message.function_id = params[:function]
55
+ model.function_id = params[:function]
17
56
  end
18
57
  end
19
-
58
+
20
59
  end
@@ -0,0 +1,3 @@
1
+ class Admin::ReaderConfigurationController < Admin::ConfigurationController
2
+
3
+ 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] = "Password reset instructions have been emailed to you."
18
+ flash[:notice] = "reset_message_sent"
19
19
  render
20
20
  else
21
21
  @reader.send_activation_message
22
- flash[:notice] = "Account activation instructions have been emailed to you."
22
+ flash[:notice] = "activation_message_sent"
23
23
  redirect_to new_reader_activation_url
24
24
  end
25
25
  else
26
- @error = flash[:error] = "Sorry. That email address is not known here."
26
+ @error = flash[:error] = "email_unknown"
27
27
  render :action => :new
28
28
  end
29
29
  end
30
30
 
31
31
  def edit
32
- if @reader
33
- flash[:notice] = "Thank you. Please enter and confirm a new password."
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] = "Thank you. Your password has been updated and you are now logged in."
44
+ flash[:notice] = 'password_updated_notice'
47
45
  redirect_to url_for(@reader)
48
46
  else
49
- flash[:error] = "Passwords don't match! Please try again."
47
+ flash[:error] = 'password_mismatch'
50
48
  render :action => :edit
51
49
  end
52
50
  else
53
- flash[:error] = "Sorry: can't find you."
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] || "Sorry: permission denied"
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] = "Please log out first"
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, but in a usefully restricted way:
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] = "Account activation instructions have been emailed to you."
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] = "Thank you! Your account has been activated."
31
+ flash[:notice] = "thanks_activated"
32
32
  redirect_back_or_to default_activated_url
33
-
34
33
  else
35
- @error = "Sorry: something was wrong in that link. Please check your email message."
36
- flash[:error] = "Activation failed."
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] = "Hello #{@reader.name}! Your account is already active."
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] = "Hello #{@reader_session.reader.name}. Welcome back."
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] = "Sorry: that combination of login and password is not known here."
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] = "You are logged out. Bye!"
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] = "Please don't fill in the spam trap field."
52
+ flash[:error] = 'please_avoid_spam_trap'
54
53
  @reader.email = ''
55
- @reader.errors.add(:trap, "must be empty")
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] = "Please use the registration form."
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] = "Your account has been updated"
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] = "Sorry. You are not allowed to edit other people's accounts." if params[:id] && params[:id] != current_reader.id
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] = 'Sorry. Wrong password.'
105
- @reader.errors.add(:current_password, "was not correct")
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] = "You can't delete readers here. Please log in to the admin interface."
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] = "Sorry. This site does not allow public registration."
115
+ flash[:error] = "registration_disallowed"
117
116
  redirect_to reader_login_url
118
117
  false
119
118
  end
@@ -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
@@ -14,6 +14,10 @@ class MessageFunction
14
14
  @name
15
15
  end
16
16
 
17
+ def humanize
18
+ to_s.gsub('_', ' ')
19
+ end
20
+
17
21
  def self.[](value)
18
22
  return if value.blank?
19
23
  @@functions.find { |function| function.symbol == value.to_s.downcase.intern }
@@ -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 "email"
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['site.mail_prefix']
9
- host = site ? site.base_domain : Radiant::Config['site.url'] || 'www.example.com'
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 ||= message.created_by
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 message.created_by.email
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.name'],
29
- :url => Radiant::Config['site.url']
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", admin_messages_url
31
+ = link_to "cancel", admin_reader_configuration_url
@@ -0,0 +1,3 @@
1
+ - if message.has_function?
2
+ %span.function
3
+ = message.function.description
@@ -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