radiant-reader-extension 0.9.2

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 (116) hide show
  1. data/.gitignore +2 -0
  2. data/README.md +89 -0
  3. data/Rakefile +140 -0
  4. data/VERSION +1 -0
  5. data/app/controllers/admin/messages_controller.rb +20 -0
  6. data/app/controllers/admin/reader_settings_controller.rb +92 -0
  7. data/app/controllers/admin/readers_controller.rb +28 -0
  8. data/app/controllers/password_resets_controller.rb +64 -0
  9. data/app/controllers/reader_action_controller.rb +84 -0
  10. data/app/controllers/reader_activations_controller.rb +60 -0
  11. data/app/controllers/reader_sessions_controller.rb +56 -0
  12. data/app/controllers/readers_controller.rb +131 -0
  13. data/app/helpers/admin/reader_settings_helper.rb +36 -0
  14. data/app/models/message.rb +108 -0
  15. data/app/models/message_function.rb +37 -0
  16. data/app/models/message_reader.rb +13 -0
  17. data/app/models/reader.rb +146 -0
  18. data/app/models/reader_notifier.rb +34 -0
  19. data/app/models/reader_session.rb +3 -0
  20. data/app/views/admin/messages/_form.html.haml +29 -0
  21. data/app/views/admin/messages/_help.html.haml +41 -0
  22. data/app/views/admin/messages/_message_description.html.haml +3 -0
  23. data/app/views/admin/messages/edit.html.haml +16 -0
  24. data/app/views/admin/messages/new.html.haml +16 -0
  25. data/app/views/admin/reader_settings/_setting.html.haml +24 -0
  26. data/app/views/admin/reader_settings/edit.html.haml +10 -0
  27. data/app/views/admin/reader_settings/index.html.haml +35 -0
  28. data/app/views/admin/reader_settings/show.html.haml +1 -0
  29. data/app/views/admin/readers/_avatar.html.haml +3 -0
  30. data/app/views/admin/readers/_form.html.haml +50 -0
  31. data/app/views/admin/readers/_list_head.html.haml +9 -0
  32. data/app/views/admin/readers/_listed.html.haml +22 -0
  33. data/app/views/admin/readers/_password_fields.html.haml +18 -0
  34. data/app/views/admin/readers/edit.html.haml +8 -0
  35. data/app/views/admin/readers/index.html.haml +17 -0
  36. data/app/views/admin/readers/new.html.haml +7 -0
  37. data/app/views/admin/readers/remove.html.haml +18 -0
  38. data/app/views/admin/sites/_choose_reader_layout.html.haml +7 -0
  39. data/app/views/password_resets/create.html.haml +13 -0
  40. data/app/views/password_resets/edit.html.haml +71 -0
  41. data/app/views/password_resets/new.html.haml +31 -0
  42. data/app/views/reader_activations/_activation_required.html.haml +34 -0
  43. data/app/views/reader_activations/_on_activation.html.haml +4 -0
  44. data/app/views/reader_activations/show.html.haml +41 -0
  45. data/app/views/reader_notifier/message.html.haml +1 -0
  46. data/app/views/reader_sessions/_login_form.html.haml +59 -0
  47. data/app/views/reader_sessions/new.html.haml +38 -0
  48. data/app/views/readers/_contributions.html.haml +2 -0
  49. data/app/views/readers/_controls.html.haml +25 -0
  50. data/app/views/readers/_extra_controls.html.haml +0 -0
  51. data/app/views/readers/_flasher.html.haml +6 -0
  52. data/app/views/readers/_form.html.haml +73 -0
  53. data/app/views/readers/create.html.haml +28 -0
  54. data/app/views/readers/edit.html.haml +47 -0
  55. data/app/views/readers/index.html.haml +16 -0
  56. data/app/views/readers/login.html.haml +15 -0
  57. data/app/views/readers/new.html.haml +41 -0
  58. data/app/views/readers/permission_denied.html.haml +23 -0
  59. data/app/views/readers/show.html.haml +35 -0
  60. data/app/views/wrappers/_field_errors.html.haml +5 -0
  61. data/config/routes.rb +22 -0
  62. data/config/settings.rb +9 -0
  63. data/db/migrate/001_create_readers.rb +31 -0
  64. data/db/migrate/002_extend_sites.rb +17 -0
  65. data/db/migrate/003_reader_honorifics.rb +12 -0
  66. data/db/migrate/004_user_readers.rb +11 -0
  67. data/db/migrate/005_last_login.rb +15 -0
  68. data/db/migrate/007_adapt_for_authlogic.rb +27 -0
  69. data/db/migrate/20090921125653_reader_messages.rb +27 -0
  70. data/db/migrate/20090924164413_functional_messages.rb +9 -0
  71. data/db/migrate/20090925081225_standard_messages.rb +106 -0
  72. data/db/migrate/20091006102438_message_visibility.rb +9 -0
  73. data/db/migrate/20091010083503_registration_config.rb +10 -0
  74. data/db/migrate/20091019124021_message_functions.rb +9 -0
  75. data/db/migrate/20091020133533_forenames.rb +9 -0
  76. data/db/migrate/20091020135152_contacts.rb +23 -0
  77. data/db/migrate/20091111090819_ensure_functional_messages_visible.rb +9 -0
  78. data/db/migrate/20091119092936_messages_have_layout.rb +9 -0
  79. data/db/migrate/20100922152338_lock_versions.rb +9 -0
  80. data/db/migrate/20100927095703_default_settings.rb +14 -0
  81. data/db/migrate/20101004074945_unlock_version.rb +9 -0
  82. data/lib/config_extensions.rb +5 -0
  83. data/lib/controller_extensions.rb +77 -0
  84. data/lib/reader_admin_ui.rb +64 -0
  85. data/lib/reader_helper.rb +36 -0
  86. data/lib/reader_site.rb +10 -0
  87. data/lib/reader_tags.rb +297 -0
  88. data/lib/rfc822.rb +29 -0
  89. data/lib/tasks/reader_extension_tasks.rake +28 -0
  90. data/pkg/radiant-reader-extension-0.9.0.gem +0 -0
  91. data/public/images/admin/chk_off.png +0 -0
  92. data/public/images/admin/chk_on.png +0 -0
  93. data/public/images/admin/new-message.png +0 -0
  94. data/public/images/admin/new-reader.png +0 -0
  95. data/public/javascripts/admin/messages.js +13 -0
  96. data/public/stylesheets/sass/admin/reader.sass +95 -0
  97. data/radiant-reader-extension.gemspec +184 -0
  98. data/reader_extension.rb +55 -0
  99. data/spec/controllers/admin/messages_controller_spec.rb +38 -0
  100. data/spec/controllers/admin/readers_controller_spec.rb +14 -0
  101. data/spec/controllers/password_resets_controller_spec.rb +140 -0
  102. data/spec/controllers/reader_activations_controller_spec.rb +45 -0
  103. data/spec/controllers/readers_controller_spec.rb +193 -0
  104. data/spec/datasets/messages_dataset.rb +49 -0
  105. data/spec/datasets/reader_layouts_dataset.rb +26 -0
  106. data/spec/datasets/reader_sites_dataset.rb +10 -0
  107. data/spec/datasets/readers_dataset.rb +51 -0
  108. data/spec/lib/reader_admin_ui_spec.rb +35 -0
  109. data/spec/lib/reader_site_spec.rb +18 -0
  110. data/spec/matchers/reader_login_system_matcher.rb +35 -0
  111. data/spec/models/message_spec.rb +109 -0
  112. data/spec/models/reader_notifier_spec.rb +34 -0
  113. data/spec/models/reader_spec.rb +155 -0
  114. data/spec/spec.opts +5 -0
  115. data/spec/spec_helper.rb +48 -0
  116. metadata +267 -0
