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
@@ -1,24 +0,0 @@
1
- en:
2
- simple_form:
3
- "yes": 'Yes'
4
- "no": 'No'
5
- required:
6
- text: 'required'
7
- mark: '*'
8
- # You can uncomment the line below if you need to overwrite the whole required html.
9
- # When using html, text and mark won't be used.
10
- # html: '<abbr title="required">*</abbr>'
11
- error_notification:
12
- default_message: "Some errors were found, please take a look:"
13
- # Labels and hints examples
14
- # labels:
15
- # password: 'Password'
16
- # user:
17
- # new:
18
- # email: 'E-mail para efetuar o sign in.'
19
- # edit:
20
- # email: 'E-mail.'
21
- # hints:
22
- # username: 'User name to sign in.'
23
- # password: 'No special characters, please.'
24
-
@@ -1,439 +0,0 @@
1
- # Fat Free CRM
2
- # Copyright (C) 2008-2011 by Michael Dvorkin
3
- #
4
- # This program is free software: you can redistribute it and/or modify
5
- # it under the terms of the GNU Affero General Public License as published by
6
- # the Free Software Foundation, either version 3 of the License, or
7
- # (at your option) any later version.
8
- #
9
- # This program is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU Affero General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU Affero General Public License
15
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
- #------------------------------------------------------------------------------
17
-
18
- require "net/imap"
19
- require "mail"
20
-
21
- module FatFreeCRM
22
- class Dropbox
23
- KEYWORDS = %w(account campaign contact lead opportunity).freeze
24
-
25
- #--------------------------------------------------------------------------------------
26
- def initialize
27
- # Models are autoloaded, so the following @@assets class variable should only be set
28
- # when Dropbox is initialized. This needs to be done so that Rake tasks such as
29
- # 'assets:precompile' can run on Heroku without depending on a database.
30
- # See: http://devcenter.heroku.com/articles/rails31_heroku_cedar#troubleshooting
31
- @@assets = [ Account, Contact, Lead ].freeze
32
- @settings = Setting.email_dropbox.dup
33
- @archived, @discarded = 0, 0
34
- end
35
-
36
- #--------------------------------------------------------------------------------------
37
- def run
38
- log "connecting to #{@settings[:server]}..."
39
- connect! or return nil
40
- log "logged in to #{@settings[:server]}..."
41
- with_new_emails do |uid, email|
42
- process(uid, email)
43
- archive(uid)
44
- end
45
- expunge!
46
- ensure
47
- log "messages processed: #{@archived + @discarded}, archived: #{@archived}, discarded: #{@discarded}."
48
- disconnect!
49
- end
50
-
51
- # Setup imap folders in settings.
52
- #--------------------------------------------------------------------------------------
53
- def setup
54
- log "connecting to #{@settings[:server]}..."
55
- connect!(:setup => true) or return nil
56
- log "logged in to #{@settings[:server]}, checking folders..."
57
- folders = [ @settings[:scan_folder] ]
58
- folders << @settings[:move_to_folder] unless @settings[:move_to_folder].blank?
59
- folders << @settings[:move_invalid_to_folder] unless @settings[:move_invalid_to_folder].blank?
60
-
61
- # Open (or create) destination folder in read-write mode.
62
- folders.each do |folder|
63
- if @imap.list("", folder)
64
- log "folder #{folder} OK"
65
- else
66
- log "folder #{folder} missing, creating..."
67
- @imap.create(folder)
68
- end
69
- end
70
- rescue => e
71
- $stderr.puts "setup error #{e.inspect}"
72
- ensure
73
- disconnect!
74
- end
75
-
76
- private
77
-
78
- #--------------------------------------------------------------------------------------
79
- def with_new_emails
80
- @imap.uid_search(['NOT', 'SEEN']).each do |uid|
81
- begin
82
- email = Mail.new(@imap.uid_fetch(uid, 'RFC822').first.attr['RFC822'])
83
- log "fetched new message...", email
84
- if is_valid?(email) && sent_from_known_user?(email)
85
- yield(uid, email)
86
- else
87
- discard(uid)
88
- end
89
- rescue Exception => e
90
- if ["test", "development"].include?(Rails.env)
91
- $stderr.puts e
92
- $stderr.puts e.backtrace
93
- end
94
- log "error processing email: #{e.inspect}", email
95
- discard(uid)
96
- end
97
- end
98
- end
99
-
100
- # Email processing pipeline: each steps gets executed if previous one returns false.
101
- #--------------------------------------------------------------------------------------
102
- def process(uid, email)
103
- with_explicit_keyword(email) do |keyword, name|
104
- data = {"Type" => keyword, "Name" => name}
105
- find_or_create_and_attach(email, data)
106
- end and return
107
-
108
- with_recipients(email) do |recipient|
109
- find_and_attach(email, recipient)
110
- end and return
111
-
112
- with_forwarded_recipient(email) do |recipient|
113
- find_and_attach(email, recipient)
114
- end and return
115
-
116
- with_recipients(email) do |recipient|
117
- create_and_attach(email, recipient)
118
- end and return
119
-
120
- with_forwarded_recipient(email) do |recipient|
121
- create_and_attach(email, recipient)
122
- end
123
- end
124
-
125
- #------------------------------------------------------------------------------
126
- def expunge!
127
- if @imap
128
- # Sends a EXPUNGE command to permanently remove from the currently selected mailbox
129
- # all messages that have the Deleted flag set.
130
- @imap.expunge
131
- end
132
- end
133
-
134
- # Connects to the imap server with the loaded settings
135
- #------------------------------------------------------------------------------
136
- def connect!(options = {})
137
- @imap = Net::IMAP.new(@settings[:server], @settings[:port], @settings[:ssl])
138
- @imap.login(@settings[:user], @settings[:password])
139
- @imap.select(@settings[:scan_folder]) unless options[:setup]
140
- @imap
141
- rescue Exception => e
142
- $stderr.puts "Dropbox: could not login to the IMAP server: #{e.inspect}" unless Rails.env == "test"
143
- nil
144
- end
145
-
146
- #------------------------------------------------------------------------------
147
- def disconnect!
148
- if @imap
149
- @imap.logout
150
- unless @imap.disconnected?
151
- @imap.disconnect rescue nil
152
- end
153
- end
154
- end
155
-
156
- # Discard message (not valid) action based on settings
157
- #------------------------------------------------------------------------------
158
- def discard(uid)
159
- if @settings[:move_invalid_to_folder]
160
- @imap.uid_copy(uid, @settings[:move_invalid_to_folder])
161
- end
162
- @imap.uid_store(uid, "+FLAGS", [:Deleted])
163
- @discarded += 1
164
- end
165
-
166
- # Archive message (valid) action based on settings
167
- #------------------------------------------------------------------------------
168
- def archive(uid)
169
- if @settings[:move_to_folder]
170
- @imap.uid_copy(uid, @settings[:move_to_folder])
171
- end
172
- @imap.uid_store(uid, "+FLAGS", [:Seen])
173
- @archived += 1
174
- end
175
-
176
- #------------------------------------------------------------------------------
177
- def is_valid?(email)
178
- valid = email.content_type != "text/html"
179
- log("not a text message, discarding") unless valid
180
- valid
181
- end
182
-
183
- #------------------------------------------------------------------------------
184
- def sent_from_known_user?(email)
185
- email_address = email.from.first
186
- known = !find_sender(email_address).nil?
187
- log("sent by unknown user #{email_address}, discarding") unless known
188
- known
189
- end
190
-
191
- #------------------------------------------------------------------------------
192
- def find_sender(email_address)
193
- @sender = User.first(:conditions => [ "(lower(email) = ? OR lower(alt_email) = ?) AND suspended_at IS NULL", email_address.downcase, email_address.downcase ])
194
- end
195
-
196
- # Checks the email to detect keyword on the first line.
197
- #--------------------------------------------------------------------------------------
198
- def with_explicit_keyword(email)
199
- first_line = plain_text_body(email).split("\n").first
200
- if first_line =~ %r|^[\./]?(#{KEYWORDS.join('|')})\s(.+)$|i
201
- yield $1.capitalize, $2.strip
202
- end
203
- end
204
-
205
- # Checks the email to detect assets on to/bcc addresses
206
- #--------------------------------------------------------------------------------------
207
- def with_recipients(email, options = {})
208
- recipients = []
209
- recipients += email.to_addrs unless email.to.blank?
210
- recipients += email.cc_addrs unless email.cc.blank?
211
- recipients -= [ @settings[:address] ]
212
- recipients.inject(false) { |attached, recipient| attached ||= yield recipient }
213
- end
214
-
215
- # Checks the email to detect valid email address in body (first email), detect forwarded emails
216
- #----------------------------------------------------------------------------------------
217
- def with_forwarded_recipient(email, options = {})
218
- if plain_text_body(email) =~ /\b([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})\b/
219
- yield $1
220
- end
221
- end
222
-
223
- # Process pipe_separated_data or explicit keyword.
224
- #--------------------------------------------------------------------------------------
225
- def find_or_create_and_attach(email, data)
226
- klass = data["Type"].constantize
227
-
228
- if data["Email"] && klass.new.respond_to?(:email)
229
- conditions = ['email = ?', data["Email"]]
230
- elsif klass.new.respond_to?(:first_name)
231
- first_name, *last_name = data["Name"].split
232
- conditions = if last_name.empty? # Treat single name as last name.
233
- [ 'last_name LIKE ?', "%#{first_name}" ]
234
- else
235
- [ 'first_name LIKE ? AND last_name LIKE ?', "%#{first_name}", "%#{last_name.join(' ')}" ]
236
- end
237
- else
238
- conditions = ['name LIKE ?', "%#{data["Name"]}%"]
239
- end
240
-
241
- # Find the asset from deduced conditions
242
- if asset = klass.where(conditions).first
243
- if sender_has_permissions_for?(asset)
244
- attach(email, asset, :strip_first_line)
245
- else
246
- log "Sender does not have permissions to attach email to #{data["Type"]} #{data["Email"]} <#{data["Name"]}>"
247
- end
248
- else
249
- log "#{data["Type"]} #{data["Email"]} <#{data["Name"]}> not found, creating new one..."
250
- asset = klass.create!(default_values(klass, data))
251
- attach(email, asset, :strip_first_line)
252
- end
253
- true
254
- end
255
-
256
- #----------------------------------------------------------------------------------------
257
- def find_and_attach(email, recipient)
258
- attached = false
259
- @@assets.each do |klass|
260
- asset = klass.find_by_email(recipient)
261
-
262
- # Leads and Contacts have an alt_email: try it if lookup by primary email has failed.
263
- if !asset && klass.column_names.include?("alt_email")
264
- asset = klass.find_by_alt_email(recipient)
265
- end
266
-
267
- if asset && sender_has_permissions_for?(asset)
268
- attach(email, asset)
269
- attached = true
270
- end
271
- end
272
- attached
273
- end
274
-
275
- #----------------------------------------------------------------------------------------
276
- def create_and_attach(email, recipient)
277
- contact = Contact.create!(default_values_for_contact(email, recipient))
278
- attach(email, contact)
279
- end
280
-
281
- #----------------------------------------------------------------------------------------
282
- def attach(email, asset, strip_first_line=false)
283
- to = email.to.blank? ? nil : email.to.join(", ")
284
- cc = email.cc.blank? ? nil : email.cc.join(", ")
285
-
286
- email_body = if strip_first_line
287
- plain_text_body(email).split("\n")[1..-1].join("\n").strip
288
- else
289
- plain_text_body(email)
290
- end
291
-
292
- Email.create(
293
- :imap_message_id => email.message_id,
294
- :user => @sender,
295
- :mediator => asset,
296
- :sent_from => email.from.first,
297
- :sent_to => to,
298
- :cc => cc,
299
- :subject => email.subject,
300
- :body => email_body,
301
- :received_at => email.date,
302
- :sent_at => email.date
303
- )
304
- asset.touch
305
-
306
- if asset.is_a?(Lead) && asset.status == "new"
307
- asset.update_attribute(:status, "contacted")
308
- end
309
-
310
- if @settings[:attach_to_account] && asset.respond_to?(:account) && asset.account
311
- Email.create(
312
- :imap_message_id => email.message_id,
313
- :user => @sender,
314
- :mediator => asset.account,
315
- :sent_from => email.from.first,
316
- :sent_to => to,
317
- :cc => cc,
318
- :subject => email.subject,
319
- :body => email_body,
320
- :received_at => email.date,
321
- :sent_at => email.date
322
- )
323
- asset.account.touch
324
- end
325
- end
326
-
327
- #----------------------------------------------------------------------------------------
328
- def default_values(klass, data)
329
- data = data.dup
330
- keyword = data.delete("Type").capitalize
331
-
332
- defaults = {
333
- :user => @sender,
334
- :access => default_access
335
- }
336
-
337
- case keyword
338
- when "Account", "Campaign", "Opportunity"
339
- defaults[:status] = "planned" if keyword == "Campaign" # TODO: I18n
340
- defaults[:stage] = "prospecting" if keyword == "Opportunity" # TODO: I18n
341
-
342
- when "Contact", "Lead"
343
- first_name, *last_name = data.delete("Name").split(' ')
344
- defaults[:first_name] = first_name
345
- defaults[:last_name] = (last_name.any? ? last_name.join(" ") : "(unknown)")
346
- defaults[:status] = "contacted" if keyword == "Lead" # TODO: I18n
347
- end
348
-
349
- data.each do |key, value|
350
- key = key.downcase
351
- defaults[key.to_sym] = value if klass.new.respond_to?(key + '=')
352
- end
353
-
354
- defaults
355
- end
356
-
357
- #----------------------------------------------------------------------------------------
358
- def default_values_for_contact(email, recipient)
359
- recipient_local, recipient_domain = recipient.split('@')
360
-
361
- defaults = {
362
- :user => @sender,
363
- :first_name => recipient_local.capitalize,
364
- :last_name => "(unknown)",
365
- :email => recipient,
366
- :access => default_access
367
- }
368
-
369
- # Search for domain name in Accounts.
370
- account = Account.where('email like ?', "%#{recipient_domain}").first
371
- if account
372
- log "asociating new contact #{recipient} with the account #{account.name}"
373
- defaults[:account] = account
374
- else
375
- log "creating new account #{recipient_domain.capitalize} for the contact #{recipient}"
376
- defaults[:account] = Account.create!(
377
- :user => @sender,
378
- :email => recipient,
379
- :name => recipient_domain.capitalize,
380
- :access => default_access
381
- )
382
- end
383
- defaults
384
- end
385
-
386
- # If default access is 'Shared' then change it to 'Private' because we don't know how
387
- # to choose anyone to share it with here.
388
- #--------------------------------------------------------------------------------------
389
- def default_access
390
- Setting.default_access == "Shared" ? 'Private' : Setting.default_access
391
- end
392
-
393
- #--------------------------------------------------------------------------------------
394
- def sender_has_permissions_for?(asset)
395
- return true if asset.access == "Public"
396
- return true if asset.user_id == @sender.id || asset.assigned_to == @sender.id
397
- return true if asset.access == "Shared" && Permission.where('user_id = ? AND asset_id = ? AND asset_type = ?', @sender.id, asset.id, asset.class.to_s).count > 0
398
-
399
- false
400
- end
401
-
402
- # Notify users with the results of the operations (feedback from dropbox)
403
- #--------------------------------------------------------------------------------------
404
- def notify(email, mediator_links)
405
- ack_email = Notifier.create_dropbox_notification(@sender, @settings[:address], email, mediator_links)
406
- Notifier.deliver(ack_email)
407
- end
408
-
409
- # Centralized logging.
410
- #--------------------------------------------------------------------------------------
411
- def log(message, email = nil)
412
- return if Rails.env == "test"
413
- puts "Dropbox: #{message}"
414
- puts " From: #{email.from}, Subject: #{email.subject} (#{email.message_id})" if email
415
- end
416
-
417
- # Returns the plain-text version of an email, or strips html tags
418
- # if only html is present.
419
- #--------------------------------------------------------------------------------------
420
- def plain_text_body(email)
421
- parts = email.parts.collect {|c| (c.respond_to?(:parts) && !c.parts.empty?) ? c.parts : c}.flatten
422
- if parts.empty?
423
- parts << email
424
- end
425
- plain_text_part = parts.detect {|p| p.content_type.include?('text/plain')}
426
- if plain_text_part.nil?
427
- # no text/plain part found, assuming html-only email
428
- # strip html tags and remove doctype directive
429
- plain_text_body = email.body.to_s.gsub(/<\/?[^>]*>/, "")
430
- plain_text_body.gsub! %r{^<!DOCTYPE .*$}, ''
431
- else
432
- plain_text_body = plain_text_part.body.to_s
433
- end
434
- plain_text_body.strip.gsub("\r\n", "\n")
435
- end
436
-
437
- end # class Dropbox
438
- end # module FatFreeCRM
439
-