fat_free_crm 0.12.0 → 0.12.1
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 +9 -9
- data/Gemfile.lock +5 -3
- data/app/controllers/application_controller.rb +2 -0
- data/app/controllers/home_controller.rb +19 -12
- data/app/models/users/user.rb +8 -0
- data/config/initializers/secret_token.rb +1 -18
- data/config/routes.rb +1 -1
- data/lib/fat_free_crm/version.rb +1 -1
- data/lib/tasks/ffcrm/secret.rake +17 -0
- data/spec/controllers/home_controller_spec.rb +66 -15
- data/spec/models/users/user_spec.rb +14 -0
- data/spec/routing/users_routing_spec.rb +4 -5
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZWNmOGI2ODA3NzM3ZWY1ZDZlZjE5ZDE5YjhmNTU2YmQ3MmQzZDljZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
7
|
-
|
6
|
+
ODQyMGQ0NDFlNDBkMTU2OWVmYzY1ODMzMmJkYTY3ZjVjOTY0MTQxNQ==
|
7
|
+
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NmFhNTU0YmVkZTBhNjkwZWQ3ZTYxODAyOGVkOGQ3Zjc3MzdmNmVkMDRlNGYx
|
10
|
+
MjljM2UxZDk4ZjY4MWMwNzBjZDk1YWMyODVmYjk2OGE1ODA3NDgwMDA2ZTcy
|
11
|
+
ODEyNTI5MGZjZDY5YjZmNDZlNzY4MmM0YmFhNDRkMjAyMGM2OTE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZDllMDRjYmIyZjI5YTJhNWE3MmY0ZmRmNzA0N2FiYTY0M2ZiMmRhNjg1ODE4
|
14
|
+
YmM4ODQyY2VjMjAyMGE1YzkxYWVkYzVmZjJkMjU5YjVjNjUzZDQ0MDc4OWEx
|
15
|
+
M2ZlMjMzMTJkNmEzODQ0ZjA4ZjA4NmI1Y2U3MTJhNWE4ODAwNjg=
|
data/Gemfile.lock
CHANGED
@@ -132,7 +132,7 @@ GEM
|
|
132
132
|
thor (>= 0.14, < 2.0)
|
133
133
|
json (1.7.7)
|
134
134
|
kgio (2.7.4)
|
135
|
-
libv8 (3.
|
135
|
+
libv8 (3.16.14.3)
|
136
136
|
listen (0.7.3)
|
137
137
|
mail (2.5.3)
|
138
138
|
i18n (>= 0.4.0)
|
@@ -222,6 +222,7 @@ GEM
|
|
222
222
|
ffi (>= 0.5.0)
|
223
223
|
rdoc (3.12.2)
|
224
224
|
json (~> 1.4)
|
225
|
+
ref (1.0.5)
|
225
226
|
responds_to_parent (1.1.0)
|
226
227
|
rest-client (1.6.7)
|
227
228
|
mime-types (>= 1.16)
|
@@ -267,8 +268,9 @@ GEM
|
|
267
268
|
rack (~> 1.0)
|
268
269
|
tilt (~> 1.1, != 1.3.0)
|
269
270
|
sqlite3 (1.3.7)
|
270
|
-
therubyracer (0.
|
271
|
-
libv8 (~> 3.
|
271
|
+
therubyracer (0.12.0)
|
272
|
+
libv8 (~> 3.16.14.0)
|
273
|
+
ref
|
272
274
|
thin (1.5.0)
|
273
275
|
daemons (>= 1.0.9)
|
274
276
|
eventmachine (>= 0.12.6)
|
@@ -5,6 +5,8 @@
|
|
5
5
|
#------------------------------------------------------------------------------
|
6
6
|
class ApplicationController < ActionController::Base
|
7
7
|
|
8
|
+
protect_from_forgery
|
9
|
+
|
8
10
|
before_filter :set_context
|
9
11
|
before_filter :clear_setting_cache
|
10
12
|
before_filter "hook(:app_before_filter, self)"
|
@@ -58,14 +58,19 @@ class HomeController < ApplicationController
|
|
58
58
|
# GET /home/timeline AJAX
|
59
59
|
#----------------------------------------------------------------------------
|
60
60
|
def timeline
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
61
|
+
state = params[:state].to_s
|
62
|
+
if %w(Collapsed Expanded).include?(state)
|
63
|
+
if (model_type = params[:type].to_s).present?
|
64
|
+
if %w(comment email).include?(model_type)
|
65
|
+
model = model_type.camelize.constantize
|
66
|
+
item = model.find(params[:id])
|
67
|
+
item.update_attribute(:state, state)
|
68
|
+
end
|
69
|
+
else
|
70
|
+
comments, emails = params[:id].split("+")
|
71
|
+
Comment.where(:id => comments.split(',')).update_all(:state => state) unless comments.blank?
|
72
|
+
Email.where(:id => emails.split(',')).update_all(:state => state) unless emails.blank?
|
73
|
+
end
|
69
74
|
end
|
70
75
|
|
71
76
|
render :nothing => true
|
@@ -118,6 +123,9 @@ class HomeController < ApplicationController
|
|
118
123
|
end
|
119
124
|
|
120
125
|
#----------------------------------------------------------------------------
|
126
|
+
# TODO: this is ugly, ugly code. It's being security patched now but urgently
|
127
|
+
# needs refactoring to use user id instead. Permuations based on name or email
|
128
|
+
# yield incorrect results.
|
121
129
|
def activity_user
|
122
130
|
user = current_user.pref[:activity_user]
|
123
131
|
if user && user != "all_users"
|
@@ -126,12 +134,11 @@ class HomeController < ApplicationController
|
|
126
134
|
else # first_name middle_name last_name any_name
|
127
135
|
name_query = if user.include?(" ")
|
128
136
|
user.name_permutations.map{ |first, last|
|
129
|
-
|
130
|
-
}.
|
137
|
+
User.where(:first_name => first, :last_name => last)
|
138
|
+
}.map(&:to_a).flatten.first
|
131
139
|
else
|
132
|
-
|
140
|
+
[User.where(:first_name => user), User.where(:last_name => user)].map(&:to_a).flatten.first
|
133
141
|
end
|
134
|
-
User.where(name_query).first
|
135
142
|
end
|
136
143
|
end
|
137
144
|
user.is_a?(User) ? user.id : nil
|
data/app/models/users/user.rb
CHANGED
@@ -146,6 +146,14 @@ class User < ActiveRecord::Base
|
|
146
146
|
super(value)
|
147
147
|
end
|
148
148
|
|
149
|
+
def to_json(options = nil)
|
150
|
+
[name].to_json
|
151
|
+
end
|
152
|
+
|
153
|
+
def to_xml(options = nil)
|
154
|
+
[name].to_xml
|
155
|
+
end
|
156
|
+
|
149
157
|
private
|
150
158
|
|
151
159
|
# Suspend newly created user if signup requires an approval.
|
@@ -1,18 +1 @@
|
|
1
|
-
|
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
|
-
# Be sure to restart your server when you modify this file.
|
7
|
-
|
8
|
-
# Your secret key for verifying the integrity of signed cookies.
|
9
|
-
# If you change this key, all old signed cookies will become invalid!
|
10
|
-
# Make sure the secret is at least 30 characters and all random,
|
11
|
-
# no regular words or you'll be exposed to dictionary attacks.
|
12
|
-
|
13
|
-
# PLEASE NOTE: This secret token must be changed in your fork of Fat Free CRM.
|
14
|
-
# This problem is mitigated when running Fat Free CRM as a Rails Engine.
|
15
|
-
|
16
|
-
if defined?(FatFreeCRM::Application)
|
17
|
-
FatFreeCRM::Application.config.secret_token = '51aa366864a80316a85cff0d3762347f4ae3d029d548bef034d56e82b1a2ffac5353ee6719d9b64e4354e2a0b1a901679f46a851c360a2ea377188e4b196b6b6'
|
18
|
-
end
|
1
|
+
FatFreeCRM::Application.config.secret_token = 'bb6810b6691d68fae269cfa4ce1805a5b4b0826e2680988e1102a4b3b80e5753af76d25a90f3ba7bc4c2fa68c4bce3b36df72baa18a0e35a71d3199918766db9'
|
data/config/routes.rb
CHANGED
data/lib/fat_free_crm/version.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
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
|
+
namespace :ffcrm do
|
8
|
+
|
9
|
+
desc "Generate a secret token for Rails to use."
|
10
|
+
task :secret do
|
11
|
+
require 'securerandom'
|
12
|
+
secret = SecureRandom.hex(64)
|
13
|
+
filename = File.join(Rails.root, 'config', 'initializers', 'secret_token.rb')
|
14
|
+
File.open(filename, 'w'){|f| f.puts "FatFreeCRM::Application.config.secret_token = '#{secret}'"}
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -42,13 +42,13 @@ describe HomeController do
|
|
42
42
|
assigns[:my_tasks].should == [task_1, task_2, task_3, task_4]
|
43
43
|
end
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
it "should not display completed tasks" do
|
46
|
+
task_1 = FactoryGirl.create(:task, :user_id => current_user.id, :name => "Your first task", :bucket => "due_asap", :assigned_to => current_user.id)
|
47
|
+
task_2 = FactoryGirl.create(:task, :user_id => current_user.id, :name => "Completed task", :bucket => "due_asap", :completed_at => 1.days.ago, :completed_by => current_user.id, :assigned_to => current_user.id)
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
get :index
|
50
|
+
assigns[:my_tasks].should == [task_1]
|
51
|
+
end
|
52
52
|
|
53
53
|
it "should get a list of my opportunities ordered by closes_on" do
|
54
54
|
opportunity_1 = FactoryGirl.create(:opportunity, :name => "Your first opportunity", :closes_on => 15.days.from_now, :assigned_to => current_user.id, :stage => 'proposal')
|
@@ -153,42 +153,93 @@ describe HomeController do
|
|
153
153
|
session[:hello].should == true
|
154
154
|
end
|
155
155
|
end
|
156
|
-
|
156
|
+
|
157
157
|
describe "activity_user" do
|
158
|
-
|
158
|
+
|
159
159
|
before(:each) do
|
160
160
|
@user = mock(User, :id => 1, :is_a? => true)
|
161
161
|
@cur_user = mock(User)
|
162
162
|
end
|
163
|
-
|
163
|
+
|
164
164
|
it "should find a user by email" do
|
165
165
|
@cur_user.stub!(:pref).and_return(:activity_user => 'billy@example.com')
|
166
166
|
controller.instance_variable_set(:@current_user, @cur_user)
|
167
167
|
User.should_receive(:where).with(:email => 'billy@example.com').and_return([@user])
|
168
168
|
controller.send(:activity_user).should == 1
|
169
169
|
end
|
170
|
-
|
170
|
+
|
171
171
|
it "should find a user by first name or last name" do
|
172
172
|
@cur_user.stub!(:pref).and_return(:activity_user => 'Billy')
|
173
173
|
controller.instance_variable_set(:@current_user, @cur_user)
|
174
|
-
User.should_receive(:where).with(
|
174
|
+
User.should_receive(:where).with(:first_name => 'Billy').and_return([@user])
|
175
|
+
User.should_receive(:where).with(:last_name => 'Billy').and_return([@user])
|
175
176
|
controller.send(:activity_user).should == 1
|
176
177
|
end
|
177
|
-
|
178
|
+
|
178
179
|
it "should find a user by first name and last name" do
|
179
180
|
@cur_user.stub!(:pref).and_return(:activity_user => 'Billy Elliot')
|
180
181
|
controller.instance_variable_set(:@current_user, @cur_user)
|
181
|
-
User.should_receive(:where).with(
|
182
|
+
User.should_receive(:where).with(:first_name => 'Billy', :last_name => "Elliot").and_return([@user])
|
183
|
+
User.should_receive(:where).with(:first_name => 'Elliot', :last_name => "Billy").and_return([@user])
|
182
184
|
controller.send(:activity_user).should == 1
|
183
185
|
end
|
184
|
-
|
186
|
+
|
185
187
|
it "should return nil when 'all_users' is specified" do
|
186
188
|
@cur_user.stub!(:pref).and_return(:activity_user => 'all_users')
|
187
189
|
controller.instance_variable_set(:@current_user, @cur_user)
|
188
190
|
User.should_not_receive(:where)
|
189
191
|
controller.send(:activity_user).should == nil
|
190
192
|
end
|
191
|
-
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
describe "timeline" do
|
197
|
+
|
198
|
+
before(:each) do
|
199
|
+
require_user
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should collapse all comments and emails on a specific contact" do
|
203
|
+
comment = double(Comment)
|
204
|
+
Comment.should_receive(:find).with("1").and_return(comment)
|
205
|
+
comment.should_receive(:update_attribute).with(:state, 'Collapsed')
|
206
|
+
xhr :get, :timeline, :type => "comment", :id => "1", :state => "Collapsed"
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should expand all comments and emails on a specific contact" do
|
210
|
+
comment = double(Comment)
|
211
|
+
Comment.should_receive(:find).with("1").and_return(comment)
|
212
|
+
comment.should_receive(:update_attribute).with(:state, 'Expanded')
|
213
|
+
xhr :get, :timeline, :type => "comment", :id => "1", :state => "Expanded"
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should not do anything when state neither Expanded nor Collapsed" do
|
217
|
+
comment = double(Comment)
|
218
|
+
Comment.should_not_receive(:find).with("1")
|
219
|
+
xhr :get, :timeline, :type => "comment", :id => "1", :state => "Explode"
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should collapse all comments and emails on Contact" do
|
223
|
+
where_stub = double
|
224
|
+
where_stub.should_receive(:update_all).with(:state => "Collapsed")
|
225
|
+
Comment.should_receive(:where).and_return(where_stub)
|
226
|
+
xhr :get, :timeline, :id => "1,2,3,4+", :state => "Collapsed"
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should not allow an arbitary state (sanitizes input)" do
|
230
|
+
where_stub = double
|
231
|
+
where_stub.should_receive(:update_all).with(:state => "Expanded")
|
232
|
+
Comment.should_receive(:where).and_return(where_stub)
|
233
|
+
xhr :get, :timeline, :id => "1,2,3,4+", :state => "Expanded"
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should not update an arbitary model (sanitizes input)" do
|
237
|
+
where_stub = double
|
238
|
+
where_stub.should_receive(:update_all).with(:state => "Expanded")
|
239
|
+
Comment.should_receive(:where).and_return(where_stub)
|
240
|
+
xhr :get, :timeline, :id => "1,2,3,4+", :state => "Expanded"
|
241
|
+
end
|
242
|
+
|
192
243
|
end
|
193
244
|
|
194
245
|
end
|
@@ -209,4 +209,18 @@ describe User do
|
|
209
209
|
@user.single_access_token.should == "token"
|
210
210
|
end
|
211
211
|
end
|
212
|
+
|
213
|
+
describe "serialization" do
|
214
|
+
|
215
|
+
let(:user) { FactoryGirl.build(:user) }
|
216
|
+
|
217
|
+
it "to json" do
|
218
|
+
expect(user.to_json).to eql([user.name].to_json)
|
219
|
+
end
|
220
|
+
|
221
|
+
it "to xml" do
|
222
|
+
expect(user.to_xml).to eql([user.name].to_xml)
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
212
226
|
end
|
@@ -8,8 +8,8 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
8
8
|
describe UsersController do
|
9
9
|
describe "routing" do
|
10
10
|
|
11
|
-
it "
|
12
|
-
{ :get => "/users" }.
|
11
|
+
it "doesn't recognize #index" do
|
12
|
+
{ :get => "/users" }.should_not be_routable
|
13
13
|
end
|
14
14
|
|
15
15
|
it "recognizes and generates #new as /signup" do
|
@@ -40,8 +40,8 @@ describe UsersController do
|
|
40
40
|
{ :put => "/opportunities/aaron" }.should_not be_routable
|
41
41
|
end
|
42
42
|
|
43
|
-
it "
|
44
|
-
{ :delete => "/users/1" }.
|
43
|
+
it "doesn't recognize #destroy" do
|
44
|
+
{ :delete => "/users/1" }.should_not be_routable
|
45
45
|
end
|
46
46
|
|
47
47
|
it "doesn't recognize #destroy with non-numeric id" do
|
@@ -81,4 +81,3 @@ describe UsersController do
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
84
|
-
|
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.1
|
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: 2013-
|
14
|
+
date: 2013-12-27 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: rails
|
@@ -1082,6 +1082,7 @@ files:
|
|
1082
1082
|
- lib/tasks/ffcrm/demo.rake
|
1083
1083
|
- lib/tasks/ffcrm/dropbox.rake
|
1084
1084
|
- lib/tasks/ffcrm/missing_translations.rake
|
1085
|
+
- lib/tasks/ffcrm/secret.rake
|
1085
1086
|
- lib/tasks/ffcrm/settings.rake
|
1086
1087
|
- lib/tasks/ffcrm/setup.rake
|
1087
1088
|
- lib/tasks/ffcrm/update_data.rake
|
@@ -1418,7 +1419,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1418
1419
|
version: '0'
|
1419
1420
|
requirements: []
|
1420
1421
|
rubyforge_project:
|
1421
|
-
rubygems_version: 2.
|
1422
|
+
rubygems_version: 2.1.11
|
1422
1423
|
signing_key:
|
1423
1424
|
specification_version: 4
|
1424
1425
|
summary: Fat Free CRM
|