alchemy_crm 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/Gemfile +10 -11
  2. data/alchemy_crm.gemspec +21 -21
  3. data/app/assets/javascripts/alchemy_crm/alchemy_crm.base.js +54 -54
  4. data/app/assets/stylesheets/alchemy_crm/base.css.scss +199 -199
  5. data/app/controllers/alchemy_crm/admin/base_controller.rb +5 -5
  6. data/app/controllers/alchemy_crm/admin/contact_groups_controller.rb +15 -15
  7. data/app/controllers/alchemy_crm/admin/contacts_controller.rb +95 -95
  8. data/app/controllers/alchemy_crm/admin/deliveries_controller.rb +66 -66
  9. data/app/controllers/alchemy_crm/admin/elements_controller_extension.rb +23 -23
  10. data/app/controllers/alchemy_crm/admin/mailings_controller.rb +44 -44
  11. data/app/controllers/alchemy_crm/admin/newsletters_controller.rb +16 -16
  12. data/app/controllers/alchemy_crm/admin/tags_controller.rb +60 -59
  13. data/app/controllers/alchemy_crm/base_controller.rb +3 -3
  14. data/app/controllers/alchemy_crm/contacts_controller.rb +88 -88
  15. data/app/controllers/alchemy_crm/mailings_controller.rb +16 -16
  16. data/app/controllers/alchemy_crm/recipients_controller.rb +30 -30
  17. data/app/controllers/alchemy_crm/subscriptions_controller.rb +54 -54
  18. data/app/helpers/alchemy/pages_helper_extension.rb +14 -14
  19. data/app/helpers/alchemy_crm/admin/base_helper.rb +8 -8
  20. data/app/helpers/alchemy_crm/mailings_helper.rb +175 -175
  21. data/app/mailers/alchemy_crm/bounce_receiver.rb +9 -9
  22. data/app/mailers/alchemy_crm/contacts_mailer.rb +21 -21
  23. data/app/mailers/alchemy_crm/mailings_mailer.rb +46 -46
  24. data/app/mailers/alchemy_crm/subscriptions_mailer.rb +12 -12
  25. data/app/models/alchemy/essence_element_teaser.rb +14 -14
  26. data/app/models/alchemy_crm/contact.rb +260 -260
  27. data/app/models/alchemy_crm/contact_group.rb +15 -15
  28. data/app/models/alchemy_crm/contact_group_filter.rb +17 -17
  29. data/app/models/alchemy_crm/delivery.rb +54 -54
  30. data/app/models/alchemy_crm/element_extension.rb +23 -23
  31. data/app/models/alchemy_crm/mailing.rb +90 -90
  32. data/app/models/alchemy_crm/newsletter.rb +33 -33
  33. data/app/models/alchemy_crm/reaction.rb +5 -5
  34. data/app/models/alchemy_crm/recipient.rb +46 -46
  35. data/app/models/alchemy_crm/subscription.rb +4 -4
  36. data/app/views/alchemy/admin/elements/fill.js.erb +11 -11
  37. data/app/views/alchemy/elements/_newsletter_article_view.html.erb +14 -14
  38. data/app/views/alchemy/elements/_newsletter_greeting_view.html.erb +9 -9
  39. data/app/views/alchemy/elements/_newsletter_signout_form_view.html.erb +18 -18
  40. data/app/views/alchemy/elements/_newsletter_signup_form_view.html.erb +62 -62
  41. data/app/views/alchemy/essences/_essence_element_teaser_editor.html.erb +29 -29
  42. data/app/views/alchemy/newsletter_layouts/_standard.html.erb +37 -37
  43. data/app/views/alchemy_crm/admin/contact_groups/_contact_group.html.erb +30 -30
  44. data/app/views/alchemy_crm/admin/contact_groups/_filter.html.erb +28 -28
  45. data/app/views/alchemy_crm/admin/contact_groups/_form.html.erb +45 -45
  46. data/app/views/alchemy_crm/admin/contact_groups/_tag.html.erb +4 -4
  47. data/app/views/alchemy_crm/admin/contact_groups/add_filter.js.erb +7 -7
  48. data/app/views/alchemy_crm/admin/contact_groups/index.html.erb +28 -28
  49. data/app/views/alchemy_crm/admin/contacts/_contact.html.erb +42 -42
  50. data/app/views/alchemy_crm/admin/contacts/_form.html.erb +76 -76
  51. data/app/views/alchemy_crm/admin/contacts/import.html.erb +27 -27
  52. data/app/views/alchemy_crm/admin/contacts/index.html.erb +39 -39
  53. data/app/views/alchemy_crm/admin/contacts/vcf_import_result.html.erb +24 -24
  54. data/app/views/alchemy_crm/admin/deliveries/_delivery.html.erb +30 -30
  55. data/app/views/alchemy_crm/admin/deliveries/_form.html.erb +61 -61
  56. data/app/views/alchemy_crm/admin/deliveries/_recipient.html.erb +36 -36
  57. data/app/views/alchemy_crm/admin/deliveries/index.html.erb +21 -21
  58. data/app/views/alchemy_crm/admin/deliveries/show.html.erb +61 -61
  59. data/app/views/alchemy_crm/admin/elements/teasables.html.erb +53 -53
  60. data/app/views/alchemy_crm/admin/mailings/_form.html.erb +41 -41
  61. data/app/views/alchemy_crm/admin/mailings/_mailing.html.erb +73 -73
  62. data/app/views/alchemy_crm/admin/mailings/edit_content.html.erb +170 -170
  63. data/app/views/alchemy_crm/admin/mailings/import_result.html.erb +18 -18
  64. data/app/views/alchemy_crm/admin/mailings/index.html.erb +25 -25
  65. data/app/views/alchemy_crm/admin/newsletters/_form.html.erb +52 -52
  66. data/app/views/alchemy_crm/admin/newsletters/_tag_with_radiobutton.html.erb +5 -5
  67. data/app/views/alchemy_crm/admin/newsletters/index.html.erb +29 -29
  68. data/app/views/alchemy_crm/admin/newsletters/new.html.erb +4 -4
  69. data/app/views/alchemy_crm/admin/tags/_radio_tag.html.erb +4 -4
  70. data/app/views/alchemy_crm/admin/tags/_tag.html.erb +30 -30
  71. data/app/views/alchemy_crm/admin/tags/edit.html.erb +32 -32
  72. data/app/views/alchemy_crm/admin/tags/index.html.erb +23 -23
  73. data/app/views/alchemy_crm/admin/tags/new.html.erb +14 -14
  74. data/app/views/alchemy_crm/contacts_mailer/signout_mail.html.erb +6 -6
  75. data/app/views/alchemy_crm/contacts_mailer/signout_mail.text.erb +2 -2
  76. data/app/views/alchemy_crm/contacts_mailer/signup_mail.html.erb +9 -9
  77. data/app/views/alchemy_crm/contacts_mailer/signup_mail.text.erb +2 -2
  78. data/app/views/alchemy_crm/mailings_mailer/verification_mail.html.erb +9 -9
  79. data/app/views/alchemy_crm/subscriptions/index.html.erb +4 -4
  80. data/app/views/alchemy_crm/subscriptions_mailer/overview_mail.html.erb +25 -25
  81. data/app/views/alchemy_crm/subscriptions_mailer/overview_mail.text.erb +2 -2
  82. data/app/views/csv_magic/import_errors.html.erb +23 -23
  83. data/app/views/csv_magic/mapper.html.erb +46 -46
  84. data/app/views/layouts/alchemy_crm/mailings.html.erb +177 -177
  85. data/config/initializers/assets.rb +2 -2
  86. data/config/locales/alchemy_crm.de.yml +1 -1
  87. data/config/locales/alchemy_crm.en.yml +1 -0
  88. data/config/locales/localized_country_select.de.rb +260 -260
  89. data/config/locales/localized_country_select.en.rb +274 -274
  90. data/config/routes.rb +67 -67
  91. data/db/migrate/20111104125306_remove_sent_mailing_pdf_id_from_sent_mailings.rb +1 -1
  92. data/db/migrate/20111124145923_namespace_alchemy_crm_models.rb +13 -13
  93. data/db/migrate/20120307160721_rename_alchemy_crm_recipients_sent_mailing_id.rb +3 -3
  94. data/db/migrate/20120320103412_add_indexes_to_alchemy_crm_sha1_columns.rb +3 -3
  95. data/db/migrate/20120327174301_add_more_indexes_to_alchemy_crm_tables.rb +10 -10
  96. data/lib/alchemy_crm.rb +15 -15
  97. data/lib/alchemy_crm/bounced_delivery.rb +38 -38
  98. data/lib/alchemy_crm/config.rb +25 -25
  99. data/lib/alchemy_crm/engine.rb +31 -31
  100. data/lib/alchemy_crm/i18n_helpers.rb +28 -28
  101. data/lib/alchemy_crm/newsletter_layout.rb +28 -28
  102. data/lib/alchemy_crm/seeder.rb +26 -26
  103. data/lib/alchemy_crm/version.rb +1 -1
  104. data/lib/generators/alchemy_crm/scaffold/files/newsletters.html.erb +19 -19
  105. data/lib/generators/alchemy_crm/scaffold/scaffold_generator.rb +2 -2
  106. data/lib/tasks/alchemy_crm.rake +22 -22
  107. data/lib/tasks/routes.rake +25 -25
  108. data/spec/config_spec.rb +24 -24
  109. data/spec/controllers/alchemy_crm/contacts_controller_spec.rb +147 -147
  110. data/spec/controllers/alchemy_crm/mailings_controller_spec.rb +62 -62
  111. data/spec/controllers/alchemy_crm/recipients_controller_spec.rb +109 -109
  112. data/spec/helpers/alchemy_crm/mailings_helper_spec.rb +165 -165
  113. data/spec/mailers/alchemy_crm/contacts_mailer_spec.rb +84 -84
  114. data/spec/mailers/alchemy_crm/mailings_mailer_spec.rb +29 -29
  115. data/spec/models/alchemy_crm/contact_group_spec.rb +25 -25
  116. data/spec/models/alchemy_crm/contact_spec.rb +71 -71
  117. data/spec/models/alchemy_crm/delivery_spec.rb +43 -39
  118. data/spec/models/alchemy_crm/mailing_spec.rb +46 -42
  119. data/spec/models/alchemy_crm/newsletter_spec.rb +29 -29
  120. data/spec/spec_helper.rb +36 -36
  121. metadata +6 -8
  122. data/rails/init.rb +0 -1
  123. data/recipes/alchemy-mailings-capistrano-tasks.rb +0 -12
