fat_free_crm 0.11.1 → 0.11.2

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.

Files changed (179) hide show
  1. data/Gemfile +30 -12
  2. data/Gemfile.lock +131 -119
  3. data/Procfile +1 -1
  4. data/README.md +1 -1
  5. data/app/assets/images/notifications.png +0 -0
  6. data/app/assets/javascripts/application.js.erb +3 -0
  7. data/app/assets/javascripts/crm_textarea_autocomplete.js +44 -0
  8. data/app/assets/stylesheets/application.css.erb +2 -0
  9. data/app/assets/stylesheets/common.scss +7 -11
  10. data/app/assets/stylesheets/textarea_autocomplete.scss +42 -0
  11. data/app/controllers/admin/application_controller.rb +5 -5
  12. data/app/controllers/admin/field_groups_controller.rb +11 -51
  13. data/app/controllers/admin/fields_controller.rb +13 -59
  14. data/app/controllers/admin/plugins_controller.rb +1 -4
  15. data/app/controllers/admin/settings_controller.rb +0 -4
  16. data/app/controllers/admin/tags_controller.rb +11 -66
  17. data/app/controllers/admin/users_controller.rb +20 -83
  18. data/app/controllers/application_controller.rb +83 -69
  19. data/app/controllers/comments_controller.rb +12 -29
  20. data/app/controllers/emails_controller.rb +1 -5
  21. data/app/controllers/entities/accounts_controller.rb +13 -32
  22. data/app/controllers/entities/campaigns_controller.rb +17 -32
  23. data/app/controllers/entities/contacts_controller.rb +20 -38
  24. data/app/controllers/entities/leads_controller.rb +33 -55
  25. data/app/controllers/entities/opportunities_controller.rb +26 -42
  26. data/app/controllers/entities_controller.rb +92 -83
  27. data/app/controllers/home_controller.rb +1 -10
  28. data/app/controllers/lists_controller.rb +1 -4
  29. data/app/controllers/{entities/tasks_controller.rb → tasks_controller.rb} +21 -32
  30. data/app/controllers/users_controller.rb +6 -5
  31. data/app/helpers/accounts_helper.rb +32 -9
  32. data/app/helpers/application_helper.rb +15 -1
  33. data/app/helpers/campaigns_helper.rb +1 -1
  34. data/app/helpers/comments_helper.rb +11 -1
  35. data/app/helpers/leads_helper.rb +1 -1
  36. data/app/helpers/opportunities_helper.rb +1 -1
  37. data/app/{models/mailers/notifier.rb → mailers/dropbox_mailer.rb} +5 -16
  38. data/app/mailers/subscription_mailer.rb +37 -0
  39. data/{lib/tasks/dropbox.rake → app/mailers/user_mailer.rb} +11 -13
  40. data/app/models/entities/account.rb +3 -1
  41. data/app/models/entities/campaign.rb +3 -1
  42. data/app/models/entities/contact.rb +3 -1
  43. data/app/models/entities/lead.rb +6 -5
  44. data/app/models/entities/opportunity.rb +3 -1
  45. data/app/models/fields/field.rb +1 -1
  46. data/app/models/polymorphic/comment.rb +34 -0
  47. data/app/models/{entities → polymorphic}/task.rb +16 -3
  48. data/app/models/setting.rb +15 -15
  49. data/app/models/users/ability.rb +12 -5
  50. data/app/models/users/user.rb +7 -2
  51. data/app/views/accounts/index.html.haml +1 -1
  52. data/app/views/accounts/index.js.rjs +1 -1
  53. data/app/views/admin/plugins/index.html.haml +1 -7
  54. data/app/views/{shared/auto_complete.html.haml → application/_auto_complete.html.haml} +0 -0
  55. data/app/views/{shared → application}/index.atom.builder +1 -1
  56. data/app/views/{shared → application}/index.rss.builder +1 -1
  57. data/app/views/campaigns/index.html.haml +1 -1
  58. data/app/views/campaigns/index.js.rjs +1 -1
  59. data/app/views/comments/_new.html.haml +6 -0
  60. data/app/views/comments/_subscription_links.html.haml +13 -0
  61. data/app/views/comments/new.js.rjs +2 -0
  62. data/app/views/contacts/_top_section.html.haml +3 -13
  63. data/app/views/contacts/index.html.haml +1 -1
  64. data/app/views/contacts/index.js.rjs +1 -1
  65. data/app/views/{notifier/dropbox_ack_notification.html.haml → dropbox_mailer/dropbox_notification.html.haml} +2 -2
  66. data/app/views/{shared → entities}/attach.js.rjs +1 -1
  67. data/app/views/entities/contacts.js.rjs +1 -1
  68. data/app/views/{shared/discard.rjs → entities/discard.js.rjs} +0 -0
  69. data/app/views/entities/leads.js.rjs +1 -1
  70. data/app/views/entities/opportunities.js.rjs +1 -1
  71. data/app/views/entities/subscription_update.js.rjs +4 -0
  72. data/app/views/entities/versions.js.rjs +1 -1
  73. data/app/views/layouts/_footer.html.haml +1 -1
  74. data/app/views/layouts/application.html.haml +3 -0
  75. data/app/views/leads/_contact.html.haml +1 -0
  76. data/app/views/leads/index.html.haml +1 -1
  77. data/app/views/leads/index.js.rjs +1 -1
  78. data/app/views/opportunities/_top_section.html.haml +4 -14
  79. data/app/views/opportunities/index.html.haml +1 -1
  80. data/app/views/opportunities/index.js.rjs +1 -1
  81. data/app/views/subscription_mailer/comment_notification.text.erb +7 -0
  82. data/app/views/{notifier → user_mailer}/password_reset_instructions.html.haml +0 -0
  83. data/config/application.rb +3 -1
  84. data/config/environments/development.rb +1 -1
  85. data/config/environments/test.rb +3 -0
  86. data/config/initializers/action_mailer.rb +8 -5
  87. data/config/initializers/cancan.rb +151 -0
  88. data/config/initializers/constants.rb +1 -0
  89. data/config/initializers/locale.rb +20 -0
  90. data/config/initializers/paper_trail.rb +4 -5
  91. data/config/initializers/relative_url_root.rb +0 -1
  92. data/config/initializers/squeel.rb +5 -0
  93. data/config/locales/cz_fat_free_crm.yml +3 -3
  94. data/config/locales/de.yml +2 -2
  95. data/config/locales/de_fat_free_crm.yml +651 -596
  96. data/config/locales/en-GB_fat_free_crm.yml +3 -3
  97. data/config/locales/en-US_fat_free_crm.yml +13 -3
  98. data/config/locales/es_fat_free_crm.yml +3 -3
  99. data/config/locales/fr-CA_fat_free_crm.yml +3 -3
  100. data/config/locales/fr_fat_free_crm.yml +3 -3
  101. data/config/locales/it_fat_free_crm.yml +3 -3
  102. data/config/locales/pl_fat_free_crm.yml +3 -3
  103. data/config/locales/pt-BR_fat_free_crm.yml +3 -3
  104. data/config/locales/ru_fat_free_crm.yml +3 -3
  105. data/config/locales/sv-SE_fat_free_crm.yml +3 -3
  106. data/config/locales/th_fat_free_crm.yml +3 -3
  107. data/config/routes.rb +10 -0
  108. data/config/settings.default.yml +29 -10
  109. data/config/unicorn.rb +4 -0
  110. data/db/migrate/20111201030535_add_field_groups_klass_name.rb +3 -1
  111. data/db/migrate/20120314080441_add_subscribed_users_to_entities.rb +23 -0
  112. data/db/migrate/20120405080727_change_subscribed_users_to_set.rb +24 -0
  113. data/db/migrate/20120405080742_change_further_subscribed_users_to_set.rb +27 -0
  114. data/db/migrate/20120413034923_add_index_on_versions_item_type.rb +5 -0
  115. data/db/schema.rb +109 -126
  116. data/fat_free_crm.gemspec +12 -18
  117. data/lib/fat_free_crm.rb +0 -1
  118. data/lib/fat_free_crm/core_ext/array.rb +1 -0
  119. data/lib/fat_free_crm/gem_dependencies.rb +1 -0
  120. data/lib/fat_free_crm/mail_processor/base.rb +226 -0
  121. data/lib/fat_free_crm/mail_processor/comment_replies.rb +86 -0
  122. data/lib/fat_free_crm/mail_processor/dropbox.rb +288 -0
  123. data/lib/fat_free_crm/permissions.rb +6 -19
  124. data/lib/fat_free_crm/renderers.rb +0 -8
  125. data/lib/fat_free_crm/tabs.rb +1 -1
  126. data/lib/fat_free_crm/version.rb +1 -1
  127. data/lib/plugins/country_select/lib/country_select.rb +2 -2
  128. data/lib/tasks/mail_processing.rake +60 -0
  129. data/spec/controllers/admin/users_controller_spec.rb +0 -2
  130. data/spec/controllers/{accounts_controller_spec.rb → entities/accounts_controller_spec.rb} +7 -9
  131. data/spec/controllers/{campaigns_controller_spec.rb → entities/campaigns_controller_spec.rb} +7 -7
  132. data/spec/controllers/{contacts_controller_spec.rb → entities/contacts_controller_spec.rb} +5 -9
  133. data/spec/controllers/{leads_controller_spec.rb → entities/leads_controller_spec.rb} +7 -9
  134. data/spec/controllers/{opportunities_controller_spec.rb → entities/opportunities_controller_spec.rb} +8 -15
  135. data/spec/controllers/tasks_controller_spec.rb +1 -5
  136. data/spec/controllers/users_controller_spec.rb +5 -9
  137. data/spec/factories/subscription_factories.rb +6 -0
  138. data/spec/lib/mail_processor/base_spec.rb +164 -0
  139. data/spec/lib/mail_processor/comment_replies_spec.rb +63 -0
  140. data/spec/lib/{dropbox_spec.rb → mail_processor/dropbox_spec.rb} +73 -181
  141. data/spec/lib/mail_processor/sample_emails/dropbox.rb +167 -0
  142. data/spec/mailers/subscription_mailer_spec.rb +17 -0
  143. data/spec/models/{base → entities}/account_contact_spec.rb +0 -0
  144. data/spec/models/{base → entities}/account_opportunity_spec.rb +0 -0
  145. data/spec/models/{base → entities}/account_spec.rb +4 -0
  146. data/spec/models/{base → entities}/campaign_spec.rb +4 -0
  147. data/spec/models/{base → entities}/contact_opportunity_spec.rb +0 -0
  148. data/spec/models/{base → entities}/contact_spec.rb +4 -0
  149. data/spec/models/{base → entities}/lead_spec.rb +4 -0
  150. data/spec/models/{base → entities}/opportunity_spec.rb +4 -0
  151. data/spec/models/polymorphic/comment_spec.rb +15 -0
  152. data/spec/models/{base → polymorphic}/task_spec.rb +124 -30
  153. data/spec/models/polymorphic/version_spec.rb +1 -1
  154. data/spec/shared/controllers.rb +5 -7
  155. data/spec/shared/models.rb +46 -0
  156. data/spec/spec_helper.rb +3 -4
  157. data/spec/support/mail_processor_mocks.rb +30 -0
  158. data/spec/support/uploaded_file.rb +3 -0
  159. data/spec/views/{common → application}/auto_complete.haml_spec.rb +1 -1
  160. data/vendor/assets/images/jquery-ui/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  161. data/vendor/assets/images/jquery-ui/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  162. data/vendor/assets/images/jquery-ui/ui-bg_flat_10_000000_40x100.png +0 -0
  163. data/vendor/assets/images/jquery-ui/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  164. data/vendor/assets/images/jquery-ui/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  165. data/vendor/assets/images/jquery-ui/ui-bg_glass_65_ffffff_1x400.png +0 -0
  166. data/vendor/assets/images/jquery-ui/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  167. data/vendor/assets/images/jquery-ui/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  168. data/vendor/assets/images/jquery-ui/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  169. data/vendor/assets/images/jquery-ui/ui-icons_222222_256x240.png +0 -0
  170. data/vendor/assets/images/jquery-ui/ui-icons_228ef1_256x240.png +0 -0
  171. data/vendor/assets/images/jquery-ui/ui-icons_ef8c08_256x240.png +0 -0
  172. data/vendor/assets/images/jquery-ui/ui-icons_ffd27a_256x240.png +0 -0
  173. data/vendor/assets/images/jquery-ui/ui-icons_ffffff_256x240.png +0 -0
  174. data/vendor/assets/javascripts/textarea_autocomplete.js +605 -0
  175. data/vendor/assets/stylesheets/jquery-ui.custom.css.erb +565 -0
  176. metadata +234 -154
  177. data/config/locales/simple_form.en.yml +0 -24
  178. data/lib/fat_free_crm/dropbox.rb +0 -439
  179. data/spec/lib/dropbox/email_samples.rb +0 -77