File without changes
@@ -0,0 +1,6 @@
1
+ - if flash[:notice]
2
+ .notice
3
+ %p= flash[:notice]
4
+ - if flash[:error]
5
+ .error
6
+ %p= flash[:error]
@@ -0,0 +1,73 @@
1
+ - with_error_report(@reader.errors.on(:name)) do
2
+ = f.label :name, 'Your name', :class => 'required'
3
+ %span.formnote as you would like it to appear
4
+ %br
5
+ = f.text_field :name, :class => 'standard'
6
+
7
+ - if Radiant::Config['reader.use_honorifics?']
8
+ - with_error_report(@reader.errors.on(:honorific)) do
9
+ = f.label :honorific, 'Title or rank', :class => 'optional'
10
+ %span.formnote as you would like us to display it when you are credited
11
+ %br
12
+ = f.text_field :honorific, :class => 'standard'
13
+
14
+ - if @reader.new_record? && @email_field
15
+
16
+ - with_error_report(@reader.errors.on(:email)) do
17
+ = f.label @email_field, 'Your email address', :class => 'required'
18
+ %span.formnote this has to work
19
+ %br
20
+ = text_field_tag @email_field, params[@email_field] || @reader.email, :id => "reader_#{@email_field}", :class => 'standard'
21
+
22
+ .innocuous
23
+ - with_error_report(@reader.errors.on(:trap)) do
24
+ %label{ :for => 'reader_email', :class => 'required' }
25
+ Don't fill this in!
26
+ %span.formnote
27
+ it's a spam trap and you weren't supposed to see it
28
+ %br
29
+ = text_field_tag 'reader_email', '', :name => 'reader[email]', :class => 'standard'
30
+
31
+ - else
32
+
33
+ - with_error_report(@reader.errors.on(:email)) do
34
+ = f.label :email, 'Your email address', :class => 'required'
35
+ %br
36
+ = f.text_field :email, :class => 'standard'
37
+
38
+ - with_error_report(@reader.errors.on(:description)) do
39
+ = f.label :description, 'A little about yourself', :class => 'optional'
40
+ %span.formnote
41
+ you can fill this in later.
42
+ Textile formatting
43
+ is allowed.
44
+ %br
45
+ = f.text_area :description, :class => 'standard', :rows => 8
46
+
47
+ - with_error_report(@reader.errors.on(:login)) do
48
+ = f.label :login, 'Login username', :class => 'optional'
49
+ %span.formnote leave blank to use your email address
50
+ %br
51
+ = f.text_field :login, :class => 'standard'
52
+
53
+ - with_error_report(@reader.errors.on(:password)) do
54
+ - label = @reader.new_record? ? 'Password' : 'Change password?'
55
+ - cssclass = @reader.new_record? ? 'required' : 'optional'
56
+ - help = @reader.new_record? ? 'at least four characters, please' : 'leave blank to keep present password. If changing, at least four characters.'
57
+
58
+ = f.label :password, label, :class => cssclass
59
+ %span.formnote
60
+ = help
61
+ %br
62
+ = f.password_field :password, :class => 'standard', :autocomplete => 'off'
63
+
64
+ - with_error_report(@reader.errors.on(:password_confirmation)) do
65
+ = f.label :password_confirmation, "Confirm #{'new ' unless @reader.new_record?}password", :class => @reader.new_record? ? 'required' : 'optional'
66
+ - unless @reader.new_record?
67
+ %span.formnote
68
+ leave blank to keep present password
69
+ %br
70
+ = f.password_field :password_confirmation, :class => 'standard', :autocomplete => 'off'
71
+
72
+ - @form_partials.each do |partial|
73
+ = render :partial => partial
@@ -0,0 +1,28 @@
1
+ = render :partial => 'flasher'
2
+
3
+ %div.reader_show
4
+ - if @reader == current_reader
5
+ %p
6
+ %strong
7
+ Hello
8
+ = @reader.name + '.'
9
+ Thank you for joining us. An email has been sent to
10
+ %strong
11
+ = @reader.email
12
+ with a reminder of your login and password and an activation link.
13
+ Click on that link and the registration process will be complete.
14
+
15
+ %p
16
+ We're sorry about the extra step: it's just to make sure that you are you. If the email hasn't come through yet, you can always go and
17
+ = link_to("give yourself a gravatar", "http://gravatar.com/signup") + '.'
18
+
19
+ - content_for :breadcrumbs do
20
+ = link_to 'Home', '/'
21
+ >
22
+ = link_to 'Readers', '/readers'
23
+ >
24
+ = @reader.name
25
+
26
+ - content_for :pagetitle do
27
+ Thank you. Please check your email
28
+
@@ -0,0 +1,47 @@
1
+ = render :partial => 'flasher'
2
+
3
+ %div.preferences_form
4
+ %p
5
+ Hello
6
+ = link_to "#{@reader.name}.", reader_url(@reader)
7
+ You can use this form to change your preferences and enter a bit more information about yourself.
8
+ First, just to make sure you're you, please enter your current password:
9
+
10
+ - unless @reader.errors.empty?
11
+ %p.errornote
12
+ %strong Sorry: there were problems.
13
+ Please check the form. The affected fields will be highlighted.
14
+
15
+ - form_for :reader, :url => reader_url(@reader), :html => { :method => "put", :class => 'friendly'} do |f|
16
+
17
+ - with_error_report(@reader.errors.on(:current_password)) do
18
+ = f.label :current_password, "Current password", :class => 'required'
19
+ %span.formnote
20
+ can't remember?
21
+ = link_to "Make a new one", new_password_reset_url
22
+ = f.password_field :current_password, :class => 'standard', :autocomplete => 'off'
23
+
24
+ %p
25
+ Fields with bold headings are required and will cause grumbling if left blank:
26
+
27
+ = render :partial => 'form', :locals => {:f => f}
28
+ %p
29
+ = submit_tag "Update your account"
30
+ or
31
+ = link_to 'cancel', request.referer
32
+
33
+ %p
34
+ = link_to gravatar_for(@reader, {:size => 60}, {:class => 'gravatar'}), 'http://www.gravatar.com/signup', :target => '_blank'
35
+ If you would like a picture to appear next to your messages, give yourself a
36
+ = link_to "gravatar.", "http://www.gravatar.com/signup", :target => '_blank'
37
+ This is what appears for you at the moment.
38
+
39
+ - content_for :breadcrumbs do
40
+ = link_to 'Home', '/'
41
+ >
42
+ = link_to 'You', '/readers/me'
43
+ >
44
+ Revise your account
45
+
46
+ - content_for :pagetitle do
47
+ Revise your account
@@ -0,0 +1,16 @@
1
+ = render :partial => 'flasher'
2
+
3
+ %div
4
+ #readers
5
+ - @readers.each do |reader|
6
+ = link_to gravatar_for(reader, {:size => 100}, {:class => 'big_gravatar'}), reader_url(reader), {:title => reader.name}
7
+ %div.stretcher
8
+ %p
9
+
10
+ - content_for :breadcrumbs do
11
+ = link_to 'Home', '/'
12
+ >
13
+ People
14
+
15
+ - content_for :pagetitle do
16
+ People
@@ -0,0 +1,15 @@
1
+ = render :partial => 'readers/flasher'
2
+
3
+ %div.login_form
4
+ %h1
5
+ Log in
6
+
7
+ = render :partial => 'reader_sessions/login_form', :locals => {:backto => @backto}
8
+
9
+ - content_for :breadcrumbs do
10
+ = link_to 'Home', '/'
11
+ > Log in
12
+
13
+ - content_for :pagetitle do
14
+ Log in
15
+
@@ -0,0 +1,41 @@
1
+ = render :partial => 'flasher'
2
+
3
+ %div.register_form
4
+ %p
5
+ If you've already done this, you should only need to
6
+ = link_to "log in.", reader_login_url
7
+ Otherwise, please take a moment to register an account.
8
+ Only the fields labelled in bold are required: the rest you can fill in later if you prefer.
9
+
10
+ - unless @reader.errors.empty?
11
+ %p.errornote
12
+ %strong Sorry: there were problems.
13
+ Please check the form. The affected fields will be highlighted like this.
14
+
15
+ - form_for :reader, :url => readers_url, :html => {:class => 'friendly'} do |f|
16
+ = render :partial => 'form', :locals => {:f => f}
17
+ %p
18
+ = submit_tag "Register"
19
+ or
20
+ = link_to 'cancel', request.referer
21
+
22
+ %h3
23
+ notes
24
+
25
+ %ul.friendly
26
+ %li
27
+ When you press the 'register' button we will send a confirmation email to the address you enter above.
28
+ Click on a link in that message, and you're in.
29
+ %li
30
+ If you would like a picture to appear next to your messages, give yourself a
31
+ = link_to "gravatar.", "http://www.gravatar.com"
32
+ %li
33
+ Please make sure you're happy with our
34
+ = link_to "terms and conditions", "/terms"
35
+
36
+ - content_for :breadcrumbs do
37
+ = link_to 'Home', '/'
38
+ > Register
39
+
40
+ - content_for :pagetitle do
41
+ Register here
@@ -0,0 +1,23 @@
1
+ = render :partial => 'flasher'
2
+
3
+ %div.apologetic
4
+ %p.haserror
5
+ You don't have permission to see the page you just requested.
6
+ - if current_reader
7
+ Please talk to the site administrator about your account.
8
+ - else
9
+ Please log in.
10
+
11
+ - unless current_reader
12
+ = render :partial => 'reader_sessions/login_form'
13
+
14
+ - content_for :breadcrumbs do
15
+ = link_to 'Home', '/'
16
+ >
17
+ = link_to 'Readers', '/readers'
18
+ >
19
+ Permission Denied
20
+
21
+ - content_for :pagetitle do
22
+ = @title
23
+
@@ -0,0 +1,35 @@
1
+ = render :partial => 'flasher'
2
+
3
+ %div.reader_show
4
+ - if @reader == current_reader
5
+ %p.system_message
6
+ %strong
7
+ Hello
8
+ = @reader.name + '.'
9
+ This is the page that other (logged-in) site visitors will see when they click on your name. You can change the text that appears here by
10
+ = link_to "editing your preferences", edit_reader_url(@reader)
11
+ and you can change the picture by
12
+ = link_to "giving yourself a gravatar.", "http://gravatar.com/signup"
13
+
14
+ = gravatar_for(@reader, {:size => 128}, {:class => 'big_gravatar'})
15
+
16
+ - if @reader.description.blank?
17
+ %p No description available.
18
+ - else
19
+ = clean_textilize @reader.description
20
+
21
+ = render :partial => 'contributions'
22
+
23
+ - content_for :breadhead do
24
+ = link_to 'People', '/readers'
25
+
26
+ - content_for :breadcrumbs do
27
+ = link_to 'Home', '/'
28
+ >
29
+ = link_to 'People', '/readers'
30
+ >
31
+ = @reader.name
32
+
33
+ - content_for :pagetitle do
34
+ = @reader.name
35
+
@@ -0,0 +1,5 @@
1
+ %p{ :class => errors ? 'haserror' : '' }
2
+ = yield
3
+ - if errors
4
+ This
5
+ = errors.to_a.to_sentence
data/config/routes.rb ADDED
@@ -0,0 +1,22 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+ map.namespace :admin do |admin|
3
+ admin.resources :readers, :except => [:show]
4
+ end
5
+
6
+ map.namespace :admin, :path_prefix => 'admin/readers' do |admin|
7
+ admin.resources :messages
8
+ admin.resources :reader_settings, :except => [:destroy]
9
+ end
10
+
11
+ map.resources :readers
12
+ map.resource :reader_session
13
+ map.resource :reader_activation, :only => [:show, :new]
14
+ map.resource :password_reset
15
+
16
+ map.repassword '/password_reset/:id/:confirmation_code', :controller => 'password_resets', :action => 'edit'
17
+ map.activate_me '/activate/:id/:activation_code', :controller => 'reader_activations', :action => 'update'
18
+ map.reader_register '/register', :controller => 'readers', :action => 'new'
19
+ map.reader_login '/login', :controller => 'reader_sessions', :action => 'new'
20
+ map.reader_logout '/logout', :controller => 'reader_sessions', :action => 'destroy'
21
+ map.reader_permission_denied '/permission_denied', :controller => 'readers', :action => 'permission_denied'
22
+ end
@@ -0,0 +1,9 @@
1
+ Radiant::Configuration.add do |config|
2
+ config.namespace :reader do |reader|
3
+ reader.setting :allow_registration?, :label => 'Allow visitors to register'
4
+ reader.setting :require_confirmation?, :label => 'Require confirmation of email address'
5
+ reader.setting :layout, :integer, :options => lambda { Layout.all.collect {|l| [ l.id, l.name ] } }, :label => "Layout", :notes => "Radiant layout used to render reader-administration pages"
6
+ reader.setting :mail_from_name, :validate => :present, :label => "Email name", :notes => "Name of person from whom administrative email seems to come"
7
+ reader.setting :mail_from_address, :validate => :present, :label => "Email address", :notes => "Åddress of person from whom administrative email seems to come"
8
+ end
9
+ end
@@ -0,0 +1,31 @@
1
+ class CreateReaders < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :readers, :force => true do |t|
4
+ t.column :site_id, :integer
5
+ t.column :name, :string, :limit => 100
6
+ t.column :email, :string
7
+ t.column :login, :string, :limit => 40, :default => "", :null => false
8
+ t.column :password, :string, :limit => 40
9
+ t.column :description, :text
10
+ t.column :notes, :text
11
+ t.column :trusted, :boolean, :default => true
12
+ t.column :receive_email, :boolean, :default => false
13
+ t.column :receive_essential_email, :boolean, :default => true
14
+ t.column :created_at, :datetime
15
+ t.column :updated_at, :datetime
16
+ t.column :created_by_id, :integer
17
+ t.column :updated_by_id, :integer
18
+ t.column :salt, :string
19
+ t.column :session_token, :string
20
+ t.column :activation_code, :string
21
+ t.column :provisional_password, :string
22
+ t.column :activated_at, :datetime
23
+ # t.column :lock_version, :integer, :default => 0
24
+ end
25
+ add_index :readers, ["session_token"], :name => "session_token"
26
+ end
27
+
28
+ def self.down
29
+ drop_table :readers
30
+ end
31
+ end
@@ -0,0 +1,17 @@
1
+ class ExtendSites < ActiveRecord::Migration
2
+ def self.up
3
+ if defined? Site
4
+ add_column :sites, :reader_layout_id, :integer
5
+ add_column :sites, :mail_from_name, :string
6
+ add_column :sites, :mail_from_address, :string
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ if defined? Site
12
+ remove_column :sites, :reader_layout_id
13
+ remove_column :sites, :mail_from_name
14
+ remove_column :sites, :mail_from_address
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ class ReaderHonorifics < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ add_column :readers, :honorific, :string
5
+ Radiant::Config['reader.use_honorifics?'] = false
6
+ end
7
+
8
+ def self.down
9
+ remove_column :readers, :honorific
10
+ end
11
+
12
+ end
@@ -0,0 +1,11 @@
1
+ class UserReaders < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ add_column :readers, :user_id, :integer
5
+ end
6
+
7
+ def self.down
8
+ remove_column :readers, :user_id
9
+ end
10
+
11
+ end
@@ -0,0 +1,15 @@
1
+ class LastLogin < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ add_column :readers, :last_seen, :datetime
5
+ add_column :readers, :last_login, :datetime
6
+ add_column :readers, :previous_login, :datetime
7
+ end
8
+
9
+ def self.down
10
+ remove_column :readers, :last_seen
11
+ remove_column :readers, :last_login
12
+ remove_column :readers, :previous_login
13
+ end
14
+
15
+ end
@@ -0,0 +1,27 @@
1
+ class AdaptForAuthlogic < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :readers, :persistence_token, :string, :null => false, :default => ""
4
+ add_column :readers, :single_access_token, :string, :null => false, :default => ""
5
+ add_column :readers, :perishable_token, :string, :null => false, :default => ""
6
+ add_column :readers, :login_count, :integer, :null => false, :default => 0
7
+ add_column :readers, :failed_login_count, :integer, :null => false, :default => 0
8
+ add_column :readers, :current_login_ip, :string
9
+ add_column :readers, :last_login_ip, :string
10
+ add_column :readers, :clear_password, :string
11
+
12
+ change_column :readers, :password, :string, :limit => 255
13
+ change_column :readers, :salt, :string, :limit => 255
14
+
15
+ rename_column :readers, :password, :crypted_password
16
+ rename_column :readers, :salt, :password_salt
17
+ rename_column :readers, :last_seen, :last_request_at
18
+ rename_column :readers, :last_login, :last_login_at
19
+
20
+ remove_column :readers, :activation_code
21
+ remove_column :readers, :previous_login
22
+ end
23
+
24
+ def self.down
25
+
26
+ end
27
+ end