fat_free_crm 0.12.0 → 0.12.1
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.
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
|