@@ -28,57 +28,51 @@ class LeadsController < EntitiesController
28
28
  # GET /leads/1
29
29
  #----------------------------------------------------------------------------
30
30
  def show
31
- @lead = Lead.my.find(params[:id])
32
-
33
31
  respond_with(@lead) do |format|
34
32
  format.html do
35
33
  @comment = Comment.new
36
34
  @timeline = timeline(@lead)
37
35
  end
38
36
  end
39
-
40
- rescue ActiveRecord::RecordNotFound
41
- respond_to_not_found(:html, :json, :xml)
42
37
  end
43
38
 
44
39
  # GET /leads/new
45
40
  #----------------------------------------------------------------------------
46
41
  def new
47
- @lead = Lead.new(:user => @current_user, :access => Setting.default_access)
42
+ @lead.attributes = {:user => @current_user, :access => Setting.default_access}
48
43
  @users = User.except(@current_user)
49
- @campaigns = Campaign.my.order("name")
44
+ get_campaigns
45
+
50
46
  if params[:related]
51
- model, id = params[:related].split("_")
52
- instance_variable_set("@#{model}", model.classify.constantize.my.find(id))
47
+ model, id = params[:related].split('_')
48
+ if related = model.classify.constantize.my.find_by_id(id)
49
+ instance_variable_set("@#{model}", related)
50
+ else
51
+ respond_to_related_not_found(model) and return
52
+ end
53
53
  end
