usman 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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +38 -0
- data/Rakefile +37 -0
- data/app/assets/config/usman_manifest.js +2 -0
- data/app/assets/javascripts/usman/application.js +13 -0
- data/app/assets/stylesheets/usman/application.css +15 -0
- data/app/controllers/usman/admin/base_controller.rb +24 -0
- data/app/controllers/usman/admin/dashboard_controller.rb +18 -0
- data/app/controllers/usman/admin/features_controller.rb +86 -0
- data/app/controllers/usman/admin/permissions_controller.rb +76 -0
- data/app/controllers/usman/admin/resource_controller.rb +11 -0
- data/app/controllers/usman/admin/users_controller.rb +117 -0
- data/app/controllers/usman/application_controller.rb +13 -0
- data/app/controllers/usman/sessions_controller.rb +84 -0
- data/app/helpers/usman/application_helper.rb +4 -0
- data/app/helpers/usman/authentication_helper.rb +120 -0
- data/app/jobs/usman/application_job.rb +4 -0
- data/app/mailers/usman/application_mailer.rb +6 -0
- data/app/models/feature.rb +112 -0
- data/app/models/image/base.rb +30 -0
- data/app/models/image/feature_image.rb +3 -0
- data/app/models/image/profile_picture.rb +3 -0
- data/app/models/permission.rb +28 -0
- data/app/models/user.rb +247 -0
- data/app/models/usman/application_record.rb +5 -0
- data/app/services/usman/authentication_service.rb +45 -0
- data/app/uploaders/feature_image_uploader.rb +14 -0
- data/app/uploaders/image_uploader.rb +90 -0
- data/app/uploaders/profile_picture_uploader.rb +14 -0
- data/app/views/layouts/kuppayam/_footer.html.erb +25 -0
- data/app/views/layouts/kuppayam/_header.html.erb +43 -0
- data/app/views/layouts/kuppayam/_navbar.html.erb +55 -0
- data/app/views/layouts/kuppayam/_sidebar.html.erb +78 -0
- data/app/views/usman/admin/dashboard/index.html.erb +52 -0
- data/app/views/usman/admin/features/_action_buttons.html.erb +11 -0
- data/app/views/usman/admin/features/_form.html.erb +19 -0
- data/app/views/usman/admin/features/_index.html.erb +79 -0
- data/app/views/usman/admin/features/_row.html.erb +55 -0
- data/app/views/usman/admin/features/_show.html.erb +48 -0
- data/app/views/usman/admin/features/create.js.erb +16 -0
- data/app/views/usman/admin/features/destroy.js.erb +16 -0
- data/app/views/usman/admin/features/edit.js.erb +7 -0
- data/app/views/usman/admin/features/index.html.erb +25 -0
- data/app/views/usman/admin/features/index.js.erb +8 -0
- data/app/views/usman/admin/features/new.js.erb +7 -0
- data/app/views/usman/admin/features/row.js.erb +10 -0
- data/app/views/usman/admin/features/show.js.erb +8 -0
- data/app/views/usman/admin/features/update.js.erb +16 -0
- data/app/views/usman/admin/permissions/_action_buttons.html.erb +11 -0
- data/app/views/usman/admin/permissions/_form.html.erb +70 -0
- data/app/views/usman/admin/permissions/_index.html.erb +56 -0
- data/app/views/usman/admin/permissions/_row.html.erb +27 -0
- data/app/views/usman/admin/permissions/_show.html.erb +48 -0
- data/app/views/usman/admin/permissions/create.js.erb +17 -0
- data/app/views/usman/admin/permissions/destroy.js.erb +16 -0
- data/app/views/usman/admin/permissions/edit.js.erb +7 -0
- data/app/views/usman/admin/permissions/index.html.erb +25 -0
- data/app/views/usman/admin/permissions/index.js.erb +8 -0
- data/app/views/usman/admin/permissions/new.js.erb +7 -0
- data/app/views/usman/admin/permissions/row.js.erb +10 -0
- data/app/views/usman/admin/permissions/show.js.erb +8 -0
- data/app/views/usman/admin/permissions/update.js.erb +16 -0
- data/app/views/usman/admin/users/_action_buttons.html.erb +11 -0
- data/app/views/usman/admin/users/_form.html.erb +36 -0
- data/app/views/usman/admin/users/_index.html.erb +120 -0
- data/app/views/usman/admin/users/_row.html.erb +92 -0
- data/app/views/usman/admin/users/_show.html.erb +132 -0
- data/app/views/usman/admin/users/create.js.erb +16 -0
- data/app/views/usman/admin/users/destroy.js.erb +16 -0
- data/app/views/usman/admin/users/edit.js.erb +7 -0
- data/app/views/usman/admin/users/index.html.erb +40 -0
- data/app/views/usman/admin/users/index.js.erb +8 -0
- data/app/views/usman/admin/users/new.js.erb +7 -0
- data/app/views/usman/admin/users/row.js.erb +10 -0
- data/app/views/usman/admin/users/show.js.erb +8 -0
- data/app/views/usman/admin/users/update.js.erb +16 -0
- data/app/views/usman/sessions/_form.html.erb +48 -0
- data/app/views/usman/sessions/_sign_in.js.erb +3 -0
- data/app/views/usman/sessions/sign_in.html.erb +63 -0
- data/config/locales/usman.en.yml +61 -0
- data/config/routes.rb +45 -0
- data/db/migrate/20131108102728_create_images.rb +12 -0
- data/db/migrate/20140402113213_create_users.rb +57 -0
- data/db/migrate/20140402113214_create_features.rb +24 -0
- data/lib/tasks/usman_tasks.rake +4 -0
- data/lib/usman/engine.rb +14 -0
- data/lib/usman/version.rb +3 -0
- data/lib/usman.rb +5 -0
- metadata +418 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
module Usman
|
|
2
|
+
module AuthenticationHelper
|
|
3
|
+
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def current_user
|
|
7
|
+
# Return if @current_user is already initialized else check if the user exists with the auth token present in request header
|
|
8
|
+
@current_user ||= authenticate_with_http_token { |token, options| User.find_by(auth_token: token)}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Returns the default URL to which the system should redirect the user after successful authentication
|
|
12
|
+
def default_redirect_url_after_sign_in
|
|
13
|
+
admin_dashboard_url
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Returns the default URL to which the system should redirect the user after an unsuccessful attempt to authorise a resource/page
|
|
17
|
+
def default_sign_in_url
|
|
18
|
+
sign_in_url
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Method to handle the redirection after unsuccesful authentication
|
|
22
|
+
# This method should also handle the redirection if it has come through a client appliction for authentication
|
|
23
|
+
# In that case, it should persist the params passed by the client application
|
|
24
|
+
def redirect_after_unsuccessful_authentication
|
|
25
|
+
params_hsh = {}
|
|
26
|
+
params_hsh[:client_app] = params[:client_app] if params[:client_app]
|
|
27
|
+
params_hsh[:redirect_back_url] = params[:redirect_back_url] if params[:redirect_back_url]
|
|
28
|
+
params_hsh[:requested_url] = request.original_url if request.get?
|
|
29
|
+
redirect_to add_query_params(default_sign_in_url, params_hsh)
|
|
30
|
+
return
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Method to redirect after successful authentication
|
|
34
|
+
# This method should also handle the requests forwarded by the client for authentication
|
|
35
|
+
def redirect_to_appropriate_page_after_sign_in
|
|
36
|
+
if params[:redirect_back_url]
|
|
37
|
+
redirect_to params[:redirect_back_url]+"?auth_token=#{@current_user.auth_token}"
|
|
38
|
+
elsif params[:requested_url]
|
|
39
|
+
redirect_to params[:requested_url]
|
|
40
|
+
else
|
|
41
|
+
redirect_to default_redirect_url_after_sign_in
|
|
42
|
+
end
|
|
43
|
+
return
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def redirect_or_popup_to_default_sign_in_page
|
|
47
|
+
respond_to do |format|
|
|
48
|
+
format.html {
|
|
49
|
+
redirect_after_unsuccessful_authentication
|
|
50
|
+
}
|
|
51
|
+
format.js {
|
|
52
|
+
render(:partial => 'usman/sessions/sign_in.js.erb', :handlers => [:erb], :formats => [:js])
|
|
53
|
+
}
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# This method is widely used to create the @current_user object from the session
|
|
58
|
+
# This method will return @current_user if it already exists which will save queries when called multiple times
|
|
59
|
+
def current_user
|
|
60
|
+
# Check if the user exists with the auth token present in session
|
|
61
|
+
@current_user = User.find_by_id(session[:id]) unless @current_user
|
|
62
|
+
return @current_user
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# This method is usually used as a before filter to secure some of the actions which requires the user to be signed in.
|
|
66
|
+
def require_user
|
|
67
|
+
current_user
|
|
68
|
+
if @current_user
|
|
69
|
+
if @current_user.token_expired?
|
|
70
|
+
#binding.pry
|
|
71
|
+
@current_user = nil
|
|
72
|
+
session.delete(:id)
|
|
73
|
+
set_notification_messages("authentication.session_expired", :error)
|
|
74
|
+
redirect_or_popup_to_default_sign_in_page
|
|
75
|
+
return
|
|
76
|
+
end
|
|
77
|
+
else
|
|
78
|
+
set_notification_messages("authentication.permission_denied", :error)
|
|
79
|
+
redirect_or_popup_to_default_sign_in_page
|
|
80
|
+
return
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# This method is usually used as a before filter from admin controllers to ensure that the logged in user is a super admin
|
|
85
|
+
def require_super_admin
|
|
86
|
+
unless @current_user.is_super_admin?
|
|
87
|
+
set_notification_messages("authentication.permission_denied", :error)
|
|
88
|
+
redirect_or_popup_to_default_sign_in_page
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# This method is only used for masquerading. When admin masquerade as user A and then as B, when he logs out as B he should be logged in back as A
|
|
93
|
+
# This is accomplished by storing the last user id in session and activating it when user is logged off
|
|
94
|
+
def restore_last_user
|
|
95
|
+
return @last_user if @last_user
|
|
96
|
+
if session[:last_user_id].present?
|
|
97
|
+
@last_user = User.find_by_id(session[:last_user_id])
|
|
98
|
+
message = translate("users.sign_in_back", user: @last_user.name)
|
|
99
|
+
set_flash_message(message, :success, false)
|
|
100
|
+
session.destroy()
|
|
101
|
+
session[:id] = @last_user.id if @last_user.present?
|
|
102
|
+
return @last_user
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def masquerade_as_user(user)
|
|
107
|
+
#if ["development", "it", "test"].include?(Rails.env)
|
|
108
|
+
message = translate("users.masquerade", user: user.name)
|
|
109
|
+
set_flash_message(message, :success, false)
|
|
110
|
+
session[:last_user_id] = current_user.id if current_user
|
|
111
|
+
user.start_session
|
|
112
|
+
session[:id] = user.id
|
|
113
|
+
default_redirect_url_after_sign_in
|
|
114
|
+
url = admin_dashboard_url
|
|
115
|
+
redirect_to url
|
|
116
|
+
#end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
class Feature < ApplicationRecord
|
|
2
|
+
|
|
3
|
+
extend KuppayamValidators
|
|
4
|
+
|
|
5
|
+
# Constants
|
|
6
|
+
UNPUBLISHED = "unpublished"
|
|
7
|
+
PUBLISHED = "published"
|
|
8
|
+
DISABLED = "disabled"
|
|
9
|
+
|
|
10
|
+
STATUS = {
|
|
11
|
+
UNPUBLISHED => "Un-Published",
|
|
12
|
+
PUBLISHED => "Published",
|
|
13
|
+
DISABLED => "Disabled"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
STATUS_REVERSE = {
|
|
17
|
+
"Un-Published" => UNPUBLISHED,
|
|
18
|
+
"Published" => PUBLISHED,
|
|
19
|
+
"Disabled" => DISABLED
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Associations
|
|
23
|
+
has_many :permissions
|
|
24
|
+
has_many :users, through: :permissions
|
|
25
|
+
has_one :feature_image, :as => :imageable, :dependent => :destroy, :class_name => "Image::FeatureImage"
|
|
26
|
+
|
|
27
|
+
# Validations
|
|
28
|
+
validate_string :name, mandatory: true
|
|
29
|
+
validates :status, :presence => true, :inclusion => {:in => STATUS.keys, :presence_of => :status, :message => "%{value} is not a valid status" }
|
|
30
|
+
|
|
31
|
+
# ------------------
|
|
32
|
+
# Class Methods
|
|
33
|
+
# ------------------
|
|
34
|
+
|
|
35
|
+
# return an active record relation object with the search query in its where clause
|
|
36
|
+
# Return the ActiveRecord::Relation object
|
|
37
|
+
# == Examples
|
|
38
|
+
# >>> feature.search(query)
|
|
39
|
+
# => ActiveRecord::Relation object
|
|
40
|
+
scope :search, lambda {|query| where("LOWER(name) LIKE LOWER('%#{query}%')")
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
scope :status, lambda { |status| where("LOWER(status)='#{status}'") }
|
|
44
|
+
|
|
45
|
+
scope :unpublished, -> { where(status: UNPUBLISHED) }
|
|
46
|
+
scope :published, -> { where(status: PUBLISHED) }
|
|
47
|
+
scope :disabled, -> { where(status: DISABLED) }
|
|
48
|
+
|
|
49
|
+
# * Return full name
|
|
50
|
+
# == Examples
|
|
51
|
+
# >>> feature.display_name
|
|
52
|
+
# => "Products"
|
|
53
|
+
def display_name
|
|
54
|
+
"#{name}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# * Return true if the user is not published, else false.
|
|
58
|
+
# == Examples
|
|
59
|
+
# >>> feature.published?
|
|
60
|
+
# => true
|
|
61
|
+
def published?
|
|
62
|
+
(status == PUBLISHED)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# * Return true if the user is unpublished, else false.
|
|
66
|
+
# == Examples
|
|
67
|
+
# >>> feature.unpublished?
|
|
68
|
+
# => true
|
|
69
|
+
def unpublished?
|
|
70
|
+
(status == UNPUBLISHED)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# * Return true if the user is disabled, else false.
|
|
74
|
+
# == Examples
|
|
75
|
+
# >>> feature.disabled?
|
|
76
|
+
# => true
|
|
77
|
+
def disabled?
|
|
78
|
+
(status == DISABLED)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# change the status to :unpublished
|
|
82
|
+
# Return the status
|
|
83
|
+
# == Examples
|
|
84
|
+
# >>> feature.unpublish!
|
|
85
|
+
# => "unpublished"
|
|
86
|
+
def unpublish!
|
|
87
|
+
self.update_attribute(:status, UNPUBLISHED)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# change the status to :published
|
|
91
|
+
# Return the status
|
|
92
|
+
# == Examples
|
|
93
|
+
# >>> feature.publish!
|
|
94
|
+
# => "published"
|
|
95
|
+
def publish!
|
|
96
|
+
self.update_attribute(:status, PUBLISHED)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# change the status to :suspended
|
|
100
|
+
# Return the status
|
|
101
|
+
# == Examples
|
|
102
|
+
# >>> feature.suspend!
|
|
103
|
+
# => "suspended"
|
|
104
|
+
def suspend!
|
|
105
|
+
self.update_attribute(:status, DISABLED)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def can_be_destroyed?
|
|
109
|
+
return true
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class Image::Base < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
self.table_name = "images"
|
|
4
|
+
|
|
5
|
+
attr_accessor :crop_x, :crop_y, :crop_w, :crop_h
|
|
6
|
+
|
|
7
|
+
# Associations
|
|
8
|
+
belongs_to :imageable, :polymorphic => true, optional: true
|
|
9
|
+
|
|
10
|
+
# Callbacks
|
|
11
|
+
after_save :crop_image
|
|
12
|
+
|
|
13
|
+
def crop_image
|
|
14
|
+
image.recreate_versions! if crop_x.present?
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
#one convenient method to pass jq_upload the necessary information
|
|
18
|
+
def to_jq_upload
|
|
19
|
+
{
|
|
20
|
+
"name" => read_attribute(:image),
|
|
21
|
+
"size" => image.size,
|
|
22
|
+
"original_url" => image.url,
|
|
23
|
+
"large_url" => image.large.url,
|
|
24
|
+
"medium_url" => image.medium.url,
|
|
25
|
+
"small_url" => image.small.url,
|
|
26
|
+
"tiny_url" => image.tiny.url
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class Permission < ApplicationRecord
|
|
2
|
+
|
|
3
|
+
# Associations
|
|
4
|
+
belongs_to :user
|
|
5
|
+
belongs_to :feature
|
|
6
|
+
|
|
7
|
+
# Validations
|
|
8
|
+
validates :can_create, inclusion: { in: [true, false] }
|
|
9
|
+
validates :can_read, inclusion: { in: [true, false] }
|
|
10
|
+
validates :can_update, inclusion: { in: [true, false] }
|
|
11
|
+
validates :can_delete, inclusion: { in: [true, false] }
|
|
12
|
+
|
|
13
|
+
# ------------------
|
|
14
|
+
# Class Methods
|
|
15
|
+
# ------------------
|
|
16
|
+
|
|
17
|
+
# return an active record relation object with the search query in its where clause
|
|
18
|
+
# Return the ActiveRecord::Relation object
|
|
19
|
+
# == Examples
|
|
20
|
+
# >>> permission.search(query)
|
|
21
|
+
# => ActiveRecord::Relation object
|
|
22
|
+
scope :search, lambda {|query| joins("INNER JOIN users u on permissions.user_id = u.id").
|
|
23
|
+
joins("INNER JOIN features f on permissions.feature_id = f.id").
|
|
24
|
+
where("LOWER(u.name) LIKE LOWER('%#{query}%') OR\
|
|
25
|
+
LOWER(u.username) LIKE LOWER('%#{query}%') OR\
|
|
26
|
+
LOWER(u.email) LIKE LOWER('%#{query}%') OR\
|
|
27
|
+
LOWER(f.name) LIKE LOWER('%#{query}%')")}
|
|
28
|
+
end
|
data/app/models/user.rb
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
class User < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
extend KuppayamValidators
|
|
4
|
+
|
|
5
|
+
# including Password Methods
|
|
6
|
+
has_secure_password
|
|
7
|
+
|
|
8
|
+
# Constants
|
|
9
|
+
PENDING = "pending"
|
|
10
|
+
APPROVED = "approved"
|
|
11
|
+
SUSPENDED = "suspended"
|
|
12
|
+
|
|
13
|
+
STATUS = {
|
|
14
|
+
PENDING => "Pending",
|
|
15
|
+
APPROVED => "Approved",
|
|
16
|
+
SUSPENDED => "Suspended"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
STATUS_REVERSE = {
|
|
20
|
+
"Pending" => PENDING,
|
|
21
|
+
"Approved" => APPROVED,
|
|
22
|
+
"Suspended" => SUSPENDED
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
EXCLUDED_JSON_ATTRIBUTES = [:confirmation_token, :password_digest, :reset_password_token, :unlock_token, :status, :reset_password_sent_at, :remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip, :confirmed_at, :confirmation_sent_at, :unconfirmed_email, :failed_attempts, :locked_at, :created_at, :updated_at]
|
|
26
|
+
DEFAULT_PASSWORD = "Password@1"
|
|
27
|
+
SESSION_TIME_OUT = 30.minutes
|
|
28
|
+
|
|
29
|
+
# Validations
|
|
30
|
+
validate_string :name, mandatory: true
|
|
31
|
+
validate_username :username
|
|
32
|
+
validate_email :email
|
|
33
|
+
validate_password :password, condition_method: :should_validate_password?
|
|
34
|
+
|
|
35
|
+
validates :status, :presence => true, :inclusion => {:in => STATUS.keys, :presence_of => :status, :message => "%{value} is not a valid status" }
|
|
36
|
+
|
|
37
|
+
# Callbacks
|
|
38
|
+
before_validation :generate_auth_token
|
|
39
|
+
|
|
40
|
+
# Associations
|
|
41
|
+
has_one :profile_picture, :as => :imageable, :dependent => :destroy, :class_name => "Image::ProfilePicture"
|
|
42
|
+
has_many :permissions
|
|
43
|
+
has_many :features, through: :permissions
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# ------------------
|
|
47
|
+
# Class Methods
|
|
48
|
+
# ------------------
|
|
49
|
+
|
|
50
|
+
def self.find_by_email_or_username(query)
|
|
51
|
+
self.where("LOWER(email) = LOWER('#{query}') OR LOWER(username) = LOWER('#{query}')").first
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# return an active record relation object with the search query in its where clause
|
|
55
|
+
# Return the ActiveRecord::Relation object
|
|
56
|
+
# == Examples
|
|
57
|
+
# >>> user.search(query)
|
|
58
|
+
# => ActiveRecord::Relation object
|
|
59
|
+
scope :search, lambda {|query| where("LOWER(name) LIKE LOWER('%#{query}%') OR\
|
|
60
|
+
LOWER(username) LIKE LOWER('%#{query}%') OR\
|
|
61
|
+
LOWER(email) LIKE LOWER('%#{query}%') OR\
|
|
62
|
+
LOWER(designation) LIKE LOWER('%#{query}%')")
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
scope :status, lambda { |status| where("LOWER(status)='#{status}'") }
|
|
66
|
+
|
|
67
|
+
scope :pending, -> { where(status: PENDING) }
|
|
68
|
+
scope :approved, -> { where(status: APPROVED) }
|
|
69
|
+
scope :suspended, -> { where(status: SUSPENDED) }
|
|
70
|
+
|
|
71
|
+
# ------------------
|
|
72
|
+
# Instance variables
|
|
73
|
+
# ------------------
|
|
74
|
+
|
|
75
|
+
# * Return full name
|
|
76
|
+
# == Examples
|
|
77
|
+
# >>> user.display_name
|
|
78
|
+
# => "Joe Black"
|
|
79
|
+
def display_name
|
|
80
|
+
"#{name}"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# * Return true if the user is not approved, else false.
|
|
84
|
+
# == Examples
|
|
85
|
+
# >>> user.approved?
|
|
86
|
+
# => true
|
|
87
|
+
def approved?
|
|
88
|
+
(status == APPROVED)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# * Return true if the user is pending, else false.
|
|
92
|
+
# == Examples
|
|
93
|
+
# >>> user.pending?
|
|
94
|
+
# => true
|
|
95
|
+
def pending?
|
|
96
|
+
(status == PENDING)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# * Return true if the user is suspended, else false.
|
|
100
|
+
# == Examples
|
|
101
|
+
# >>> user.suspended?
|
|
102
|
+
# => true
|
|
103
|
+
def suspended?
|
|
104
|
+
(status == SUSPENDED)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# change the status to :pending
|
|
108
|
+
# Return the status
|
|
109
|
+
# == Examples
|
|
110
|
+
# >>> user.pending!
|
|
111
|
+
# => "pending"
|
|
112
|
+
def pending!
|
|
113
|
+
self.update_attribute(:status, PENDING)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# change the status to :approved
|
|
117
|
+
# Return the status
|
|
118
|
+
# == Examples
|
|
119
|
+
# >>> user.approve!
|
|
120
|
+
# => "approved"
|
|
121
|
+
def approve!
|
|
122
|
+
self.update_attribute(:status, APPROVED)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# change the status to :suspended
|
|
126
|
+
# Return the status
|
|
127
|
+
# == Examples
|
|
128
|
+
# >>> user.suspend!
|
|
129
|
+
# => "suspended"
|
|
130
|
+
def suspend!
|
|
131
|
+
self.update_attribute(:status, SUSPENDED)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def is_super_admin?
|
|
135
|
+
super_admin
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def start_session
|
|
139
|
+
# FIX ME - specs are not written to ensure that all these data are saved
|
|
140
|
+
self.token_created_at = Time.now
|
|
141
|
+
self.sign_in_count = self.sign_in_count ? self.sign_in_count + 1 : 1
|
|
142
|
+
self.last_sign_in_at = self.current_sign_in_at
|
|
143
|
+
self.last_sign_in_ip = self.current_sign_in_ip
|
|
144
|
+
self.current_sign_in_at = self.token_created_at
|
|
145
|
+
|
|
146
|
+
# FIX ME - pass remote_ip to this method.
|
|
147
|
+
# Make necessary changes to authentication service to make it work
|
|
148
|
+
# self.current_sign_in_ip = remote_ip if remote_ip
|
|
149
|
+
self.save
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def end_session
|
|
153
|
+
# Reseting the auth token for user when he logs out.
|
|
154
|
+
# (Time.now - 1.second)
|
|
155
|
+
self.update_attributes auth_token: SecureRandom.hex, token_created_at: nil
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def assign_default_password
|
|
159
|
+
self.password = DEFAULT_PASSWORD
|
|
160
|
+
self.password_confirmation = DEFAULT_PASSWORD
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def token_expired?
|
|
164
|
+
return self.token_created_at.nil? || (Time.now > self.token_created_at + SESSION_TIME_OUT)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def generate_reset_password_token
|
|
168
|
+
self.reset_password_token = SecureRandom.hex unless self.reset_password_token
|
|
169
|
+
self.reset_password_sent_at = Time.now unless self.reset_password_sent_at
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def default_image_url(size="small")
|
|
173
|
+
"/assets/kuppayam/defaults/user-#{size}.png"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def set_permission(feature_name, **options)
|
|
177
|
+
options.reverse_merge!(
|
|
178
|
+
can_create: false,
|
|
179
|
+
can_read: true,
|
|
180
|
+
can_update: false,
|
|
181
|
+
can_delete: false
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
feature = get_feature(feature_name)
|
|
185
|
+
|
|
186
|
+
permission = Permission.where("user_id = ? AND feature_id = ?", self.id, feature.id).first || Permission.new(user: self, feature: feature)
|
|
187
|
+
permission.assign_attributes(options)
|
|
188
|
+
permission.save
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def can_create?(feature_name)
|
|
192
|
+
feature = get_feature(feature_name)
|
|
193
|
+
|
|
194
|
+
permission = Permission.where("feature_id = ? AND user_id = ?", feature.id, self.id).first
|
|
195
|
+
permission && permission.can_create?
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def can_read?(feature_name)
|
|
199
|
+
feature = get_feature(feature_name)
|
|
200
|
+
|
|
201
|
+
permission = Permission.where("feature_id = ? AND user_id = ?", feature.id, self.id).first
|
|
202
|
+
permission && permission.can_read?
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def can_update?(feature_name)
|
|
206
|
+
feature = get_feature(feature_name)
|
|
207
|
+
|
|
208
|
+
permission = Permission.where("feature_id = ? AND user_id = ?", feature.id, self.id).first
|
|
209
|
+
permission && permission.can_update?
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
def can_delete?(feature_name)
|
|
213
|
+
feature = get_feature(feature_name)
|
|
214
|
+
|
|
215
|
+
permission = Permission.where("feature_id = ? AND user_id = ?", feature.id, self.id).first
|
|
216
|
+
permission && permission.can_delete?
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def can_be_destroyed?
|
|
220
|
+
return true
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
private
|
|
224
|
+
|
|
225
|
+
def should_validate_password?
|
|
226
|
+
self.new_record? || (self.new_record? == false and self.password.present?)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def generate_auth_token
|
|
230
|
+
self.auth_token = SecureRandom.hex unless self.auth_token
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def get_feature(feature_name)
|
|
234
|
+
case feature_name
|
|
235
|
+
when Feature
|
|
236
|
+
feature = feature_name
|
|
237
|
+
when String
|
|
238
|
+
feature = Feature.find_by_name(feature_name)
|
|
239
|
+
when Integer
|
|
240
|
+
feature = Feature.find_by_id(feature_name)
|
|
241
|
+
else
|
|
242
|
+
raise "Feature with name '#{feature.name}' doesn't exist" unless feature
|
|
243
|
+
end
|
|
244
|
+
return feature
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Usman
|
|
2
|
+
class AuthenticationService
|
|
3
|
+
|
|
4
|
+
attr_reader :login_handle, :password, :error, :user
|
|
5
|
+
|
|
6
|
+
def initialize(params)
|
|
7
|
+
@login_handle = params[:login_handle]
|
|
8
|
+
@password = params[:password]
|
|
9
|
+
@error = nil
|
|
10
|
+
|
|
11
|
+
check_if_user_exists
|
|
12
|
+
if @user
|
|
13
|
+
authenticate
|
|
14
|
+
check_if_user_is_approved
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
@user.start_session unless @error
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def invalid_login_error
|
|
21
|
+
"authentication.invalid_login"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def user_status_error
|
|
25
|
+
"authentication.user_is_#{@user.status.downcase}"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def check_if_user_exists
|
|
29
|
+
@user = User.where("LOWER(email) = LOWER('#{@login_handle}') OR LOWER(username) = LOWER('#{@login_handle}')").first
|
|
30
|
+
set_error(invalid_login_error) unless @user
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def check_if_user_is_approved
|
|
34
|
+
set_error(user_status_error) unless @user.approved?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def authenticate
|
|
38
|
+
set_error(invalid_login_error) unless @user.authenticate(@password)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def set_error(id)
|
|
42
|
+
@error ||= id
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|