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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NjYzZTU1ZTMxNGUyNGI2M2FkNjExNjdlOTI0MDZjYzg0YmM5NTE5MA==
4
+ ZWNmOGI2ODA3NzM3ZWY1ZDZlZjE5ZDE5YjhmNTU2YmQ3MmQzZDljZQ==
5
5
  data.tar.gz: !binary |-
6
- YjM0ZjE0ZDhjNjQxMTIxYmZjZTJiY2MyMzE3ZDA2MjRlYmU2ZDdlMg==
7
- !binary "U0hBNTEy":
6
+ ODQyMGQ0NDFlNDBkMTU2OWVmYzY1ODMzMmJkYTY3ZjVjOTY0MTQxNQ==
7
+ SHA512:
8
8
  metadata.gz: !binary |-
9
- OGY4M2Y1ZjQ4NGZkMDRhNWRiMTlmMTc2MjM5YWJhMmRlOWNlN2E1MjU1Njg2
10
- YWZkNzU3ZmVlNDUxMmIxMGRmYmYxYTA1NGU2NzI0MDIyZjZkNzQ3NDYwZDBk
11
- ZWYwMjE2NWIxYzgwYjhiZWM5MjYwYjMzYjNjZDkyYjBmNDY4NWQ=
9
+ NmFhNTU0YmVkZTBhNjkwZWQ3ZTYxODAyOGVkOGQ3Zjc3MzdmNmVkMDRlNGYx
10
+ MjljM2UxZDk4ZjY4MWMwNzBjZDk1YWMyODVmYjk2OGE1ODA3NDgwMDA2ZTcy
11
+ ODEyNTI5MGZjZDY5YjZmNDZlNzY4MmM0YmFhNDRkMjAyMGM2OTE=
12
12
  data.tar.gz: !binary |-
13
- Yzc4OTkwOTgyOWI1NjNkODc4MzY5YjVjODc3MWJjZDhjM2M4YTBjOWMwZjMy
14
- ZjdiZWYzNjU2YjM1YWM3YjkzYzgxZDUxMjZiYjgwNjM4NmQ2MmFiYzBlNWMx
15
- MzAwMTllYTRjNmJlNmRmYjI1NzY4YWNkZjhhZjcxMGMwYWM2ODc=
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.3.10.4)
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.10.1)
271
- libv8 (~> 3.3.10)
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
- unless params[:type].empty?
62
- model = params[:type].camelize.constantize
63
- item = model.find(params[:id])
64
- item.update_attribute(:state, params[:state])
65
- else
66
- comments, emails = params[:id].split("+")
67
- Comment.update_all("state = '#{params[:state]}'", "id IN (#{comments})") unless comments.blank?
68
- Email.update_all("state = '#{params[:state]}'", "id IN (#{emails})") unless emails.blank?
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
- "(upper(first_name) LIKE upper('%#{first}%') AND upper(last_name) LIKE upper('%#{last}%'))"
130
- }.join(" OR ")
137
+ User.where(:first_name => first, :last_name => last)
138
+ }.map(&:to_a).flatten.first
131
139
  else
132
- "upper(first_name) LIKE upper('%#{user}%') OR upper(last_name) LIKE upper('%#{user}%')"
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
@@ -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
- # 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
- # 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
@@ -137,7 +137,7 @@ Rails.application.routes.draw do
137
137
  end
138
138
  end
139
139
 
140
- resources :users, :id => /\d+/ do
140
+ resources :users, :id => /\d+/, :except => [:index, :destroy] do
141
141
  member do
142
142
  get :avatar
143
143
  get :password
@@ -7,7 +7,7 @@ module FatFreeCRM
7
7
  module VERSION #:nodoc:
8
8
  MAJOR = 0
9
9
  MINOR = 12
10
- TINY = 0
10
+ TINY = 1
11
11
  PRE = nil
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
@@ -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
- 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)
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
- get :index
50
- assigns[:my_tasks].should == [task_1]
51
- end
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("upper(first_name) LIKE upper('%Billy%') OR upper(last_name) LIKE upper('%Billy%')").and_return([@user])
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("(upper(first_name) LIKE upper('%Billy%') AND upper(last_name) LIKE upper('%Elliot%')) OR (upper(first_name) LIKE upper('%Elliot%') AND upper(last_name) LIKE upper('%Billy%'))").and_return([@user])
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 "recognizes and generates #index" do
12
- { :get => "/users" }.should route_to(:controller => "users", :action => "index")
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 "recognizes and generates #destroy" do
44
- { :delete => "/users/1" }.should route_to(:controller => "users", :action => "destroy", :id => "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.0
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-06-28 00:00:00.000000000 Z
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.0.3
1422
+ rubygems_version: 2.1.11
1422
1423
  signing_key:
1423
1424
  specification_version: 4
1424
1425
  summary: Fat Free CRM