54
- respond_with(@lead)
55
54
 
56
- rescue ActiveRecord::RecordNotFound # Kicks in if related asset was not found.
57
- respond_to_related_not_found(model, :js) if model
55
+ respond_with(@lead)
58
56
  end
59
57
 
60
58
  # GET /leads/1/edit AJAX
61
59
  #----------------------------------------------------------------------------
62
60
  def edit
63
- @lead = Lead.my.find(params[:id])
64
61
  @users = User.except(@current_user)
65
- @campaigns = Campaign.my.order("name")
62
+ get_campaigns
63
+
66
64
  if params[:previous].to_s =~ /(\d+)\z/
67
- @previous = Lead.my.find($1)
65
+ @previous = Lead.my.find_by_id($1) || $1.to_i
68
66
  end
69
- respond_with(@lead)
70
67
 
71
- rescue ActiveRecord::RecordNotFound
72
- @previous ||= $1.to_i
73
- respond_to_not_found(:js) unless @lead
68
+ respond_with(@lead)
74
69
  end
75
70
 
76
71
  # POST /leads
77
72
  #----------------------------------------------------------------------------
78
73
  def create
79
- @lead = Lead.new(params[:lead])
80
74
  @users = User.except(@current_user)
81
- @campaigns = Campaign.my.order("name")
75
+ get_campaigns
82
76
 
