muck-users 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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}') ]
|