@@ -1,13 +1,13 @@
1
1
  module AlchemyCrm
2
- class BounceReceiver < ActionMailer::Base
2
+ class BounceReceiver < ActionMailer::Base
3
3
 
4
- def receive(email)
5
- return unless email.content_type == "multipart/report"
6
- bounce = BouncedDelivery.from_email(email)
7
- recipient = Recipient.find_by_message_id(bounce.original_message_id)
8
- recipient.bounced = (bounce.status == "Failure")
9
- recipient.save!
10
- end
4
+ def receive(email)
5
+ return unless email.content_type == "multipart/report"
6
+ bounce = BouncedDelivery.from_email(email)
7
+ recipient = Recipient.find_by_message_id(bounce.original_message_id)
8
+ recipient.bounced = (bounce.status == "Failure")
9
+ recipient.save!
10
+ end
11
11
 
12
- end
12
+ end
13
13
  end
@@ -1,26 +1,26 @@
1
1
  module AlchemyCrm
2
- class ContactsMailer < ActionMailer::Base
2
+ class ContactsMailer < ActionMailer::Base
3
3
 
4
- def signup_mail(contact, page)
5
- @contact = contact
6
- @newsletter_ids = @contact.subscriptions.collect(&:newsletter_id)
7
- @element = page.elements.where(:name => 'newsletter_signup_mail').first
8
- mail(
9
- :from => @element.ingredient('mail_from'),
10
- :to => contact.email,
11
- :subject => @element.ingredient('subject')
12
- )
13
- end
4
+ def signup_mail(contact, page)
5
+ @contact = contact
6
+ @newsletter_ids = @contact.subscriptions.collect(&:newsletter_id)
7
+ @element = page.elements.where(:name => 'newsletter_signup_mail').first
8
+ mail(
9
+ :from => @element.ingredient('mail_from'),
10
+ :to => contact.email,
11
+ :subject => @element.ingredient('subject')
12
+ )
13
+ end
14
14
 