83
77
  respond_with(@lead) do |format|
84
78
  if @lead.save_with_permissions(params)
@@ -95,61 +89,48 @@ class LeadsController < EntitiesController
95
89
  # PUT /leads/1
96
90
  #----------------------------------------------------------------------------
97
91
  def update
98
- @lead = Lead.my.find(params[:id])
99
-
100
92
  respond_with(@lead) do |format|
101
93
  if @lead.update_with_permissions(params[:lead], params[:users])
102
94
  update_sidebar
103
95
  else
104
96
  @users = User.except(@current_user)
105
- @campaigns = Campaign.my.order("name")
97
+ @campaigns = Campaign.my.order('name')
106
98
  end
107
99
  end
108
-
109
- rescue ActiveRecord::RecordNotFound
110
- respond_to_not_found(:js, :json, :xml)
111
100
  end
112
101
 
113
102
  # DELETE /leads/1
114
103
  #----------------------------------------------------------------------------
115
104
  def destroy
116
- @lead = Lead.my.find(params[:id])
117
- @lead.destroy if @lead
105
+ @lead.destroy
118
106
 
119
107
  respond_with(@lead) do |format|
120
108
  format.html { respond_to_destroy(:html) }
121
109
  format.js { respond_to_destroy(:ajax) }
122
110
  end
123
-
124
- rescue ActiveRecord::RecordNotFound
125
- respond_to_not_found(:html, :js, :json, :xml)
126
111
  end
127
112
 
128
113
  # GET /leads/1/convert
129
114
  #----------------------------------------------------------------------------
130
115
  def convert
131
- @lead = Lead.my.find(params[:id])
132
116
  @users = User.except(@current_user)
133
117
  @account = Account.new(:user => @current_user, :name => @lead.company, :access => "Lead")
134
- @accounts = Account.my.order("name")
118
+ @accounts = Account.my.order('name')
135
119
  @opportunity = Opportunity.new(:user => @current_user, :access => "Lead", :stage => "prospecting", :campaign => @lead.campaign, :source => @lead.source)
120
+
136
121
  if params[:previous].to_s =~ /(\d+)\z/
137
- @previous = Lead.my.find($1)
122
+ @previous = Lead.my.find_by_id($1) || $1.to_i
138
123
  end
139
- respond_with(@lead)
140
124
 
141
- rescue ActiveRecord::RecordNotFound
142
- @previous ||= $1.to_i
143
- respond_to_not_found(:js, :json, :xml) unless @lead
125
+ respond_with(@lead)
144
126
  end
145
127
 
146
128
  # PUT /leads/1/promote
147
129
  #----------------------------------------------------------------------------
148
130
  def promote
149
- @lead = Lead.my.find(params[:id])
150
131
  @users = User.except(@current_user)
151
132
  @account, @opportunity, @contact = @lead.promote(params)
152
- @accounts = Account.my.order("name")
133
+ @accounts = Account.my.order('name')
153
134
  @stage = Setting.unroll(:opportunity_stage)
154
135
 
155
136
  respond_with(@lead) do |format|
@@ -161,33 +142,26 @@ class LeadsController < EntitiesController
161
142
  format.xml { render :xml => @account.errors + @opportunity.errors + @contact.errors, :status => :unprocessable_entity }
162
143
  end
163
144
  end
164
-
165
- rescue ActiveRecord::RecordNotFound
166
- respond_to_not_found(:js, :json, :xml)
167
145
  end
168
146
 
169
147
  # PUT /leads/1/reject
170
148
  #----------------------------------------------------------------------------
171
149
  def reject
172
- @lead = Lead.my.find(params[:id])
173
- @lead.reject if @lead
150
+ @lead.reject
174
151
  update_sidebar
175
152
 
176
153
  respond_with(@lead) do |format|
177
154
  format.html { flash[:notice] = t(:msg_asset_rejected, @lead.full_name); redirect_to leads_path }
178
155
  end
179
-
180
- rescue ActiveRecord::RecordNotFound
181
- respond_to_not_found(:html, :js, :json, :xml)
182
156
  end
