fat_free_crm 0.12.1 → 0.12.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of fat_free_crm might be problematic. Click here for more details.
- checksums.yaml +8 -8
- data/app/controllers/application_controller.rb +23 -23
- data/app/controllers/home_controller.rb +0 -1
- data/app/controllers/users_controller.rb +23 -46
- data/app/models/users/ability.rb +13 -2
- data/app/models/users/user.rb +4 -0
- data/app/views/layouts/application.html.haml +8 -5
- data/config/application.rb +1 -1
- data/config/environments/production.rb +2 -3
- data/config/initializers/secret_token.rb +25 -1
- data/config/locales/en-US_fat_free_crm.yml +1 -1
- data/lib/fat_free_crm.rb +11 -1
- data/lib/fat_free_crm/secret_token_generator.rb +59 -0
- data/lib/fat_free_crm/version.rb +1 -1
- data/spec/controllers/admin/users_controller_spec.rb +1 -3
- data/spec/controllers/users_controller_spec.rb +47 -19
- data/spec/lib/secret_token_generator_spec.rb +55 -0
- data/spec/models/users/abilities/user_ability_spec.rb +58 -0
- data/spec/spec_helper.rb +2 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ODc2YTUzOGEyMTQyYjM2YjU5NjBhZWIxZjdlYzM3YmU0ZDA2MmRiOA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
Y2Q5ZGRmY2YxZTYzNzBkYjJhMmJkODliODYxZDQwOTZkYWI1ZmYzOA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Zjc1M2JhOGYyNWJhODdlNDVkM2Y1YmU4Yjg2MzlmZmNhNTY4MzUzN2I1NmNk
|
10
|
+
NDBiNTcyZjNlY2Y3NTBlODM1OThhMTYyZmNkZjIyYTA4ZmIwYzI4OTFiNmYx
|
11
|
+
NjIwODkzYjQ1ZGQwNDFlMDFlZmJkMDg0Zjk0MTJhNzY3ZjY0NzI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZTk3Zjc2MmFmZjU3OGQzNWM1ZTUxOWIyNWRjN2I0Y2ZlZTM5ODA4YWZiZGQ1
|
14
|
+
YjEwMzBmYzQ2MWExYTBjMWY2OTEzZTVmYjIwZDQ0MDMwZTkwYjcxMTk3NzJl
|
15
|
+
MjQ0NWUxYmZhZDQ4ZTEwNzU4ZWM0OTYzOWZmMDMyMzRlMTdjNzc=
|
@@ -145,7 +145,7 @@ private
|
|
145
145
|
|
146
146
|
#----------------------------------------------------------------------------
|
147
147
|
def can_signup?
|
148
|
-
|
148
|
+
User.can_signup?
|
149
149
|
end
|
150
150
|
|
151
151
|
#----------------------------------------------------------------------------
|
@@ -199,10 +199,10 @@ private
|
|
199
199
|
flash[:warning] = t(:msg_asset_not_available, asset)
|
200
200
|
|
201
201
|
respond_to do |format|
|
202
|
-
format.html { redirect_to
|
202
|
+
format.html { redirect_to(redirection_url) }
|
203
203
|
format.js { render(:update) { |page| page.reload } }
|
204
|
-
format.json { render :text => flash[:warning],
|
205
|
-
format.xml { render :
|
204
|
+
format.json { render :text => flash[:warning], :status => :not_found }
|
205
|
+
format.xml { render :xml => [flash[:warning]], :status => :not_found }
|
206
206
|
end
|
207
207
|
end
|
208
208
|
|
@@ -213,32 +213,32 @@ private
|
|
213
213
|
|
214
214
|
url = send("#{related.pluralize}_path")
|
215
215
|
respond_to do |format|
|
216
|
-
format.html { redirect_to
|
217
|
-
format.js { render(:update) { |page| page.redirect_to
|
218
|
-
format.json { render :text => flash[:warning],
|
219
|
-
format.xml { render :
|
216
|
+
format.html { redirect_to(url) }
|
217
|
+
format.js { render(:update) { |page| page.redirect_to(url) } }
|
218
|
+
format.json { render :text => flash[:warning], :status => :not_found }
|
219
|
+
format.xml { render :xml => [flash[:warning]], :status => :not_found }
|
220
220
|
end
|
221
221
|
end
|
222
222
|
|
223
223
|
#----------------------------------------------------------------------------
|
224
224
|
def respond_to_access_denied
|
225
|
-
|
226
|
-
flash[:warning] = t(:msg_asset_not_authorized, asset)
|
227
|
-
|
228
|
-
else
|
229
|
-
flick = case self.action_name
|
230
|
-
when "destroy" then "delete"
|
231
|
-
when "promote" then "convert"
|
232
|
-
else self.action_name
|
233
|
-
end
|
234
|
-
flash[:warning] = t(:msg_cant_do, :action => flick, :asset => asset)
|
235
|
-
end
|
236
|
-
|
225
|
+
flash[:warning] = t(:msg_not_authorized, default: 'You are not authorized to take this action.')
|
237
226
|
respond_to do |format|
|
238
|
-
format.html { redirect_to
|
227
|
+
format.html { redirect_to(redirection_url) }
|
239
228
|
format.js { render(:update) { |page| page.reload } }
|
240
|
-
format.json { render :text => flash[:warning],
|
241
|
-
format.xml { render :
|
229
|
+
format.json { render :text => flash[:warning], :status => :unauthorized }
|
230
|
+
format.xml { render :xml => [flash[:warning]], :status => :unauthorized }
|
242
231
|
end
|
243
232
|
end
|
233
|
+
|
234
|
+
#----------------------------------------------------------------------------
|
235
|
+
def redirection_url
|
236
|
+
# Try to redirect somewhere sensible. Note: not all controllers have an index action
|
237
|
+
url = if current_user.present?
|
238
|
+
(respond_to?(:index) and self.action_name != 'index') ? { action: 'index' } : root_url
|
239
|
+
else
|
240
|
+
login_url
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
244
|
end
|
@@ -6,7 +6,6 @@
|
|
6
6
|
class HomeController < ApplicationController
|
7
7
|
before_filter :require_user, :except => [ :toggle, :timezone ]
|
8
8
|
before_filter :set_current_tab, :only => :index
|
9
|
-
before_filter "hook(:home_before_filter, self, :amazing => true)"
|
10
9
|
|
11
10
|
#----------------------------------------------------------------------------
|
12
11
|
def index
|
@@ -5,44 +5,30 @@
|
|
5
5
|
#------------------------------------------------------------------------------
|
6
6
|
class UsersController < ApplicationController
|
7
7
|
|
8
|
-
before_filter :require_no_user, :only => [ :new, :create ]
|
9
|
-
before_filter :require_user, :only => [ :show, :redraw ]
|
10
8
|
before_filter :set_current_tab, :only => [ :show, :opportunities_overview ] # Don't hightlight any tabs.
|
11
|
-
before_filter :require_and_assign_user, :except => [ :new, :create, :show, :avatar, :upload_avatar ]
|
12
|
-
before_filter :assign_given_or_current_user, :only => [ :show, :avatar, :upload_avatar, :edit, :update ]
|
13
9
|
|
14
|
-
|
10
|
+
check_authorization
|
11
|
+
load_and_authorize_resource # handles all security
|
15
12
|
|
16
13
|
respond_to :html, :only => [ :show, :new ]
|
17
14
|
|
18
15
|
# GET /users/1
|
19
|
-
# GET /users/1.
|
20
|
-
# GET /users/1.xml HTML
|
16
|
+
# GET /users/1.js
|
21
17
|
#----------------------------------------------------------------------------
|
22
18
|
def show
|
19
|
+
@user = current_user if params[:id].nil?
|
23
20
|
respond_with(@user)
|
24
21
|
end
|
25
22
|
|
26
23
|
# GET /users/new
|
27
|
-
# GET /users/new.
|
28
|
-
# GET /users/new.xml HTML
|
24
|
+
# GET /users/new.js
|
29
25
|
#----------------------------------------------------------------------------
|
30
26
|
def new
|
31
|
-
if can_signup?
|
32
|
-
respond_with(@user)
|
33
|
-
else
|
34
|
-
redirect_to login_path
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# GET /users/1/edit AJAX
|
39
|
-
#----------------------------------------------------------------------------
|
40
|
-
def edit
|
41
27
|
respond_with(@user)
|
42
28
|
end
|
43
29
|
|
44
30
|
# POST /users
|
45
|
-
# POST /users.
|
31
|
+
# POST /users.js
|
46
32
|
#----------------------------------------------------------------------------
|
47
33
|
def create
|
48
34
|
if @user.save
|
@@ -58,31 +44,29 @@ class UsersController < ApplicationController
|
|
58
44
|
end
|
59
45
|
end
|
60
46
|
|
61
|
-
#
|
62
|
-
# PUT /users/1.json
|
63
|
-
# PUT /users/1.xml AJAX
|
47
|
+
# GET /users/1/edit.js
|
64
48
|
#----------------------------------------------------------------------------
|
65
|
-
def
|
66
|
-
@user.update_attributes(params[:user])
|
49
|
+
def edit
|
67
50
|
respond_with(@user)
|
68
51
|
end
|
69
52
|
|
70
|
-
#
|
71
|
-
#
|
53
|
+
# PUT /users/1
|
54
|
+
# PUT /users/1.js
|
72
55
|
#----------------------------------------------------------------------------
|
73
|
-
def
|
74
|
-
|
56
|
+
def update
|
57
|
+
@user.update_attributes(params[:user])
|
58
|
+
respond_with(@user)
|
75
59
|
end
|
76
60
|
|
77
61
|
# GET /users/1/avatar
|
78
|
-
# GET /users/1/avatar.
|
62
|
+
# GET /users/1/avatar.js
|
79
63
|
#----------------------------------------------------------------------------
|
80
64
|
def avatar
|
81
65
|
respond_with(@user)
|
82
66
|
end
|
83
67
|
|
84
68
|
# PUT /users/1/upload_avatar
|
85
|
-
# PUT /users/1/upload_avatar.
|
69
|
+
# PUT /users/1/upload_avatar.js
|
86
70
|
#----------------------------------------------------------------------------
|
87
71
|
def upload_avatar
|
88
72
|
if params[:gravatar]
|
@@ -106,19 +90,21 @@ class UsersController < ApplicationController
|
|
106
90
|
end
|
107
91
|
|
108
92
|
# GET /users/1/password
|
109
|
-
# GET /users/1/password.
|
93
|
+
# GET /users/1/password.js
|
110
94
|
#----------------------------------------------------------------------------
|
111
95
|
def password
|
112
96
|
respond_with(@user)
|
113
97
|
end
|
114
98
|
|
115
99
|
# PUT /users/1/change_password
|
116
|
-
# PUT /users/1/change_password.
|
100
|
+
# PUT /users/1/change_password.js
|
117
101
|
#----------------------------------------------------------------------------
|
118
102
|
def change_password
|
119
103
|
if @user.valid_password?(params[:current_password], true) || @user.password_hash.blank?
|
120
104
|
unless params[:user][:password].blank?
|
121
|
-
@user.
|
105
|
+
@user.password = params[:user][:password]
|
106
|
+
@user.password_confirmation = params[:user][:password_confirmation]
|
107
|
+
@user.save
|
122
108
|
flash[:notice] = t(:msg_password_changed)
|
123
109
|
else
|
124
110
|
flash[:notice] = t(:msg_password_not_changed)
|
@@ -130,27 +116,18 @@ class UsersController < ApplicationController
|
|
130
116
|
respond_with(@user)
|
131
117
|
end
|
132
118
|
|
133
|
-
# POST /users/1/redraw
|
119
|
+
# POST /users/1/redraw
|
134
120
|
#----------------------------------------------------------------------------
|
135
121
|
def redraw
|
136
122
|
current_user.preference[:locale] = params[:locale]
|
137
123
|
render(:update) { |page| page.redirect_to user_path(current_user) }
|
138
124
|
end
|
139
125
|
|
126
|
+
# GET /users/opportunities_overview
|
127
|
+
#----------------------------------------------------------------------------
|
140
128
|
def opportunities_overview
|
141
129
|
@users_with_opportunities = User.have_assigned_opportunities.order(:first_name)
|
142
130
|
@unassigned_opportunities = Opportunity.unassigned.pipeline.order(:stage)
|
143
131
|
end
|
144
132
|
|
145
|
-
private
|
146
|
-
|
147
|
-
#----------------------------------------------------------------------------
|
148
|
-
def require_and_assign_user
|
149
|
-
require_user
|
150
|
-
@user = current_user
|
151
|
-
end
|
152
|
-
|
153
|
-
def assign_given_or_current_user
|
154
|
-
@user = params[:id] ? User.find(params[:id]) : current_user
|
155
|
-
end
|
156
133
|
end
|
data/app/models/users/ability.rb
CHANGED
@@ -9,11 +9,22 @@ class Ability
|
|
9
9
|
include CanCan::Ability
|
10
10
|
|
11
11
|
def initialize(user)
|
12
|
+
|
13
|
+
# handle signup
|
14
|
+
can(:create, User) if User.can_signup?
|
15
|
+
|
12
16
|
if user.present?
|
13
17
|
entities = [Account, Campaign, Contact, Lead, Opportunity]
|
14
18
|
|
15
|
-
|
16
|
-
can :
|
19
|
+
# User
|
20
|
+
can :manage, User, id: user.id # can do any action on themselves
|
21
|
+
|
22
|
+
# Tasks
|
23
|
+
can :create, Task
|
24
|
+
can :manage, Task, user: user.id
|
25
|
+
can :manage, Task, assigned_to: user.id
|
26
|
+
|
27
|
+
# Entities
|
17
28
|
can :manage, entities, :access => 'Public'
|
18
29
|
can :manage, entities + [Task], :user_id => user.id
|
19
30
|
can :manage, entities + [Task], :assigned_to => user.id
|
data/app/models/users/user.rb
CHANGED
@@ -20,13 +20,16 @@
|
|
20
20
|
= hook(:javascript_includes, self)
|
21
21
|
|
22
22
|
:javascript
|
23
|
-
#{
|
24
|
-
var _ffcrm_users = [
|
25
|
-
#{User.all.map{|u| "\"#{u.full_name} (@#{u.username})\"" }.join(",\n")}
|
26
|
-
];
|
27
|
-
|
23
|
+
crm.language = "#{I18n.locale}"
|
28
24
|
window.controller = "#{controller.controller_name}"
|
29
25
|
|
26
|
+
- if current_user.present?
|
27
|
+
:javascript
|
28
|
+
#{yield :javascript}
|
29
|
+
var _ffcrm_users = [
|
30
|
+
#{User.all.map{|u| "\"#{u.full_name} (@#{u.username})\"" }.join(",\n")}
|
31
|
+
];
|
32
|
+
|
30
33
|
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
|
31
34
|
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
32
35
|
|
data/config/application.rb
CHANGED
@@ -65,7 +65,7 @@ module FatFreeCRM
|
|
65
65
|
config.encoding = "utf-8"
|
66
66
|
|
67
67
|
# Configure sensitive parameters which will be filtered from the log file.
|
68
|
-
config.filter_parameters += [:password]
|
68
|
+
config.filter_parameters += [:password, :password_hash, :password_salt, :password_confirmation]
|
69
69
|
|
70
70
|
# Use SQL instead of Active Record's schema dumper when creating the database.
|
71
71
|
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
@@ -10,9 +10,8 @@ if defined?(FatFreeCRM::Application)
|
|
10
10
|
# Code is not reloaded between requests
|
11
11
|
config.cache_classes = true
|
12
12
|
|
13
|
-
# Full error reports are
|
14
|
-
config.consider_all_requests_local =
|
15
|
-
# Caching is turned on
|
13
|
+
# Full error reports are disabled and caching is turned on.
|
14
|
+
config.consider_all_requests_local = false
|
16
15
|
config.action_controller.perform_caching = true
|
17
16
|
|
18
17
|
# Disable Rails's static asset server (Apache or nginx will already do this)
|
@@ -1 +1,25 @@
|
|
1
|
-
|
1
|
+
# Copyright (c) 2008-2013 Michael Dvorkin and contributors.
|
2
|
+
#
|
3
|
+
# Fat Free CRM is freely distributable under the terms of MIT license.
|
4
|
+
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
5
|
+
#------------------------------------------------------------------------------
|
6
|
+
|
7
|
+
# Be sure to restart your server when you modify this file.
|
8
|
+
|
9
|
+
# Your secret key is used for verifying the integrity of signed cookies.
|
10
|
+
# If you change this key, all old signed cookies will become invalid!
|
11
|
+
|
12
|
+
# Make sure the secret is at least 30 characters and all random,
|
13
|
+
# no regular words or you'll be exposed to dictionary attacks.
|
14
|
+
# You can use `rake secret` to generate a secure secret key.
|
15
|
+
|
16
|
+
# Make sure your secret_key_base is kept private
|
17
|
+
# if you're sharing your code publicly.
|
18
|
+
|
19
|
+
#
|
20
|
+
# We should setup a secret token if FFCRM is running in application mode but NOT in engine mode.
|
21
|
+
# This functionality has been extracted to lib so it can be tested.
|
22
|
+
if FatFreeCRM.application?
|
23
|
+
require 'fat_free_crm/secret_token_generator'
|
24
|
+
FatFreeCRM::SecretTokenGenerator.setup!
|
25
|
+
end
|
@@ -189,7 +189,7 @@ en-US:
|
|
189
189
|
msg_account_not_approved: Your account has not been approved yet.
|
190
190
|
msg_asset_deleted: "%{value} has been deleted."
|
191
191
|
msg_asset_not_available: This %{value} is no longer available.
|
192
|
-
|
192
|
+
msg_not_authorized: You are not authorized to take this action.
|
193
193
|
msg_assets_not_available: The %{value} are not available.
|
194
194
|
msg_asset_rejected: "%{value} has been rejected."
|
195
195
|
msg_bad_image_file: "^Could't upload or resize the image file you specified."
|
data/lib/fat_free_crm.rb
CHANGED
@@ -9,12 +9,22 @@ module FatFreeCRM
|
|
9
9
|
# Return either Application or Engine,
|
10
10
|
# depending on how Fat Free CRM has been loaded
|
11
11
|
def application
|
12
|
-
|
12
|
+
engine? ? Engine : Application
|
13
13
|
end
|
14
14
|
|
15
15
|
def root
|
16
16
|
application.root
|
17
17
|
end
|
18
|
+
|
19
|
+
# Are we running as an engine?
|
20
|
+
def engine?
|
21
|
+
defined?(FatFreeCRM::Engine).present?
|
22
|
+
end
|
23
|
+
|
24
|
+
def application?
|
25
|
+
!engine?
|
26
|
+
end
|
27
|
+
|
18
28
|
end
|
19
29
|
end
|
20
30
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Copyright (c) 2008-2014 Michael Dvorkin and contributors.
|
2
|
+
#
|
3
|
+
# Fat Free CRM is freely distributable under the terms of MIT license.
|
4
|
+
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
5
|
+
#------------------------------------------------------------------------------
|
6
|
+
|
7
|
+
require 'securerandom'
|
8
|
+
|
9
|
+
module FatFreeCRM
|
10
|
+
|
11
|
+
class SecretTokenGenerator
|
12
|
+
|
13
|
+
class << self
|
14
|
+
|
15
|
+
#
|
16
|
+
# If there is no secret token defined, we generate one and save it as a setting
|
17
|
+
# If a token has been already been saved, we tell Rails to use it and move on.
|
18
|
+
def setup!
|
19
|
+
if token.blank?
|
20
|
+
Rails.logger.info("No secret key defined yet... generating and saving to Setting.secret_token")
|
21
|
+
generate_and_persist_token!
|
22
|
+
end
|
23
|
+
FatFreeCRM::Application.config.secret_token = token
|
24
|
+
raise(FAIL_MESSAGE) if FatFreeCRM::Application.config.secret_token.blank?
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
FAIL_MESSAGE = ::I18n.t('secret_token_generator.fail_message', default: "There was a problem generating the secret token. Please see lib/fat_free_crm/secret_token_generator.rb")
|
30
|
+
|
31
|
+
#
|
32
|
+
# Read the current token from settings
|
33
|
+
def token
|
34
|
+
Setting.secret_token
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Create a new secret token and save it as a setting.
|
39
|
+
def generate_and_persist_token!
|
40
|
+
quietly do
|
41
|
+
Setting.secret_token = SecureRandom.hex(64)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#
|
46
|
+
# Yields to a block that executes with the logging turned off
|
47
|
+
# This stops the secret token from being appended to the log
|
48
|
+
def quietly(&block)
|
49
|
+
temp_logger = ActiveRecord::Base.logger
|
50
|
+
ActiveRecord::Base.logger = nil
|
51
|
+
yield
|
52
|
+
ActiveRecord::Base.logger = temp_logger
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/lib/fat_free_crm/version.rb
CHANGED
@@ -54,10 +54,8 @@ describe Admin::UsersController do
|
|
54
54
|
#----------------------------------------------------------------------------
|
55
55
|
describe "GET new" do
|
56
56
|
it "assigns a new user as @user and renders [new] template" do
|
57
|
-
@user = User.new
|
58
|
-
|
59
57
|
xhr :get, :new
|
60
|
-
assigns[:user].
|
58
|
+
expect(assigns[:user]).to be_new_record
|
61
59
|
response.should render_template("admin/users/new")
|
62
60
|
end
|
63
61
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
# Fat Free CRM is freely distributable under the terms of MIT license.
|
4
4
|
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
5
5
|
#------------------------------------------------------------------------------
|
6
|
-
require
|
6
|
+
require 'spec_helper'
|
7
7
|
|
8
8
|
describe UsersController do
|
9
9
|
|
@@ -15,11 +15,9 @@ describe UsersController do
|
|
15
15
|
require_user
|
16
16
|
end
|
17
17
|
|
18
|
-
it "should
|
19
|
-
|
20
|
-
|
21
|
-
get :show, :id => @user.id
|
22
|
-
assigns[:user].should == @user
|
18
|
+
it "should render [show] template" do
|
19
|
+
get :show, :id => current_user.id
|
20
|
+
assigns[:user].should == current_user
|
23
21
|
response.should render_template("users/show")
|
24
22
|
end
|
25
23
|
|
@@ -29,16 +27,30 @@ describe UsersController do
|
|
29
27
|
response.should render_template("users/show")
|
30
28
|
end
|
31
29
|
|
30
|
+
it "should show user if admin user" do
|
31
|
+
@user = create(:user)
|
32
|
+
require_user(admin: true)
|
33
|
+
get :show, id: @user.id
|
34
|
+
assigns[:user].should == @user
|
35
|
+
response.should render_template("users/show")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should not show user if not admin user" do
|
39
|
+
@user = create(:user)
|
40
|
+
get :show, id: @user.id
|
41
|
+
response.should redirect_to(root_url)
|
42
|
+
end
|
43
|
+
|
32
44
|
describe "with mime type of JSON" do
|
33
45
|
before(:each) do
|
34
46
|
request.env["HTTP_ACCEPT"] = "application/json"
|
35
47
|
end
|
36
48
|
|
37
49
|
it "should render the requested user as JSON" do
|
38
|
-
User.should_receive(:find).and_return(
|
39
|
-
|
50
|
+
User.should_receive(:find).and_return(current_user)
|
51
|
+
current_user.should_receive(:to_json).and_return("generated JSON")
|
40
52
|
|
41
|
-
get :show, :id =>
|
53
|
+
get :show, :id => current_user.id
|
42
54
|
response.body.should == "generated JSON"
|
43
55
|
end
|
44
56
|
|
@@ -56,10 +68,10 @@ describe UsersController do
|
|
56
68
|
end
|
57
69
|
|
58
70
|
it "should render the requested user as XML" do
|
59
|
-
User.should_receive(:find).and_return(
|
60
|
-
|
71
|
+
User.should_receive(:find).and_return(current_user)
|
72
|
+
current_user.should_receive(:to_xml).and_return("generated XML")
|
61
73
|
|
62
|
-
get :show, :id =>
|
74
|
+
get :show, :id => current_user.id
|
63
75
|
response.body.should == "generated XML"
|
64
76
|
end
|
65
77
|
|
@@ -79,7 +91,7 @@ describe UsersController do
|
|
79
91
|
|
80
92
|
describe "if user is allowed to sign up" do
|
81
93
|
it "should expose a new user as @user and render [new] template" do
|
82
|
-
|
94
|
+
User.should_receive(:can_signup?).and_return(true)
|
83
95
|
@user = FactoryGirl.build(:user)
|
84
96
|
User.stub!(:new).and_return(@user)
|
85
97
|
|
@@ -91,7 +103,7 @@ describe UsersController do
|
|
91
103
|
|
92
104
|
describe "if user is not allowed to sign up" do
|
93
105
|
it "should redirect to login_path" do
|
94
|
-
|
106
|
+
User.should_receive(:can_signup?).and_return(false)
|
95
107
|
|
96
108
|
get :new
|
97
109
|
response.should redirect_to(login_path)
|
@@ -102,14 +114,27 @@ describe UsersController do
|
|
102
114
|
# GET /users/1/edit AJAX
|
103
115
|
#----------------------------------------------------------------------------
|
104
116
|
describe "responding to GET edit" do
|
105
|
-
|
117
|
+
|
118
|
+
it "should expose current user as @user and render [edit] template" do
|
106
119
|
require_user
|
107
120
|
@user = current_user
|
121
|
+
xhr :get, :edit, :id => @user.id
|
122
|
+
assigns[:user].should == current_user
|
123
|
+
response.should render_template("users/edit")
|
108
124
|
end
|
109
125
|
|
110
|
-
it "should
|
126
|
+
it "should not allow current user to edit another user" do
|
127
|
+
@user = create(:user)
|
128
|
+
require_user
|
111
129
|
xhr :get, :edit, :id => @user.id
|
112
|
-
|
130
|
+
expect(response.body).to eql("window.location.reload();")
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should allow admin to edit another user" do
|
134
|
+
require_user(admin: true)
|
135
|
+
@user = create(:user)
|
136
|
+
xhr :get, :edit, :id => @user.id
|
137
|
+
assigns[:user].should == @user
|
113
138
|
response.should render_template("users/edit")
|
114
139
|
end
|
115
140
|
|
@@ -130,6 +155,7 @@ describe UsersController do
|
|
130
155
|
end
|
131
156
|
|
132
157
|
it "exposes a newly created user as @user and redirect to profile page" do
|
158
|
+
require_user(admin: true)
|
133
159
|
post :create, :user => { :username => @username, :email => @email, :password => @password, :password_confirmation => @password }
|
134
160
|
assigns[:user].should == @user
|
135
161
|
flash[:notice].should =~ /welcome/
|
@@ -148,6 +174,7 @@ describe UsersController do
|
|
148
174
|
|
149
175
|
describe "with invalid params" do
|
150
176
|
it "assigns a newly created but unsaved user as @user and renders [new] template" do
|
177
|
+
require_user(admin: true)
|
151
178
|
@user = FactoryGirl.build(:user, :username => "", :email => "")
|
152
179
|
User.stub!(:new).and_return(@user)
|
153
180
|
|
@@ -292,8 +319,9 @@ describe UsersController do
|
|
292
319
|
describe "responding to PUT change_password" do
|
293
320
|
before(:each) do
|
294
321
|
require_user
|
295
|
-
|
296
|
-
@current_user_session.stub
|
322
|
+
User.stub(:find).and_return(current_user)
|
323
|
+
@current_user_session.stub(:unauthorized_record=).and_return(current_user)
|
324
|
+
@current_user_session.stub(:save).and_return(current_user)
|
297
325
|
@user = current_user
|
298
326
|
@new_password = "secret?!"
|
299
327
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Copyright (c) 2008-2014 Michael Dvorkin and contributors.
|
2
|
+
#
|
3
|
+
# Fat Free CRM is freely distributable under the terms of MIT license.
|
4
|
+
# See MIT-LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
5
|
+
#------------------------------------------------------------------------------
|
6
|
+
|
7
|
+
require 'spec_helper'
|
8
|
+
require 'fat_free_crm/secret_token_generator'
|
9
|
+
|
10
|
+
describe FatFreeCRM::SecretTokenGenerator do
|
11
|
+
|
12
|
+
let(:token) { 'e5a4b315c062dec4ecb40dabcde84fd6c067cb016a813702d2f4299ad16255c88ed1020bd47fb527e8e5f7052b04be1fbb8e63c043b8fb36f88d3c7d79a68681' }
|
13
|
+
|
14
|
+
describe "setup!" do
|
15
|
+
|
16
|
+
it "should not generate a token if one already exists" do
|
17
|
+
FatFreeCRM::SecretTokenGenerator.stub(:token).and_return(nil)
|
18
|
+
expect(FatFreeCRM::SecretTokenGenerator).to receive(:generate_and_persist_token!)
|
19
|
+
FatFreeCRM::Application.config.stub(:secret_token).and_return(token)
|
20
|
+
FatFreeCRM::SecretTokenGenerator.setup!
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should generate a token if none exists already" do
|
24
|
+
FatFreeCRM::SecretTokenGenerator.stub(:token).and_return(token)
|
25
|
+
expect(FatFreeCRM::SecretTokenGenerator).not_to receive(:generate_and_persist_token!)
|
26
|
+
FatFreeCRM::SecretTokenGenerator.setup!
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should raise an error if the token is still blank (should never happen)" do
|
30
|
+
FatFreeCRM::SecretTokenGenerator.stub(:token).and_return(nil)
|
31
|
+
lambda { FatFreeCRM::SecretTokenGenerator.setup! }.should raise_error(RuntimeError)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "token" do
|
37
|
+
|
38
|
+
it "should delegate to Setting" do
|
39
|
+
expect(Setting).to receive(:secret_token).and_return(token)
|
40
|
+
expect(FatFreeCRM::SecretTokenGenerator.send(:token)).to eql(token)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "generate_and_persist_token!" do
|
46
|
+
|
47
|
+
it "should generate a random token" do
|
48
|
+
expect(SecureRandom).to receive(:hex).with(64).and_return(token)
|
49
|
+
expect(Setting).to receive(:secret_token=).with(token)
|
50
|
+
FatFreeCRM::SecretTokenGenerator.send(:generate_and_persist_token!)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'cancan/matchers'
|
3
|
+
|
4
|
+
def all_actions
|
5
|
+
[:index, :show, :create, :update, :destroy, :manage]
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "User abilities" do
|
9
|
+
|
10
|
+
subject(:ability) { Ability.new(user) }
|
11
|
+
let(:subject_user) { create :user }
|
12
|
+
|
13
|
+
context "when site manager, I" do
|
14
|
+
let(:user) { create :user, admin: true}
|
15
|
+
all_actions.each do |do_action|
|
16
|
+
it{ should be_able_to(do_action, subject_user) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when myself, I" do
|
21
|
+
let(:user) { create :user }
|
22
|
+
let(:subject_user) { user }
|
23
|
+
all_actions.each do |do_action|
|
24
|
+
it{ should be_able_to(do_action, subject_user) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when another user, I" do
|
29
|
+
let(:user) { create :user }
|
30
|
+
let(:can) { [] }
|
31
|
+
let(:cannot) { [:show, :create, :update, :index, :destroy, :manage] }
|
32
|
+
it{ can.each do |do_action|
|
33
|
+
should be_able_to(do_action, subject_user)
|
34
|
+
end}
|
35
|
+
it{ cannot.each do |do_action|
|
36
|
+
should_not be_able_to(do_action, subject_user)
|
37
|
+
end}
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when anonymous user, I" do
|
41
|
+
let(:user) { nil }
|
42
|
+
let(:can) { [] }
|
43
|
+
let(:cannot) { [:show, :create, :update, :index, :destroy, :manage] }
|
44
|
+
it{ can.each do |do_action|
|
45
|
+
should be_able_to(do_action, subject_user)
|
46
|
+
end}
|
47
|
+
it{ cannot.each do |do_action|
|
48
|
+
should_not be_able_to(do_action, subject_user)
|
49
|
+
end}
|
50
|
+
|
51
|
+
it "and signup enabled" do
|
52
|
+
User.stub(:can_signup?).and_return(true)
|
53
|
+
should be_able_to(:create, User)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -11,7 +11,7 @@ require 'rspec/rails'
|
|
11
11
|
require 'capybara/rails'
|
12
12
|
|
13
13
|
require 'acts_as_fu'
|
14
|
-
require '
|
14
|
+
require 'factory_girl_rails'
|
15
15
|
require 'ffaker'
|
16
16
|
|
17
17
|
require 'coveralls'
|
@@ -38,6 +38,7 @@ RSpec.configure do |config|
|
|
38
38
|
|
39
39
|
# RSpec configuration options for Fat Free CRM.
|
40
40
|
config.include RSpec::Rails::Matchers
|
41
|
+
config.include(FactoryGirl::Syntax::Methods)
|
41
42
|
|
42
43
|
config.before(:each) do
|
43
44
|
# Overwrite locale settings within "config/settings.yml" if necessary.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fat_free_crm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Dvorkin
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2014-01-07 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rails
|
@@ -1052,6 +1052,7 @@ files:
|
|
1052
1052
|
- lib/fat_free_crm/plugin.rb
|
1053
1053
|
- lib/fat_free_crm/plugin_dependencies.rb
|
1054
1054
|
- lib/fat_free_crm/renderers.rb
|
1055
|
+
- lib/fat_free_crm/secret_token_generator.rb
|
1055
1056
|
- lib/fat_free_crm/sortable.rb
|
1056
1057
|
- lib/fat_free_crm/tabs.rb
|
1057
1058
|
- lib/fat_free_crm/version.rb
|
@@ -1171,6 +1172,7 @@ files:
|
|
1171
1172
|
- spec/lib/mail_processor/dropbox_spec.rb
|
1172
1173
|
- spec/lib/mail_processor/sample_emails/dropbox.rb
|
1173
1174
|
- spec/lib/permissions_spec.rb
|
1175
|
+
- spec/lib/secret_token_generator_spec.rb
|
1174
1176
|
- spec/lib/view_factory_spec.rb
|
1175
1177
|
- spec/mailers/subscription_mailer_spec.rb
|
1176
1178
|
- spec/mailers/user_mailer_spec.rb
|
@@ -1196,6 +1198,7 @@ files:
|
|
1196
1198
|
- spec/models/polymorphic/task_spec.rb
|
1197
1199
|
- spec/models/polymorphic/version_spec.rb
|
1198
1200
|
- spec/models/setting_spec.rb
|
1201
|
+
- spec/models/users/abilities/user_ability_spec.rb
|
1199
1202
|
- spec/models/users/authentication_spec.rb
|
1200
1203
|
- spec/models/users/group_spec.rb
|
1201
1204
|
- spec/models/users/permission_spec.rb
|