15
- def signout_mail(contact, page)
16
- @element = page.elements.where(:name => 'newsletter_signout_mail').first
17
- @contact = contact
18
- mail(
19
- :from => @element.ingredient("mail_from"),
20
- :to => contact.email,
21
- :subject => @element.ingredient('subject')
22
- )
23
- end
15
+ def signout_mail(contact, page)
16
+ @element = page.elements.where(:name => 'newsletter_signout_mail').first
17
+ @contact = contact
18
+ mail(
19
+ :from => @element.ingredient("mail_from"),
20
+ :to => contact.email,
21
+ :subject => @element.ingredient('subject')
22
+ )
23
+ end
24
24
 
25
- end
25
+ end
26
26
  end
@@ -1,48 +1,48 @@
1
1
  module AlchemyCrm
2
- class MailingsMailer < ActionMailer::Base
3
-
4
- default :from => AlchemyCrm::Config.get(:mail_from)
5
-
6
- helper "AlchemyCrm::Mailings", "Application"
7
- helper_method :logged_in?, :configuration
8
-
9
- # Renders the email sent to the mailing recipient
10
- # It takes the layout from +layouts/alchemy_crm/mailings.erb+ and renders a html and a text part from it.
11
- def build(mailing, recipient, options = {})
12
- @options = options
13
- ::I18n.locale = @options[:locale]
14
- @mailing = mailing
15
- @page = @mailing.page
16
- @recipient = recipient
17
- @contact = @recipient.contact || Contact.new_from_recipient(@recipient)
18
-
19
- mail(:to => @recipient.mail_to, :subject => mailing.subject) do |format|
20
- format.text { render("layouts/alchemy_crm/mailings.text") }
21
- format.html { render("layouts/alchemy_crm/mailings.html") }
22
- end
23
- end
24
-
25
- # Faking that we are not logged in
26
- def logged_in?
27
- false
28
- end
29
-
30
- # Proxy to Alchemy config for view helpers
31
- def configuration(name)
32
- Alchemy::Config.get(name)
33
- end
34
-
35
- # Simple session object that contains the language id for view helpers.
36
- def session
37
- {
38
- :language_id => @options[:language_id]
39
- }
40
- end
41
-
42
- # Setting default url options for rails url_for helpers.
43
- def default_url_options
44
- {:host => @options[:host], :port => @options[:port]}
45
- end
46
-
47
- end
2
+ class MailingsMailer < ActionMailer::Base
3
+
4
+ default :from => AlchemyCrm::Config.get(:mail_from)
5
+
6
+ helper "AlchemyCrm::Mailings", "Application"
7
+ helper_method :logged_in?, :configuration
8
+
9
+ # Renders the email sent to the mailing recipient
10
+ # It takes the layout from +layouts/alchemy_crm/mailings.erb+ and renders a html and a text part from it.
11
+ def build(mailing, recipient, options = {})
12
+ @options = options
13
+ ::I18n.locale = @options[:locale]
14
+ @mailing = mailing
15
+ @page = @mailing.page
16
+ @recipient = recipient
17
+ @contact = @recipient.contact || Contact.new_from_recipient(@recipient)
18
+
19
+ mail(:to => @recipient.mail_to, :subject => mailing.subject) do |format|
20
+ format.text { render("layouts/alchemy_crm/mailings.text") }
21
+ format.html { render("layouts/alchemy_crm/mailings.html") }
22
+ end
23
+ end
24
+
25
+ # Faking that we are not logged in
26
+ def logged_in?
27
+ false
28
+ end
29
+
30
+ # Proxy to Alchemy config for view helpers
31
+ def configuration(name)
32
+ Alchemy::Config.get(name)
33
+ end
34
+
35
+ # Simple session object that contains the language id for view helpers.
36
+ def session
37
+ {
38
+ :language_id => @options[:language_id]
39
+ }
40
+ end
41
+
42
+ # Setting default url options for rails url_for helpers.
43
+ def default_url_options
44
+ {:host => @options[:host], :port => @options[:port]}
45
+ end
46
+
47
+ end
48
48
  end