183
157
 
184
158
  # PUT /leads/1/attach
185
159
  #----------------------------------------------------------------------------
186
- # Handled by ApplicationController :attach
160
+ # Handled by EntitiesController :attach
187
161
 
188
162
  # POST /leads/1/discard
189
163
  #----------------------------------------------------------------------------
190
- # Handled by ApplicationController :discard
164
+ # Handled by EntitiesController :discard
191
165
 
192
166
  # POST /leads/auto_complete/query AJAX
193
167
  #----------------------------------------------------------------------------
@@ -229,15 +203,19 @@ class LeadsController < EntitiesController
229
203
  # POST /leads/filter AJAX
230
204
  #----------------------------------------------------------------------------
231
205
  def filter
232
- session[:filter_by_lead_status] = params[:status]
206
+ session[:leads_filter] = params[:status]
233
207
  @leads = get_leads(:page => 1) # Start one the first page.
234
208
  render :index
235
209
  end
236
210
 
237
- private
211
+ private
212
+
213
+ #----------------------------------------------------------------------------
214
+ alias :get_leads :get_list_of_records
215
+
238
216
  #----------------------------------------------------------------------------
239
- def get_leads(options = {})
240
- get_list_of_records(Lead, options.merge!(:filter => :filter_by_lead_status))
217
+ def get_campaigns
218
+ @campaigns = Campaign.my.order('name')
241
219
  end
242
220
 
243
221
  #----------------------------------------------------------------------------
@@ -18,7 +18,7 @@
18
18
  class OpportunitiesController < EntitiesController
19
19
  before_filter :load_settings
20
20
  before_filter :get_data_for_sidebar, :only => :index
21
- before_filter :set_params, :only => [:index, :redraw, :filter]
21
+ before_filter :set_params, :only => [ :index, :redraw, :filter ]
22
22
 
23
23
  # GET /opportunities
24
24
  #----------------------------------------------------------------------------
@@ -30,58 +30,51 @@ class OpportunitiesController < EntitiesController
30
30
  # GET /opportunities/1
31
31
  #----------------------------------------------------------------------------
32
32
  def show
33
- @opportunity = Opportunity.my.find(params[:id])
34
-
35
33
  respond_with(@opportunity) do |format|
36
34
  format.html do
37
35
  @comment = Comment.new
38
36
  @timeline = timeline(@opportunity)
39
37
  end
40
38
  end
41
-
42
- rescue ActiveRecord::RecordNotFound
43
- respond_to_not_found(:html, :json, :xml)
44
39
  end
45
40
 
46
41
  # GET /opportunities/new
47
42
  #----------------------------------------------------------------------------
48
43
  def new
49
- @opportunity = Opportunity.new(:user => @current_user, :stage => "prospecting", :access => Setting.default_access)
44
+ @opportunity.attributes = {:user => @current_user, :stage => "prospecting", :access => Setting.default_access}
50
45
  @users = User.except(@current_user)
51
- @account = Account.new(:user => @current_user)
52
- @accounts = Account.my.order("name")
46
+ @account = Account.new(:user => @current_user, :access => Setting.default_access)
47
+ @accounts = Account.my.order('name')
48
+
53
49
  if params[:related]
54
- model, id = params[:related].split("_")
55
- instance_variable_set("@#{model}", model.classify.constantize.my.find(id))
50
+ model, id = params[:related].split('_')
51
+ if related = model.classify.constantize.my.find_by_id(id)
52
+ instance_variable_set("@#{model}", related)
53
+ else
54
+ respond_to_related_not_found(model) and return
55
+ end
56
56
  end
57
- respond_with(@opportunity)
58
57
 
59
- rescue ActiveRecord::RecordNotFound # Kicks in if related asset was not found.
60
- respond_to_related_not_found(model, :js) if model
58
+ respond_with(@opportunity)
61
59
  end
62
60
 
63
61
  # GET /opportunities/1/edit AJAX
64
62
  #----------------------------------------------------------------------------
65
63
  def edit
66
- @opportunity = Opportunity.my.find(params[:id])
67
64
  @users = User.except(@current_user)
68
65
  @account = @opportunity.account || Account.new(:user => @current_user)
69
- @accounts = Account.my.order("name")
66
+ @accounts = Account.my.order('name')
67
+
70
68
  if params[:previous].to_s =~ /(\d+)\z/
71
- @previous = Opportunity.my.find($1)
69
+ @previous = Opportunity.my.find_by_id($1) || $1.to_i
72
70
  end
73
- respond_with(@opportunity)
74
71
 
75
- rescue ActiveRecord::RecordNotFound
76
- @previous ||= $1.to_i
77
- respond_to_not_found(:js) unless @opportunity
72
+ respond_with(@opportunity)
78
73
  end
79
74
 
80
75
  # POST /opportunities
81
76
  #----------------------------------------------------------------------------
82
77
  def create
83
- @opportunity = Opportunity.new(params[:opportunity])
84
-
85
78
  respond_with(@opportunity) do |format|
