muck-users 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +27 -0
- data/Rakefile +96 -0
- data/VERSION +1 -0
- data/app/controllers/admin/muck/roles_controller.rb +57 -0
- data/app/controllers/admin/muck/users_controller.rb +122 -0
- data/app/controllers/muck/activations_controller.rb +31 -0
- data/app/controllers/muck/password_resets_controller.rb +81 -0
- data/app/controllers/muck/user_sessions_controller.rb +40 -0
- data/app/controllers/muck/username_request_controller.rb +43 -0
- data/app/controllers/muck/users_controller.rb +211 -0
- data/app/models/muck_user_mailer.rb +53 -0
- data/app/models/permission.rb +17 -0
- data/app/models/role.rb +25 -0
- data/app/views/admin/roles/_role.html.erb +9 -0
- data/app/views/admin/roles/edit.html.erb +17 -0
- data/app/views/admin/roles/index.html.erb +8 -0
- data/app/views/admin/roles/new.html.erb +16 -0
- data/app/views/admin/roles/show.html.erb +7 -0
- data/app/views/admin/users/_activate.html.erb +5 -0
- data/app/views/admin/users/_ajax_search_box.html.erb +6 -0
- data/app/views/admin/users/_row.html.erb +6 -0
- data/app/views/admin/users/_search_box.html.erb +6 -0
- data/app/views/admin/users/_table.html.erb +21 -0
- data/app/views/admin/users/_user_navigation.html.erb +11 -0
- data/app/views/admin/users/do_search.html.erb +5 -0
- data/app/views/admin/users/inactive.html.erb +8 -0
- data/app/views/admin/users/inactive_emails.html.erb +6 -0
- data/app/views/admin/users/index.html.erb +12 -0
- data/app/views/admin/users/search.html.erb +5 -0
- data/app/views/muck_user_mailer/activation_confirmation.html.erb +7 -0
- data/app/views/muck_user_mailer/activation_instructions.html.erb +7 -0
- data/app/views/muck_user_mailer/password_not_active_instructions.html.erb +10 -0
- data/app/views/muck_user_mailer/password_reset_instructions.html.erb +10 -0
- data/app/views/muck_user_mailer/username_request.html.erb +3 -0
- data/app/views/muck_user_mailer/welcome_notification.html.erb +5 -0
- data/app/views/password_resets/edit.html.erb +9 -0
- data/app/views/password_resets/new.html.erb +11 -0
- data/app/views/user_sessions/new.html.erb +17 -0
- data/app/views/username_request/new.html.erb +11 -0
- data/app/views/users/_user.html.erb +15 -0
- data/app/views/users/activation_confirmation.html.erb +1 -0
- data/app/views/users/activation_instructions.html.erb +1 -0
- data/app/views/users/edit.html.erb +45 -0
- data/app/views/users/new.html.erb +51 -0
- data/app/views/users/show.html.erb +4 -0
- data/app/views/users/welcome.html.erb +4 -0
- data/config/muck_users_routes.rb +56 -0
- data/db/migrate/20090320174818_create_muck_permissions_and_roles.rb +16 -0
- data/db/migrate/20090512013727_add_photo_to_user.rb +13 -0
- data/install.rb +1 -0
- data/lib/action_controller/authentic_application.rb +213 -0
- data/lib/active_record/acts/muck_user.rb +192 -0
- data/lib/muck-users/exceptions.rb +5 -0
- data/lib/muck-users/initialize_routes.rb +8 -0
- data/lib/muck-users/tasks.rb +46 -0
- data/lib/muck-users.rb +7 -0
- data/locales/ar.yml +124 -0
- data/locales/bg.yml +124 -0
- data/locales/ca.yml +124 -0
- data/locales/cs.yml +124 -0
- data/locales/da.yml +124 -0
- data/locales/de.yml +124 -0
- data/locales/el.yml +124 -0
- data/locales/en.yml +127 -0
- data/locales/es.yml +124 -0
- data/locales/fr.yml +124 -0
- data/locales/it.yml +124 -0
- data/locales/iw.yml +124 -0
- data/locales/ja.yml +124 -0
- data/locales/ko.yml +124 -0
- data/locales/lt.yml +124 -0
- data/locales/lv.yml +124 -0
- data/locales/nl.yml +124 -0
- data/locales/no.yml +125 -0
- data/locales/pl.yml +124 -0
- data/locales/pt.yml +124 -0
- data/locales/ro.yml +124 -0
- data/locales/ru.yml +124 -0
- data/locales/sk.yml +124 -0
- data/locales/sl.yml +124 -0
- data/locales/sr.yml +124 -0
- data/locales/sv.yml +124 -0
- data/locales/tl.yml +124 -0
- data/locales/uk.yml +124 -0
- data/locales/vi.yml +124 -0
- data/locales/zh-CN.yml +124 -0
- data/locales/zh-TW.yml +124 -0
- data/locales/zh.yml +124 -0
- data/muck-users.gemspec +170 -0
- data/pkg/muck-users-0.1.0.gem +0 -0
- data/public/images/profile_default.jpg +0 -0
- data/rails/init.rb +18 -0
- data/tasks/muck_users_engine.rake +27 -0
- data/tasks/rails.rake +2 -0
- data/test/factories.rb +56 -0
- data/test/functional/activations_controller_test.rb +73 -0
- data/test/functional/admin/roles_controller_test.rb +10 -0
- data/test/functional/admin/users_controller_test.rb +55 -0
- data/test/functional/password_resets_controller_test.rb +60 -0
- data/test/functional/user_sessions_controller_test.rb +62 -0
- data/test/functional/users_controller_test.rb +255 -0
- data/test/shoulda_macros/controller.rb +43 -0
- data/test/shoulda_macros/forms.rb +28 -0
- data/test/shoulda_macros/models.rb +34 -0
- data/test/shoulda_macros/pagination.rb +48 -0
- data/test/shoulda_macros/plugins.rb +30 -0
- data/test/test_helper.rb +36 -0
- data/test/unit/muck_user_mailer_test.rb +64 -0
- data/test/unit/permission_test.rb +19 -0
- data/test/unit/role_test.rb +17 -0
- data/uninstall.rb +1 -0
- metadata +198 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
<div id="edit-user" class="common-form">
|
2
|
+
<h1><%= t('muck.users.update_user') %></h1>
|
3
|
+
|
4
|
+
<% custom_form_for @user, :url => user_path(@user), :html => {:id => "edit-user-form", :name => 'edit-user-form', :method => :put, :multipart => true } do |f| -%>
|
5
|
+
|
6
|
+
<%= output_errors(t('muck.users.problem_editing_account'), {:class => 'help-box'}, @user) %>
|
7
|
+
|
8
|
+
<%= f.text_field :email, { :label => t('muck.users.email_address'),
|
9
|
+
:tip => t('muck.users.email_help') } -%>
|
10
|
+
<%= f.text_field :first_name, { :label => t('muck.users.first_name') } %>
|
11
|
+
<%= f.text_field :last_name, { :label => t('muck.users.last_name') } %>
|
12
|
+
<%= image_tag @user.photo.url(:thumb) %>
|
13
|
+
<%= f.file_field :photo, { :label => t('muck.users.upload_photo') } %>
|
14
|
+
<div class="button form-row">
|
15
|
+
<%= f.submit t('muck.general.save') %>
|
16
|
+
</div>
|
17
|
+
<%= hidden_field_tag :redirect_to, edit_user_path(@user) %>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<div id="change-password" class="common-form">
|
23
|
+
<h2><%= t('muck.users.change_password') %></h2>
|
24
|
+
<% custom_form_for @user, :url => user_path(@user), :html => { :id => "change-password-form", :name => 'change-password-form', :method => :put } do |f| %>
|
25
|
+
<%= f.password_field :password, { :label => t('muck.users.password'),
|
26
|
+
:tip => t('muck.users.password_help')} -%>
|
27
|
+
<%= f.password_field :password_confirmation, { :label => t('muck.users.confirm_password'),
|
28
|
+
:tip => t('muck.users.password_confirmation_help') } -%>
|
29
|
+
<div class="button form-row">
|
30
|
+
<%= submit_tag t('muck.users.change_password'), :class => 'button' %>
|
31
|
+
</div>
|
32
|
+
<%= hidden_field_tag :redirect_to, edit_user_path(@user) %>
|
33
|
+
<% end -%>
|
34
|
+
</div>
|
35
|
+
|
36
|
+
<% if GlobalConfig.let_users_delete_their_account -%>
|
37
|
+
<div id="delete-account" class="common-form">
|
38
|
+
<% custom_form_for :user, :url => users_path, :html => {:id => "delete-user-form", :name => 'delete-user-form', :method => :delete, :confirm => t("users.confirm_delete_account")} do |f| -%>
|
39
|
+
<h2><%= t('muck.users.remove_my_account') %></h2>
|
40
|
+
<div class="button form-row">
|
41
|
+
<%= f.submit t('muck.general.delete_my_account') %>
|
42
|
+
</div>
|
43
|
+
<% end -%>
|
44
|
+
</div>
|
45
|
+
<% end -%>
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<div id="registration" class="common-form">
|
2
|
+
<h1><%= t('muck.users.register_account', :application_name => GlobalConfig.application_name) %></h1>
|
3
|
+
<p><%= t('muck.users.already_registered') %> <a href="<%=login_url%>"><%= t('muck.users.sign_in_now') %></a></p>
|
4
|
+
|
5
|
+
<% custom_form_for :user, :url => users_path, :html => {:id => "register-user-form", :name => 'register-user-form'} do |f| -%>
|
6
|
+
|
7
|
+
<%= output_errors(t('muck.users.problem_creating_account'), {:class => 'help-box'}, @user) %>
|
8
|
+
|
9
|
+
<%= f.text_field :login, { :label => t('muck.users.choose_member_name'),
|
10
|
+
:extra_html => '<span id="username-availibility" class="availability"></span>',
|
11
|
+
:tip => t('muck.users.username_help'),
|
12
|
+
:required_label => t('muck.users.username') } -%>
|
13
|
+
<%= f.text_field :email, { :label => t('muck.users.email_address'),
|
14
|
+
:tip => t('muck.users.email_help'),
|
15
|
+
:extra_html => '<span id="email-availibility" class="availability"></span>' } -%>
|
16
|
+
<%= f.password_field :password, { :label => t('muck.users.password'),
|
17
|
+
:tip => t('muck.users.password_help')} -%>
|
18
|
+
<%= f.password_field :password_confirmation, { :label => t('muck.users.confirm_password'),
|
19
|
+
:tip => t('muck.users.password_confirmation_help') } -%>
|
20
|
+
<%= f.file_field :photo, { :label => t('muck.users.upload_photo') } %>
|
21
|
+
<% if GlobalConfig.use_recaptcha -%>
|
22
|
+
<div class="recaptcha">
|
23
|
+
<%= recaptcha_tags %>
|
24
|
+
</div>
|
25
|
+
<% end -%>
|
26
|
+
|
27
|
+
<div class="button form-row">
|
28
|
+
<%= f.submit t('muck.users.sign_up_now') %>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<% end %>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
<% content_for :javascript do -%>
|
35
|
+
jQuery("#user_login").blur(function(){
|
36
|
+
jQuery.post("is_login_available",{ user_login:jQuery(this).val() } ,function(data){
|
37
|
+
jQuery("#username-availibility").html(data);
|
38
|
+
});
|
39
|
+
});
|
40
|
+
jQuery("#user_login").keydown(function() {
|
41
|
+
jQuery("#username-availibility").html('');
|
42
|
+
});
|
43
|
+
jQuery("#user_email").blur(function(){
|
44
|
+
jQuery.post("is_email_available",{ user_email:jQuery(this).val() } ,function(data){
|
45
|
+
jQuery("#email-availibility").html(data);
|
46
|
+
});
|
47
|
+
});
|
48
|
+
jQuery("#user_email").keydown(function() {
|
49
|
+
jQuery("#email-availibility").html('');
|
50
|
+
});
|
51
|
+
<% end -%>
|
@@ -0,0 +1,56 @@
|
|
1
|
+
ActionController::Routing::Routes.draw do |map|
|
2
|
+
|
3
|
+
# users
|
4
|
+
map.resources :users, :controller => 'muck/users',
|
5
|
+
:member => { :enable => :put, :welcome => :get, :activation_instructions => :get },
|
6
|
+
:collection => { :is_login_available => :post, :is_email_available => :post }
|
7
|
+
|
8
|
+
map.with_options(:controller => 'muck/users') do |users|
|
9
|
+
users.signup "/signup", :action => 'new'
|
10
|
+
users.signup_complete "/users/signup_complete/:id", :action => 'welcome'
|
11
|
+
users.activation_complete "/users/activation_complete/:id", :action => 'welcome'
|
12
|
+
users.signup_complete_activation_required '/signup_complete_activate/:id', :action => 'activation_instructions'
|
13
|
+
users.is_login_available '/is_login_available', :action => 'is_login_available'
|
14
|
+
users.is_email_available '/is_email_available', :action => 'is_email_available'
|
15
|
+
users.account "account", :action => 'show'
|
16
|
+
end
|
17
|
+
|
18
|
+
# activations
|
19
|
+
map.resources :activations, :controller => 'muck/activations'
|
20
|
+
map.with_options(:controller => 'muck/activations') do |activations|
|
21
|
+
activations.activate '/activate/:activation_code', :action => 'new'
|
22
|
+
end
|
23
|
+
|
24
|
+
# passwords
|
25
|
+
map.resource :password_resets, :controller => 'muck/password_resets'
|
26
|
+
|
27
|
+
map.with_options(:controller => 'muck/password_resets') do |password_resets|
|
28
|
+
password_resets.forgot_password "/forgot_password", :action => 'new'
|
29
|
+
password_resets.reset_password "/reset_password/:id", :action => 'edit'
|
30
|
+
end
|
31
|
+
|
32
|
+
# username
|
33
|
+
map.resource :username_request, :controller => 'muck/username_request'
|
34
|
+
|
35
|
+
map.with_options(:controller => 'muck/username_request') do |username_request|
|
36
|
+
username_request.forgot_username "/forgot_username", :action => 'new'
|
37
|
+
end
|
38
|
+
|
39
|
+
# sessions
|
40
|
+
map.resource :user_session, :controller => 'muck/user_sessions'
|
41
|
+
map.with_options(:controller => 'muck/user_sessions') do |user_sessions|
|
42
|
+
user_sessions.login "/login", :action => 'new'
|
43
|
+
user_sessions.logout "/logout", :action => 'destroy'
|
44
|
+
user_sessions.signup_complete_login_required '/signup_complete_login/:id', :action => 'new'
|
45
|
+
end
|
46
|
+
|
47
|
+
# admin
|
48
|
+
map.namespace :admin do |a|
|
49
|
+
a.resources :users, :controller => 'muck/users', :collection => { :inactive => :get, :inactive_emails => :get, :activate_all => :get, :search => :post, :ajax_search => :post }
|
50
|
+
a.resources :roles, :controller => 'muck/roles'
|
51
|
+
a.resources :permissions, :controller => 'muck/permissions'
|
52
|
+
end
|
53
|
+
|
54
|
+
# public (replace with something more useful in your application)
|
55
|
+
map.public_user '/profiles/:id', :controller => 'default', :action => 'index'
|
56
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateMuckPermissionsAndRoles < ActiveRecord::Migration
|
2
|
+
|
3
|
+
create_table "permissions", :force => true do |t|
|
4
|
+
t.integer "role_id", :null => false
|
5
|
+
t.integer "user_id", :null => false
|
6
|
+
t.datetime "created_at"
|
7
|
+
t.datetime "updated_at"
|
8
|
+
end
|
9
|
+
|
10
|
+
create_table "roles", :force => true do |t|
|
11
|
+
t.string "rolename"
|
12
|
+
t.datetime "created_at"
|
13
|
+
t.datetime "updated_at"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class AddPhotoToUser < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :users, :photo_file_name, :string
|
4
|
+
add_column :users, :photo_content_type, :string
|
5
|
+
add_column :users, :photo_file_size, :integer
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.down
|
9
|
+
remove_column :users, :photo_file_name
|
10
|
+
remove_column :users, :photo_content_type
|
11
|
+
remove_column :users, :photo_file_size
|
12
|
+
end
|
13
|
+
end
|
data/install.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Install hook code here
|
@@ -0,0 +1,213 @@
|
|
1
|
+
module ActionController
|
2
|
+
|
3
|
+
module AuthenticApplication
|
4
|
+
|
5
|
+
# Module automatically mixed into the all controllers
|
6
|
+
def self.included(base)
|
7
|
+
base.class_eval do
|
8
|
+
include InstanceMethods
|
9
|
+
end
|
10
|
+
# Inclusion hook to make #current_user and #logged_in?, etc available as ActionView helper methods.
|
11
|
+
base.send :helper_method, :current_user_session, :current_user, :logged_in?, :admin?, :is_me?, :is_owner?
|
12
|
+
base.send :filter_parameter_logging, :password, :password_confirmation
|
13
|
+
end
|
14
|
+
|
15
|
+
module InstanceMethods
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
# Returns true or false if the user is logged in.
|
20
|
+
def logged_in?
|
21
|
+
!current_user.blank?
|
22
|
+
end
|
23
|
+
|
24
|
+
def current_user_session
|
25
|
+
return @current_user_session if defined?(@current_user_session)
|
26
|
+
@current_user_session = UserSession.find
|
27
|
+
end
|
28
|
+
|
29
|
+
def current_user
|
30
|
+
return @current_user if defined?(@current_user)
|
31
|
+
@current_user = current_user_session && current_user_session.record
|
32
|
+
end
|
33
|
+
|
34
|
+
def login_required
|
35
|
+
unless logged_in?
|
36
|
+
store_location
|
37
|
+
flash[:notice] = I18n.t('muck.users.login_requred')
|
38
|
+
access_denied
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def not_logged_in_required
|
43
|
+
if logged_in?
|
44
|
+
store_location
|
45
|
+
flash[:notice] = t('muck.users.logout_required')
|
46
|
+
enforce_logout_required
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def check_role(role)
|
51
|
+
unless logged_in? && current_user.has_role?(role)
|
52
|
+
if logged_in?
|
53
|
+
permission_denied
|
54
|
+
else
|
55
|
+
store_referer
|
56
|
+
access_denied
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def admin?
|
62
|
+
logged_in? && current_user.admin?
|
63
|
+
end
|
64
|
+
|
65
|
+
# check to see if the current user is the owner of the specified object
|
66
|
+
def is_owner?(obj)
|
67
|
+
obj.user_id == current_user.id
|
68
|
+
end
|
69
|
+
|
70
|
+
def is_owner?(user, user_id)
|
71
|
+
user.id == user_id
|
72
|
+
end
|
73
|
+
|
74
|
+
# check to see if the given user is the same as the current user
|
75
|
+
def is_me?(user)
|
76
|
+
user == current_user
|
77
|
+
end
|
78
|
+
|
79
|
+
# checks permissions on an object. Redirects if the current user
|
80
|
+
# doesn't own it or have admin rights
|
81
|
+
def protect_owner(obj)
|
82
|
+
if is_owner?(obj) || admin?
|
83
|
+
true
|
84
|
+
else
|
85
|
+
permission_denied
|
86
|
+
false
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# allow or deny access depending on options specified
|
91
|
+
def allowed_access?(options)
|
92
|
+
if !options[:owner].nil? && !options[:object_user_id].nil?
|
93
|
+
return true if is_owner?(options[:owner], options[:object_user_id])
|
94
|
+
end
|
95
|
+
|
96
|
+
options[:permit_roles].each do |role|
|
97
|
+
return true if current_user.has_role?(role)
|
98
|
+
end
|
99
|
+
|
100
|
+
# access denied
|
101
|
+
permission_denied
|
102
|
+
false
|
103
|
+
end
|
104
|
+
|
105
|
+
def can_access?(user, object, roles, &block)
|
106
|
+
if logged_in? && user.is_in_role?(event, roles)
|
107
|
+
content = capture(&block)
|
108
|
+
concat(content, block.binding)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def is_mine?(user, &block)
|
113
|
+
if logged_in? && (current_user.id == user.id)
|
114
|
+
content = capture(&block)
|
115
|
+
concat(content, block.binding)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Redirect as appropriate when an access request fails.
|
120
|
+
#
|
121
|
+
# The default action is to redirect to the login screen.
|
122
|
+
#
|
123
|
+
# Override this method in your controllers if you want to have special
|
124
|
+
# behavior in case the user is not authorized
|
125
|
+
# to access the requested action. For example, a popup window might
|
126
|
+
# simply close itself.
|
127
|
+
def access_denied
|
128
|
+
respond_to do |format|
|
129
|
+
format.html do
|
130
|
+
store_location
|
131
|
+
flash[:error] = I18n.t('muck.users.access_denied')
|
132
|
+
redirect_to login_path
|
133
|
+
end
|
134
|
+
format.xml do
|
135
|
+
request_http_basic_authentication 'Web Password'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def permission_denied
|
141
|
+
respond_to do |format|
|
142
|
+
format.html do
|
143
|
+
#Put your domain name here ex. http://www.example.com
|
144
|
+
domain_name = GlobalConfig.application_base_url
|
145
|
+
http_referer = session[:refer_to]
|
146
|
+
if http_referer.nil?
|
147
|
+
store_referer
|
148
|
+
http_referer = ( session[:refer_to] || domain_name )
|
149
|
+
end
|
150
|
+
flash[:error] = I18n.t('muck.users.permission_denied')
|
151
|
+
#The [0..20] represents the 21 characters in http://localhost:3000
|
152
|
+
#You have to set that to the number of characters in your domain name
|
153
|
+
if http_referer[0..domain_name.length] != domain_name
|
154
|
+
session[:refer_to] = nil
|
155
|
+
redirect_to root_path
|
156
|
+
else
|
157
|
+
redirect_to_referer_or_default(root_path)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
format.xml do
|
161
|
+
headers["Status"] = "Unauthorized"
|
162
|
+
headers["WWW-Authenticate"] = %(Basic realm="Web Password")
|
163
|
+
render :text => I18n.t('muck.users.permission_denied'), :status => '401 Unauthorized'
|
164
|
+
end
|
165
|
+
format.js do
|
166
|
+
render :text => I18n.t('muck.users.permission_denied')
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def enforce_logout_required
|
172
|
+
respond_to do |format|
|
173
|
+
format.html do
|
174
|
+
redirect_to current_user
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Store the URI of the current request in the session.
|
180
|
+
# We can return to this location by calling #redirect_back_or_default.
|
181
|
+
# Only store html requests so we don't redirect a user back to and rss or xml feed
|
182
|
+
def store_location
|
183
|
+
if request.format == :html
|
184
|
+
session[:return_to] = request.request_uri
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def store_referer
|
189
|
+
session[:refer_to] = request.env["HTTP_REFERER"]
|
190
|
+
end
|
191
|
+
|
192
|
+
# Redirect to the URI stored by the most recent store_location call or
|
193
|
+
# to the passed default.
|
194
|
+
def redirect_back_or_default(default)
|
195
|
+
redirect_to(session[:return_to] || default)
|
196
|
+
session[:return_to] = nil
|
197
|
+
end
|
198
|
+
|
199
|
+
def redirect_to_referer_or_default(default)
|
200
|
+
redirect_to(session[:refer_to] || default)
|
201
|
+
session[:refer_to] = nil
|
202
|
+
end
|
203
|
+
|
204
|
+
# Called from #current_user. Now, attempt to login by basic authentication information.
|
205
|
+
# def login_from_basic_auth
|
206
|
+
# authenticate_with_http_basic do |username, password|
|
207
|
+
# self.current_user = User.authenticate(username, password)
|
208
|
+
# end
|
209
|
+
# end
|
210
|
+
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Acts #:nodoc:
|
3
|
+
module MuckUser #:nodoc:
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
|
10
|
+
def acts_as_muck_user(options = {})
|
11
|
+
|
12
|
+
has_many :permissions
|
13
|
+
has_many :roles, :through => :permissions
|
14
|
+
|
15
|
+
named_scope :by_newest, :order => "created_at DESC"
|
16
|
+
named_scope :active, :conditions => "activated_at IS NOT NULL"
|
17
|
+
named_scope :inactive, :conditions => "activated_at IS NULL"
|
18
|
+
named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }
|
19
|
+
|
20
|
+
email_name_regex = '[\w\.%\+\-]+'.freeze
|
21
|
+
domain_head_regex = '(?:[A-Z0-9\-]+\.)+'.freeze
|
22
|
+
domain_tld_regex = '(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|jobs|museum)'.freeze
|
23
|
+
email_regex = /\A#{email_name_regex}@#{domain_head_regex}#{domain_tld_regex}\z/i
|
24
|
+
|
25
|
+
has_attached_file :photo,
|
26
|
+
:styles => { :medium => "300x300>",
|
27
|
+
:thumb => "100x100>",
|
28
|
+
:icon => "50x50>" },
|
29
|
+
:default_url => "/images/profile_default.jpg"
|
30
|
+
|
31
|
+
class_eval <<-EOV
|
32
|
+
validates_format_of :login, :with => /^[a-z0-9-]+$/i, :message => 'may only contain letters, numbers or a hyphen.'
|
33
|
+
validates_format_of :email, :with => email_regex, :message => 'does not look like a valid email address.'
|
34
|
+
|
35
|
+
# prevents a user from submitting a crafted form that bypasses activation
|
36
|
+
attr_protected :crypted_password, :password_salt, :persistence_token, :single_access_token, :perishable_token, :login_count,
|
37
|
+
:failed_login_count, :last_request_at, :last_login_at, :current_login_at, :current_login_ip, :last_login_ip,
|
38
|
+
:terms_of_service, :time_zone, :disabled_at, :activated_at, :created_at, :updated_at, :photo_file_name,
|
39
|
+
:photo_content_type, :photo_file_size
|
40
|
+
EOV
|
41
|
+
|
42
|
+
include ActiveRecord::Acts::MuckUser::InstanceMethods
|
43
|
+
extend ActiveRecord::Acts::MuckUser::SingletonMethods
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# class methods
|
49
|
+
module SingletonMethods
|
50
|
+
def do_search( query )
|
51
|
+
User.find(:all, :conditions => [ "email LIKE ? OR first_name LIKE ? OR last_name LIKE ?", '%' + query + '%', '%' + query + '%', '%' + query + '%' ])
|
52
|
+
end
|
53
|
+
|
54
|
+
def inactive_count
|
55
|
+
User.count :conditions => "activated_at is null"
|
56
|
+
end
|
57
|
+
|
58
|
+
def activate_all
|
59
|
+
User.update_all("activated_at = '#{Time.now}'", 'activated_at IS NULL')
|
60
|
+
end
|
61
|
+
|
62
|
+
# Finds the user with the corresponding activation code, activates their account and returns the user.
|
63
|
+
#
|
64
|
+
# Raises:
|
65
|
+
# +User::ActivationCodeNotFound+ if there is no user with the corresponding activation code
|
66
|
+
# +User::AlreadyActivated+ if the user with the corresponding activation code has already activated their account
|
67
|
+
def find_and_activate!(activation_code)
|
68
|
+
raise ArgumentError if activation_code.nil?
|
69
|
+
user = find_by_activation_code(activation_code)
|
70
|
+
raise ActivationCodeNotFound if !user
|
71
|
+
raise AlreadyActivated.new(user) if user.active?
|
72
|
+
user.send(:activate!)
|
73
|
+
user
|
74
|
+
end
|
75
|
+
|
76
|
+
# checks to see if a given login is already in the database
|
77
|
+
def login_exists?(login)
|
78
|
+
if User.find_by_login(login).nil?
|
79
|
+
false
|
80
|
+
else
|
81
|
+
true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# checks to see if a given email is already in the database
|
86
|
+
def email_exists?(email)
|
87
|
+
if User.find_by_email(email).nil?
|
88
|
+
false
|
89
|
+
else
|
90
|
+
true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
# All the methods available to a record that has had <tt>acts_as_muck_user</tt> specified.
|
97
|
+
module InstanceMethods
|
98
|
+
|
99
|
+
def deliver_welcome_email
|
100
|
+
MuckUserMailer.deliver_welcome_notification(self) if GlobalConfig.send_welcome
|
101
|
+
end
|
102
|
+
|
103
|
+
def deliver_activation_confirmation!
|
104
|
+
reset_perishable_token!
|
105
|
+
MuckUserMailer.deliver_activation_confirmation(self)
|
106
|
+
end
|
107
|
+
|
108
|
+
def deliver_activation_instructions!
|
109
|
+
reset_perishable_token!
|
110
|
+
MuckUserMailer.deliver_activation_instructions(self)
|
111
|
+
end
|
112
|
+
|
113
|
+
def deliver_password_reset_instructions!
|
114
|
+
if self.active?
|
115
|
+
reset_perishable_token!
|
116
|
+
MuckUserMailer.deliver_password_reset_instructions(self)
|
117
|
+
else
|
118
|
+
MuckUserMailer.deliver_password_not_active_instructions(self)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def deliver_username_request!
|
123
|
+
MuckUserMailer.deliver_username_request(self)
|
124
|
+
end
|
125
|
+
|
126
|
+
|
127
|
+
# Since password reset doesn't need to change openid_identifier,
|
128
|
+
# we save without block as usual.
|
129
|
+
def reset_password!(user)
|
130
|
+
self.password = user[:password]
|
131
|
+
self.password_confirmation = user[:password_confirmation]
|
132
|
+
save
|
133
|
+
end
|
134
|
+
|
135
|
+
def has_role?(rolename)
|
136
|
+
@roles ||= self.roles.map{|role| role.rolename}
|
137
|
+
return false unless @roles
|
138
|
+
@roles.include?(rolename)
|
139
|
+
end
|
140
|
+
|
141
|
+
def admin?
|
142
|
+
has_role?('administrator')
|
143
|
+
end
|
144
|
+
|
145
|
+
def can_edit?(user)
|
146
|
+
return false if user.nil?
|
147
|
+
self.id == user.id || user.admin?
|
148
|
+
end
|
149
|
+
|
150
|
+
def to_xml(options = {})
|
151
|
+
options[:except] ||= []
|
152
|
+
options[:except] << :email << :crypted_password << :salt << :remember_token << :remember_token_expires_at << :activation_code
|
153
|
+
options[:except] << :activated_at << :password_reset_code << :enabled << :terms_of_service << :can_send_messages << :identity_url
|
154
|
+
options[:except] << :tmp_password << :protected_profile << :public_profile
|
155
|
+
super
|
156
|
+
end
|
157
|
+
|
158
|
+
# Authlogic automatically executes the following methods
|
159
|
+
def active?
|
160
|
+
!activated_at.blank?
|
161
|
+
end
|
162
|
+
|
163
|
+
# def approved?
|
164
|
+
# end
|
165
|
+
#
|
166
|
+
# def confirmed?
|
167
|
+
# end
|
168
|
+
|
169
|
+
def activate!
|
170
|
+
self.update_attribute(:activated_at, Time.now.utc)
|
171
|
+
end
|
172
|
+
|
173
|
+
def short_name
|
174
|
+
CGI::escapeHTML(self.first_name) || self.display_name
|
175
|
+
end
|
176
|
+
|
177
|
+
def full_name
|
178
|
+
if self.first_name.blank? && self.last_name.blank?
|
179
|
+
self.display_name rescue 'Deleted user'
|
180
|
+
else
|
181
|
+
((CGI::escapeHTML(self.first_name) || '') + ' ' + (CGI::escapeHTML(self.last_name) || '')).strip
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def display_name
|
186
|
+
CGI::escapeHTML(self.login)
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class ActionController::Routing::RouteSet
|
2
|
+
def load_routes_with_muck_users!
|
3
|
+
muck_users_routes = File.join(File.dirname(__FILE__), *%w[.. .. config muck_users_routes.rb])
|
4
|
+
add_configuration_file(muck_users_routes) unless configuration_files.include? muck_users_routes
|
5
|
+
load_routes_without_muck_users!
|
6
|
+
end
|
7
|
+
alias_method_chain :load_routes!, :muck_users
|
8
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Disguise
|
6
|
+
class Tasks < ::Rake::TaskLib
|
7
|
+
def initialize
|
8
|
+
define
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def define
|
13
|
+
|
14
|
+
namespace :muck do
|
15
|
+
namespace :users do
|
16
|
+
desc "Sync files from muck users."
|
17
|
+
task :sync do
|
18
|
+
path = File.join(File.dirname(__FILE__), *%w[.. ..])
|
19
|
+
system "rsync -ruv #{path}/db ."
|
20
|
+
system "rsync -ruv #{path}/public ."
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Setup default admin user"
|
24
|
+
task :create_admin => :environment do
|
25
|
+
['administrator'].each {|r| Role.create(:rolename => r) }
|
26
|
+
user = User.new
|
27
|
+
user.login = "admin"
|
28
|
+
user.email = GlobalConfig.admin_email
|
29
|
+
user.password = "asdfasdf"
|
30
|
+
user.password_confirmation = "asdfasdf"
|
31
|
+
user.first_name = "Administrator"
|
32
|
+
user.last_name = "Administrator"
|
33
|
+
user.save
|
34
|
+
user.activate!
|
35
|
+
|
36
|
+
user.roles << Role.find_by_rolename('administrator')
|
37
|
+
|
38
|
+
puts 'created admin user'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
Disguise::Tasks.new
|
data/lib/muck-users.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
require 'muck-users/exceptions'
|
2
|
+
|
3
|
+
ActionController::Base.send :include, ActionController::AuthenticApplication
|
4
|
+
ActiveRecord::Base.class_eval { include ActiveRecord::Acts::MuckUser }
|
5
|
+
ActiveRecord::Base.class_eval { include MuckUsersEngine::Exceptions }
|
6
|
+
|
7
|
+
I18n.load_path += Dir[ File.join(File.dirname(__FILE__), '..', 'locales', '*.{rb,yml}') ]
|