@@ -1,17 +1,17 @@
1
1
  # encoding: UTF-8
2
2
  module AlchemyCrm
3
- class SubscriptionsMailer < ActionMailer::Base
3
+ class SubscriptionsMailer < ActionMailer::Base
4
4
 
5
- def overview_mail(contact, element)
6
- @contact = contact
7
- @subscriptions = contact.subscriptions
8
- @element = element
9
- mail(
10
- :from => element.ingredient("mail_from"),
11
- :to => contact.email,
12
- :subject => element.ingredient("mail_subject")
13
- )
14
- end
5
+ def overview_mail(contact, element)
6
+ @contact = contact
7
+ @subscriptions = contact.subscriptions
8
+ @element = element
9
+ mail(
10
+ :from => element.ingredient("mail_from"),
11
+ :to => contact.email,
12
+ :subject => element.ingredient("mail_subject")
13
+ )
14
+ end
15
15
 
16
- end
16
+ end
17
17
  end
@@ -1,19 +1,19 @@
1
1
  module Alchemy
2
- class EssenceElementTeaser < ActiveRecord::Base
2
+ class EssenceElementTeaser < ActiveRecord::Base
3
3
 
4
- acts_as_essence(
5
- :ingredient_column => :url,
6
- :preview_text_method => :url
7
- )
4
+ acts_as_essence(
5
+ :ingredient_column => :url,
6
+ :preview_text_method => :url
7
+ )
8
8
 
9
- # Saves the content from params
10
- def save_ingredient(params, options = {})
11
- return true if params.blank?
12
- self.url = params["url"]
13
- self.title = params["title"]
14
- self.text = params["text"]
15
- self.save!
16
- end
9
+ # Saves the content from params
10
+ def save_ingredient(params, options = {})
11
+ return true if params.blank?
12
+ self.url = params["url"]
13
+ self.title = params["title"]
14
+ self.text = params["text"]
15
+ self.save!
16
+ end
17
17
 
18
- end
18
+ end
19
19
  end