86
79
  if @opportunity.save_with_account_and_permissions(params)
87
80
  if called_from_index_page?
@@ -94,7 +87,7 @@ class OpportunitiesController < EntitiesController
94
87
  end
95
88
  else
96
89
  @users = User.except(@current_user)
97
- @accounts = Account.my.order("name")
90
+ @accounts = Account.my.order('name')
98
91
  unless params[:account][:id].blank?
99
92
  @account = Account.find(params[:account][:id])
100
93
  else
@@ -113,8 +106,6 @@ class OpportunitiesController < EntitiesController
113
106
  # PUT /opportunities/1
114
107
  #----------------------------------------------------------------------------
115
108
  def update
116
- @opportunity = Opportunity.my.find(params[:id])
117
-
118
109
  respond_with(@opportunity) do |format|
119
110
  if @opportunity.update_with_account_and_permissions(params)
120
111
  if called_from_index_page?
@@ -126,7 +117,7 @@ class OpportunitiesController < EntitiesController
126
117
  end
127
118
  else
128
119
  @users = User.except(@current_user)
129
- @accounts = Account.my.order("name")
120
+ @accounts = Account.my.order('name')
130
121
  if @opportunity.account
131
122
  @account = Account.find(@opportunity.account.id)
132
123
  else
@@ -134,38 +125,31 @@ class OpportunitiesController < EntitiesController
134
125
  end
135
126
  end
136
127
  end
137
-
138
- rescue ActiveRecord::RecordNotFound
139
- respond_to_not_found(:js, :json, :xml)
140
128
  end
141
129
 
142
130
  # DELETE /opportunities/1
143
131
  #----------------------------------------------------------------------------
144
132
  def destroy
145
- @opportunity = Opportunity.my.find(params[:id])
146
133
  if called_from_landing_page?(:accounts)
147
134
  @account = @opportunity.account # Reload related account if any.
148
135
  elsif called_from_landing_page?(:campaigns)
149
136
  @campaign = @opportunity.campaign # Reload related campaign if any.
150
137
  end
151
- @opportunity.destroy if @opportunity
138
+ @opportunity.destroy
152
139
 
153
140
  respond_with(@opportunity) do |format|
154
141
  format.html { respond_to_destroy(:html) }
155
142
  format.js { respond_to_destroy(:ajax) }
156
143
  end
157
-
158
- rescue ActiveRecord::RecordNotFound
159
- respond_to_not_found(:html, :js, :json, :xml)
160
144
  end
161
145
 
162
146
  # PUT /opportunities/1/attach
163
147
  #----------------------------------------------------------------------------
164
- # Handled by ApplicationController :attach
148
+ # Handled by EntitiesController :attach
165
149
 
166
150
  # POST /opportunities/1/discard
167
151
  #----------------------------------------------------------------------------
168
- # Handled by ApplicationController :discard
152
+ # Handled by EntitiesController :discard
169
153
 
170
154
  # POST /opportunities/auto_complete/query AJAX
171
155
  #----------------------------------------------------------------------------
@@ -195,11 +179,10 @@ class OpportunitiesController < EntitiesController
195
179
  render :index
196
180
  end
197
181
 
198
- private
182
+ private
183
+
199
184
  #----------------------------------------------------------------------------
200
- def get_opportunities(options = {})
201
- get_list_of_records(Opportunity, options.merge!(:filter => :filter_by_opportunity_stage))
202
- end
185
+ alias :get_opportunities :get_list_of_records
203
186
 
204
187
  #----------------------------------------------------------------------------
205
188
  def respond_to_destroy(method)
@@ -241,10 +224,11 @@ class OpportunitiesController < EntitiesController
241
224
  @stage = Setting.unroll(:opportunity_stage)
242
225
  end
243
226
 
227
+ #----------------------------------------------------------------------------
244
228
  def set_params
245
229
  @current_user.pref[:opportunities_per_page] = params[:per_page] if params[:per_page]
246
230
  @current_user.pref[:opportunities_outline] = params[:outline] if params[:outline]
247
231
  @current_user.pref[:opportunities_sort_by] = Opportunity::sort_by_map[params[:sort_by]] if params[:sort_by]
248
- session[:filter_by_opportunity_stage] = params[:stage] if params[:stage]
232
+ session[:opportunities_filter] = params[:stage] if params[:stage]
249
233
  end
250
234
  end
@@ -18,119 +18,105 @@
18
18
  class EntitiesController < ApplicationController
19
19
  before_filter :require_user
20
20
  before_filter :set_current_tab, :only => [ :index, :show ]
21
- after_filter :update_recently_viewed, :only => :show
22
21
 
23
- respond_to :html, :only => [ :index, :show, :auto_complete ]
24
- respond_to :js
25
- respond_to :json, :xml, :except => :edit
26
- respond_to :atom, :csv, :rss, :xls, :only => :index
22
+ load_and_authorize_resource
27
23
 