@@ -1,264 +1,264 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module AlchemyCrm
4
- class Contact < ActiveRecord::Base
5
-
6
- acts_as_taggable
7
-
8
- attr_accessible(
9
- :salutation,
10
- :title,
11
- :firstname,
12
- :lastname,
13
- :email,
14
- :phone,
15
- :mobile,
16
- :address,
17
- :zip,
18
- :city,
19
- :organisation,
20
- :country,
21
- :subscriptions_attributes
22
- )
23
-
24
- attr_accessible(
25
- :salutation,
26
- :title,
27
- :firstname,
28
- :lastname,
29
- :email,
30
- :phone,
31
- :mobile,
32
- :address,
33
- :zip,
34
- :city,
35
- :organisation,
36
- :country,
37
- :subscriptions_attributes,
38
- :verified,
39
- :disabled,
40
- :tag_list,
41
- :as => :admin
42
- )
43
-
44
- has_many :subscriptions, :dependent => :destroy
45
- has_many :newsletters, :through => :subscriptions, :uniq => true
46
- has_many :recipients
47
-
48
- attr_accessor :skip_validation
49
-
50
- accepts_nested_attributes_for :subscriptions, :allow_destroy => true
51
-
52
- validates_presence_of :salutation, :unless => proc { skip_validation }
53
- validates_presence_of :firstname, :unless => proc { skip_validation }
54
- validates_presence_of :lastname
55
- validates_presence_of :email
56
- validates_uniqueness_of :email
57
- validates_format_of :email, :with => ::Authlogic::Regex.email, :if => proc { errors[:email].blank? }
58
-
59
- before_save :update_sha1, :if => proc { email_sha1.blank? || email_changed? }
60
-
61
- scope :verified, where(:verified => true)
62
- scope :disabled, where(:disabled => true)
63
- scope :enabled, where(:disabled => false)
64
- scope :available, verified.enabled
65
-
66
- COLUMN_NAMES = [
67
- [::I18n.t(:title, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Title'), "title"],
68
- [::I18n.t(:salutation, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Salutation'), "salutation"],
69
- [::I18n.t(:firstname, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Firstname'), "firstname"],
70
- [::I18n.t(:lastname, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Lastname'), "lastname"],
71
- [::I18n.t(:address, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Address'), "address"],
72
- [::I18n.t(:zip, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Zipcode'), "zip"],
73
- [::I18n.t(:city, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'City'), "city"],
74
- [::I18n.t(:country, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Country'), "country"],
75
- [::I18n.t(:organisation, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Organisation'), "organisation"]
76
- ]
77
-
78
- INTERPOLATION_NAME_METHODS = %w(fullname name_with_title firstname lastname name email)
79
-
80
- def disable!
81
- update_attributes({
82
- :verified => false,
83
- :disabled => true
84
- }, :as => :admin)
85
- subscriptions.destroy_all
86
- end
87
-
88
- # Returns a full name
89
- # Salutation + Title + Firstname + Lastname
90
- def fullname
91
- if lastname.present? || firstname.present?
92
- "#{translated_salutation} #{name_with_title}".squeeze(" ")
93
- else
94
- name
95
- end
96
- end
97
-
98
- # Translated salutation
99
- #
100
- # Translate the saluations in your +config/LOCALE.yml+
101
- #
102
- # alchemy_crm:
103
- # salutations:
104
- # mr:
105
- # ms:
106
- #
107
- def translated_salutation
108
- ::I18n.t(salutation, :scope => [:alchemy_crm, :salutations], :default => salutation.to_s.capitalize)
109
- end
110
-
111
- # Returns the name and title
112
- # Title + Firstname + Lastname
113
- def name_with_title
114
- "#{title} #{name}".squeeze(" ")
115
- end
116
-
117
- # Returns the name ot email, if no name is present
118
- # Firstname + Lastname, or email
119
- def name
120
- if lastname.present? || firstname.present?
121
- "#{firstname} #{lastname}".squeeze(" ")
122
- else
123
- email
124
- end
125
- end
126
-
127
- # Uses the +config['name_interpolation_method']+ to return the value for emails and forms %{name} interpolations.
128
- def interpolation_name_value
129
- name_interpolation_method = Config.get(:name_interpolation_method)
130
- if name_interpolation_method.present? && INTERPOLATION_NAME_METHODS.include?(name_interpolation_method.to_s) && self.respond_to?(name_interpolation_method.to_sym)
131
- self.send(name_interpolation_method.to_sym)
132
- else
133
- fullname
134
- end
135
- end
136
-
137
- def self.fake
138
- fake = new(
139
- :salutation => nil,
140
- :title => ::I18n.t(:title, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'Dr.'),
141
- :firstname => ::I18n.t(:firstname, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'Jon'),
142
- :lastname => ::I18n.t(:lastname, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'Doe'),
143
- :email => ::I18n.t(:email, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'jon@doe.com'),
144
- :phone => ::I18n.t(:phone, :scope => 'alchemy_crm.fake_contact_attributes', :default => '1-1234567'),
145
- :mobile => ::I18n.t(:mobile, :scope => 'alchemy_crm.fake_contact_attributes', :default => '123-456789'),
146
- :address => ::I18n.t(:address, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'Street 1'),
147
- :zip => ::I18n.t(:zip, :scope => 'alchemy_crm.fake_contact_attributes', :default => '10000'),
148
- :city => ::I18n.t(:city, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'City'),
149
- :organisation => ::I18n.t(:organisation, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'Company inc.'),
150
- :country => ::I18n.t(:country, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'US')
151
- )
152
- fake.readonly!
153
- fake
154
- end
155
-
156
- def self.replace_tag(old_tag, new_tag)
157
- self.tagged_with(old_tag).each do |contact|
158
- contact.tags.delete(old_tag)
159
- contact.tags << new_tag
160
- contact.save
161
- end
162
- end
163
-
164
- def self.find_by_query(query, options, paginate)
165
- column_names = Contact.public_column_names
166
- search_string = (column_names.join(" LIKE '%#{query}%' OR ") + " LIKE '%#{query}%'")
167
- contacts = where(search_string)
168
- if paginate
169
- contacts.paginate(options)
170
- else
171
- contacts
172
- end
173
- end
174
-
175
- #TODO: Zu den selbstgewählten Mailingformaten müssten noch alle durch den Backend User gewählten Formate mit angezeigt werden, oder?
176
- def all_newsletters
177
- self.newsletters
178
- end
179
-
180
- def self.public_column_names
181
- Contact.column_names - ["created_at", "updated_at", "email_salt", "verified", "email_sha1", "id"]
182
- end
183
-
184
- def self.filterable_column_names
185
- COLUMN_NAMES
186
- end
187
-
188
- def self.find_or_create(data)
189
- if (contact = Contact.find_by_email(data[:email])).nil?
190
- contact = Contact.create(data)
191
- end
192
- contact
193
- end
194
-
195
- def all_subscriptions_verified?
196
- self.subscriptions.inject(true){|acc, s| acc = s.verified? && acc; acc}
197
- end
198
-
199
- def self.new_from_recipient(recipient)
200
- raise "No recipient found!" if recipient.nil?
201
- contact = new(:email => recipient.email, :lastname => recipient.email)
202
- contact.readonly!
203
- contact
204
- end
205
-
206
- def self.new_from_vcard(vcard, verified)
207
- raise "No vcard found!" if vcard.nil?
208
- raise ::I18n.t(:imported_contacts_not_verified, :scope => :alchemy_crm) if !verified
209
- contacts = []
210
- ::Vpim::Vcard.decode(vcard).each do |card|
211
- remapped_attributes = {
212
- :organisation => card.org.blank? ? nil : card.org.first,
213
- :lastname => card.name.blank? ? nil : card.name.family,
214
- :firstname => card.name.blank? ? nil : card.name.given,
215
- :title => card.name.blank? ? nil : card.name.prefix,
216
- :address => card.address.blank? ? nil : card.address.street,
217
- :city => card.address.blank? ? nil : card.address.locality,
218
- :country => card.address.blank? ? nil : card.address.country,
219
- :zip => card.address.blank? ? nil : card.address.postalcode,
220
- :email => card.email.to_s,
221
- :phone => card.telephone ? card.telephone.location.include?("cell") ? nil : card.telephone.to_s : nil,
222
- :mobile => card.telephones.detect { |t| t.location.include?("cell") }.to_s,
223
- :verified => true
224
- }
225
- contact = Contact.new(remapped_attributes, :as => :admin)
226
- contact.skip_validation = true
227
- contact.save
228
- contacts << contact
229
- end
230
- contacts
231
- end
232
-
233
- def to_vcard
234
- card = Vpim::Vcard::Maker.make2 do |maker|
235
- maker.add_name do |name|
236
- name.prefix = title unless title.blank?
237
- name.given = firstname unless firstname.blank?
238
- name.family = lastname unless lastname.blank?
239
- end
240
- maker.add_tel(phone) { |t| t.location = 'work' } unless phone.blank?
241
- maker.add_tel(mobile) { |t| t.location = 'cell' } unless mobile.blank?
242
- maker.add_email(email) { |e| e.location = 'work' } unless email.blank?
243
- maker.add_addr do |addr|
244
- addr.street = address
245
- addr.postalcode = zip
246
- addr.locality = city
247
- addr.country = country
248
- end
249
- maker.org = organisation
250
- end
251
- vcf = File.new(Rails.root.to_s + "/tmp/#{fullname}.vcf", "w")
252
- vcf.write(card.encode)
253
- vcf.close
254
- end
255
-
256
- private
257
-
258
- def update_sha1
259
- salt = email_salt || [Array.new(6){rand(256).chr}.join].pack("m")[0..7]
260
- self.email_salt, self.email_sha1 = salt, Digest::SHA1.hexdigest(email + salt)
261
- end
262
-
263
- end
4
+ class Contact < ActiveRecord::Base
5
+
6
+ acts_as_taggable
7
+
8
+ attr_accessible(
9
+ :salutation,
10
+ :title,
11
+ :firstname,
12
+ :lastname,
13
+ :email,
14
+ :phone,
15
+ :mobile,
16
+ :address,
17
+ :zip,
18
+ :city,
19
+ :organisation,
20
+ :country,
21
+ :subscriptions_attributes
22
+ )
23
+
24
+ attr_accessible(
25
+ :salutation,
26
+ :title,
27
+ :firstname,
28
+ :lastname,
29
+ :email,
30
+ :phone,
31
+ :mobile,
32
+ :address,
33
+ :zip,
34
+ :city,
35
+ :organisation,
36
+ :country,
37
+ :subscriptions_attributes,
38
+ :verified,
39
+ :disabled,
40
+ :tag_list,
41
+ :as => :admin
42
+ )
43
+
44
+ has_many :subscriptions, :dependent => :destroy
45
+ has_many :newsletters, :through => :subscriptions, :uniq => true
46
+ has_many :recipients
47
+
48
+ attr_accessor :skip_validation
49
+
50
+ accepts_nested_attributes_for :subscriptions, :allow_destroy => true
51
+
52
+ validates_presence_of :salutation, :unless => proc { skip_validation }
53
+ validates_presence_of :firstname, :unless => proc { skip_validation }
54
+ validates_presence_of :lastname
55
+ validates_presence_of :email
56
+ validates_uniqueness_of :email
57
+ validates_format_of :email, :with => ::Authlogic::Regex.email, :if => proc { errors[:email].blank? }
58
+
59
+ before_save :update_sha1, :if => proc { email_sha1.blank? || email_changed? }
60
+
61
+ scope :verified, where(:verified => true)
62
+ scope :disabled, where(:disabled => true)
63
+ scope :enabled, where(:disabled => false)
64
+ scope :available, verified.enabled
65
+
66
+ COLUMN_NAMES = [
67
+ [::I18n.t(:title, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Title'), "title"],
68
+ [::I18n.t(:salutation, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Salutation'), "salutation"],
69
+ [::I18n.t(:firstname, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Firstname'), "firstname"],
70
+ [::I18n.t(:lastname, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Lastname'), "lastname"],
71
+ [::I18n.t(:address, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Address'), "address"],
72
+ [::I18n.t(:zip, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Zipcode'), "zip"],
73
+ [::I18n.t(:city, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'City'), "city"],
74
+ [::I18n.t(:country, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Country'), "country"],
75
+ [::I18n.t(:organisation, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Organisation'), "organisation"]
76
+ ]
77
+
78
+ INTERPOLATION_NAME_METHODS = %w(fullname name_with_title firstname lastname name email)
79
+
80
+ def disable!
81
+ update_attributes({
82
+ :verified => false,
83
+ :disabled => true
84
+ }, :as => :admin)
85
+ subscriptions.destroy_all
86
+ end
87
+
88
+ # Returns a full name
89
+ # Salutation + Title + Firstname + Lastname
90
+ def fullname
91
+ if lastname.present? || firstname.present?
92
+ "#{translated_salutation} #{name_with_title}".squeeze(" ")
93
+ else
94
+ name
95
+ end
96
+ end
97
+
98
+ # Translated salutation
99
+ #
100
+ # Translate the saluations in your +config/LOCALE.yml+
101
+ #
102
+ # alchemy_crm:
103
+ # salutations:
104
+ # mr:
105
+ # ms:
106
+ #
107
+ def translated_salutation
108
+ ::I18n.t(salutation, :scope => [:alchemy_crm, :salutations], :default => salutation.to_s.capitalize)
109
+ end
110
+
111
+ # Returns the name and title
112
+ # Title + Firstname + Lastname
113
+ def name_with_title
114
+ "#{title} #{name}".squeeze(" ")
115
+ end
116
+
117
+ # Returns the name ot email, if no name is present
118
+ # Firstname + Lastname, or email
119
+ def name
120
+ if lastname.present? || firstname.present?
121
+ "#{firstname} #{lastname}".squeeze(" ")
122
+ else
123
+ email
124
+ end
125
+ end
126
+
127
+ # Uses the +config['name_interpolation_method']+ to return the value for emails and forms %{name} interpolations.
128
+ def interpolation_name_value
129
+ name_interpolation_method = Config.get(:name_interpolation_method)
130
+ if name_interpolation_method.present? && INTERPOLATION_NAME_METHODS.include?(name_interpolation_method.to_s) && self.respond_to?(name_interpolation_method.to_sym)
131
+ self.send(name_interpolation_method.to_sym)
132
+ else
133
+ fullname
134
+ end
135
+ end
136
+
137
+ def self.fake
138
+ fake = new(
139
+ :salutation => nil,
140
+ :title => ::I18n.t(:title, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'Dr.'),
141
+ :firstname => ::I18n.t(:firstname, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'Jon'),
142
+ :lastname => ::I18n.t(:lastname, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'Doe'),
143
+ :email => ::I18n.t(:email, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'jon@doe.com'),
144
+ :phone => ::I18n.t(:phone, :scope => 'alchemy_crm.fake_contact_attributes', :default => '1-1234567'),
145
+ :mobile => ::I18n.t(:mobile, :scope => 'alchemy_crm.fake_contact_attributes', :default => '123-456789'),
146
+ :address => ::I18n.t(:address, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'Street 1'),
147
+ :zip => ::I18n.t(:zip, :scope => 'alchemy_crm.fake_contact_attributes', :default => '10000'),
148
+ :city => ::I18n.t(:city, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'City'),
149
+ :organisation => ::I18n.t(:organisation, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'Company inc.'),
150
+ :country => ::I18n.t(:country, :scope => 'alchemy_crm.fake_contact_attributes', :default => 'US')
151
+ )
152
+ fake.readonly!
153
+ fake
154
+ end
155
+
156
+ def self.replace_tag(old_tag, new_tag)
157
+ self.tagged_with(old_tag).each do |contact|
158
+ contact.tags.delete(old_tag)
159
+ contact.tags << new_tag
160
+ contact.save
161
+ end
162
+ end
163
+
164
+ def self.find_by_query(query, options, paginate)
165
+ column_names = Contact.public_column_names
166
+ search_string = (column_names.join(" LIKE '%#{query}%' OR ") + " LIKE '%#{query}%'")
167
+ contacts = where(search_string)
168
+ if paginate
169
+ contacts.paginate(options)
170
+ else
171
+ contacts
172
+ end
173
+ end
174
+
175
+ #TODO: Zu den selbstgewählten Mailingformaten müssten noch alle durch den Backend User gewählten Formate mit angezeigt werden, oder?
176
+ def all_newsletters
177
+ self.newsletters
178
+ end
179
+
180
+ def self.public_column_names
181
+ Contact.column_names - ["created_at", "updated_at", "email_salt", "verified", "email_sha1", "id"]
182
+ end
183
+
184
+ def self.filterable_column_names
185
+ COLUMN_NAMES
186
+ end
187
+
188
+ def self.find_or_create(data)
189
+ if (contact = Contact.find_by_email(data[:email])).nil?
190
+ contact = Contact.create(data)
191
+ end
192
+ contact
193
+ end
194
+
195
+ def all_subscriptions_verified?
196
+ self.subscriptions.inject(true){|acc, s| acc = s.verified? && acc; acc}
197
+ end
198
+
199
+ def self.new_from_recipient(recipient)
200
+ raise "No recipient found!" if recipient.nil?
201
+ contact = new(:email => recipient.email, :lastname => recipient.email)
202
+ contact.readonly!
203
+ contact
204
+ end
205
+
206
+ def self.new_from_vcard(vcard, verified)
207
+ raise "No vcard found!" if vcard.nil?
208
+ raise ::I18n.t(:imported_contacts_not_verified, :scope => :alchemy_crm) if !verified
209
+ contacts = []
210
+ ::Vpim::Vcard.decode(vcard).each do |card|
211
+ remapped_attributes = {
212
+ :organisation => card.org.blank? ? nil : card.org.first,
213
+ :lastname => card.name.blank? ? nil : card.name.family,
214
+ :firstname => card.name.blank? ? nil : card.name.given,
215
+ :title => card.name.blank? ? nil : card.name.prefix,
216
+ :address => card.address.blank? ? nil : card.address.street,
217
+ :city => card.address.blank? ? nil : card.address.locality,
218
+ :country => card.address.blank? ? nil : card.address.country,
219
+ :zip => card.address.blank? ? nil : card.address.postalcode,
220
+ :email => card.email.to_s,
221
+ :phone => card.telephone ? card.telephone.location.include?("cell") ? nil : card.telephone.to_s : nil,
222
+ :mobile => card.telephones.detect { |t| t.location.include?("cell") }.to_s,
223
+ :verified => true
224
+ }
225
+ contact = Contact.new(remapped_attributes, :as => :admin)
226
+ contact.skip_validation = true
227
+ contact.save
228
+ contacts << contact
229
+ end
230
+ contacts
231
+ end
232
+
233
+ def to_vcard
234
+ card = Vpim::Vcard::Maker.make2 do |maker|
235
+ maker.add_name do |name|
236
+ name.prefix = title unless title.blank?
237
+ name.given = firstname unless firstname.blank?
238
+ name.family = lastname unless lastname.blank?
239
+ end
240
+ maker.add_tel(phone) { |t| t.location = 'work' } unless phone.blank?
241
+ maker.add_tel(mobile) { |t| t.location = 'cell' } unless mobile.blank?
242
+ maker.add_email(email) { |e| e.location = 'work' } unless email.blank?
243
+ maker.add_addr do |addr|
244
+ addr.street = address
245
+ addr.postalcode = zip
246
+ addr.locality = city
247
+ addr.country = country
248
+ end
249
+ maker.org = organisation
250
+ end
251
+ vcf = File.new(Rails.root.to_s + "/tmp/#{fullname}.vcf", "w")
252
+ vcf.write(card.encode)
253
+ vcf.close
254
+ end
255
+
256
+ private
257
+
258
+ def update_sha1
259
+ salt = email_salt || [Array.new(6){rand(256).chr}.join].pack("m")[0..7]
260
+ self.email_salt, self.email_sha1 = salt, Digest::SHA1.hexdigest(email + salt)
261
+ end
262
+
263
+ end
264
264
  end