28
- helper_method :search
24
+ after_filter :update_recently_viewed, :only => :show
29
25
 
30
- # Common auto_complete handler for all core controllers.
31
- #----------------------------------------------------------------------------
32
- def auto_complete
33
- @query = params[:auto_complete_query]
34
- @auto_complete = hook(:auto_complete, self, :query => @query, :user => @current_user)
35
- if @auto_complete.empty?
36
- @auto_complete = klass.my.text_search(@query).limit(10)
37
- else
38
- @auto_complete = @auto_complete.last
39
- end
40
- session[:auto_complete] = controller_name.to_sym
41
- respond_to do |format|
42
- format.any(:js, :html) { render "shared/auto_complete", :layout => nil }
43
- format.json { render :json => @auto_complete.inject({}){|h,a| h[a.id] = a.name; h } }
44
- end
45
- end
26
+ helper_method :entity, :entities, :search
46
27
 
47
28
  # Common attach handler for all core controllers.
48
29
  #----------------------------------------------------------------------------
49
30
  def attach
50
- model = klass.my.find(params[:id])
51
31
  @attachment = params[:assets].classify.constantize.find(params[:asset_id])
52
- @attached = model.attach!(@attachment)
53
- @account = model.reload if model.is_a?(Account)
54
- @campaign = model.reload if model.is_a?(Campaign)
55
-
56
- respond_to do |format|
57
- format.js { render "shared/attach" }
58
- format.json { render :json => model.reload }
59
- format.xml { render :xml => model.reload }
60
- end
32
+ @attached = entity.attach!(@attachment)
33
+ entity.reload
61
34
 
62
- rescue ActiveRecord::RecordNotFound
63
- respond_to_not_found(:html, :js, :json, :xml)
35
+ respond_with(entity)
64
36
  end
65
37
 
66
38
  # Common discard handler for all core controllers.
67
39
  #----------------------------------------------------------------------------
68
40
  def discard
69
- model = klass.my.find(params[:id])
70
41
  @attachment = params[:attachment].constantize.find(params[:attachment_id])
71
- model.discard!(@attachment)
72
- @account = model.reload if model.is_a?(Account)
73
- @campaign = model.reload if model.is_a?(Campaign)
74
-
75
- respond_to do |format|
76
- format.js { render "shared/discard" }
77
- format.json { render :json => model.reload }
78
- format.xml { render :xml => model.reload }
42
+ entity.discard!(@attachment)
43
+ entity.reload
44
+
45
+ respond_with(entity)
46
+ end
47
+
48
+ # Common subscribe handler for all core controllers.
49
+ #----------------------------------------------------------------------------
50
+ def subscribe
51
+ entity.subscribed_users += [current_user.id]
52
+ entity.save
53
+
54
+ respond_with(entity) do |format|
55
+ format.js { render 'subscription_update' }
79
56
  end
57
+ end
80
58
 
81
- rescue ActiveRecord::RecordNotFound
82
- respond_to_not_found(:html, :js, :json, :xml)
59
+ # Common unsubscribe handler for all core controllers.
60
+ #----------------------------------------------------------------------------
61
+ def unsubscribe
62
+ entity.subscribed_users -= [current_user.id]
63
+ entity.save
64
+
65
+ respond_with(entity) do |format|
66
+ format.js { render 'subscription_update' }
67
+ end
83
68
  end
84
69
 
85
70
  # GET /entities/contacts AJAX
86
71
  #----------------------------------------------------------------------------
87
72
  def contacts
88
- @entity = klass.my.find(params[:id])
89
73
  end
90
74
 
91
75
  # GET /entities/leads AJAX
92
76
  #----------------------------------------------------------------------------
93
77
  def leads
94
- @entity = klass.my.find(params[:id])
95
78
  end
96
79
 
97
80
  # GET /entities/opportunities AJAX
98
81
  #----------------------------------------------------------------------------
99
82
  def opportunities
100
- @entity = klass.my.find(params[:id])
101
83
  end
102
84
 
103
85
  # GET /entities/versions AJAX
104
86
  #----------------------------------------------------------------------------
105
87
  def versions
106
- @entity = klass.my.find(params[:id])
107
88
  end
108
89
 
109
- def timeline(asset)
110
- (asset.comments + asset.emails).sort { |x, y| y.created_at <=> x.created_at }
90
+ protected
91
+
92
+ #----------------------------------------------------------------------------
93
+ def entity=(entity)
94
+ instance_variable_set("@#{controller_name.singularize}", entity)
111
95
  end
112
96
 
113
- # Controller instance method that responds to /controlled/tagged/tag request.
114
- # It stores given tag as current query and redirect to index to display all
115
- # records tagged with the tag.
116
97
  #----------------------------------------------------------------------------
117
- def tagged
118
- self.send(:current_query=, "#" << params[:id]) unless params[:id].blank?
119
- redirect_to :action => "index"
98
+ def entity
99
+ instance_variable_get("@#{controller_name.singularize}")
120
100
  end
121
101
 
122
- def field_group
123
- if @tag = Tag.find_by_name(params[:tag].strip)
124
- if @field_group = FieldGroup.find_by_tag_id_and_klass_name(@tag.id, klass.to_s)
125
- @asset = klass.find_by_id(params[:asset_id]) || klass.new
126
- render 'fields/group' and return
127
- end
128
- end
129
- render :text => ''
102
+ #----------------------------------------------------------------------------
103
+ def entities=(entities)
104
+ instance_variable_set("@#{controller_name}", entities)
130
105
  end
131
106
 
132
- private
107
+ #----------------------------------------------------------------------------
108
+ def entities
109
+ instance_variable_get("@#{controller_name}") || klass.my
110
+ end
133
111
 
112
+ private
113
+
114
+ #----------------------------------------------------------------------------
115
+ def get_users
116
+ @users ||= User.except(current_user)
117
+ end
118
+
119
+ #----------------------------------------------------------------------------
134
120
  def search
135
121
  @search ||= begin
136
122
  search = klass.search(params[:q])
@@ -141,46 +127,69 @@ class EntitiesController < ApplicationController
141
127
 
142
128
  # Get list of records for a given model class.
143
129
  #----------------------------------------------------------------------------
144
- def get_list_of_records(klass, options = {})
145
- items = klass.name.tableize
130
+ def get_list_of_records(options = {})
146
131
  options[:query] ||= params[:query] if params[:query]
147
132
  self.current_page = options[:page] if options[:page]
148
133
  query, tags = parse_query_and_tags(options[:query]) if options[:query]
149
134
  self.current_query = query
150
135
 
151
- records = {
152
- :user => current_user,
153
- :order => current_user.pref[:"#{items}_sort_by"] || klass.sort_by
154
- }
136
+ order = current_user.pref[:"#{controller_name}_sort_by"] || klass.sort_by
137
+
155
138
  pages = {
156
139
  :page => current_page,
157
- :per_page => current_user.pref[:"#{items}_per_page"]
140
+ :per_page => current_user.pref[:"#{controller_name}_per_page"]
158
141
  }
159
142
 
160
- # Call the hook and return its output if any.
161
- assets = hook(:"get_#{items}", self, :records => records, :pages => pages)
162
- return assets.last unless assets.empty?
163
-
164
143
  # Use default processing if no hooks are present. Note that comma-delimited
165
144
  # export includes deleted records, and the pagination is enabled only for
166
145
  # plain HTTP, Ajax and XML API requests.
167
146
  wants = request.format
168
- filter = session[options[:filter]].to_s.split(',') if options[:filter]
147
+ filter = session[:"#{controller_name}_filter"].to_s.split(',')
169
148
 
170
- scope = klass.my(records)
171
- scope = scope.merge(search.result)
149
+ scope = entities.merge(search.result)
172
150
  scope = scope.state(filter) if filter.present?
173
151
  scope = scope.text_search(query) if query.present?
174
152
  scope = scope.tagged_with(tags, :on => :tags) if tags.present?
175
- scope = scope.unscoped if wants.csv?
153
+ scope = scope.order(order)
176
154
  scope = scope.paginate(pages) if wants.html? || wants.js? || wants.xml?
177
155
  scope
178
156
  end
179
157
 
180
158
  #----------------------------------------------------------------------------
181
159
  def update_recently_viewed
182
- if item = instance_variable_get("@#{controller_name.singularize}")
183
- item.send(item.class.versions_association_name).create(:event => :view, :whodunnit => PaperTrail.whodunnit)
160
+ entity.versions.create(:event => :view, :whodunnit => PaperTrail.whodunnit)
161
+ end
162
+
163
+ #----------------------------------------------------------------------------
164
+ def field_group
165
+ if @tag = Tag.find_by_name(params[:tag].strip)
166
+ if @field_group = FieldGroup.find_by_tag_id_and_klass_name(@tag.id, klass.to_s)
167
+ @asset = klass.find_by_id(params[:asset_id]) || klass.new
168
+ render 'fields/group' and return
169
+ end
170
+ end
171
+ render :text => ''
172
+ end
173
+
174
+ # Somewhat simplistic parser that extracts query and hash-prefixed tags from
175
+ # the search string and returns them as two element array, for example:
176
+ #
177
+ # "#real Billy Bones #pirate" => [ "Billy Bones", "real, pirate" ]
178
+ #----------------------------------------------------------------------------
179
+ def parse_query_and_tags(search_string)
180
+ query, tags = [], []
181
+ search_string.scan(/[\w@\-\.#]+/).each do |token|
182
+ if token.starts_with?("#")
183
+ tags << token[1 .. -1]
184
+ else
185
+ query << token
186
+ end
184
187
  end
188
+ [ query.join(" "), tags.join(", ") ]
189
+ end
190
+
191
+ #----------------------------------------------------------------------------
192
+ def timeline(asset)
193
+ (asset.comments + asset.emails).sort { |x, y| y.created_at <=> x.created_at }
185
194
  end
186
195
  end