alchemy_crm 2.0.3 → 2.0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,7 @@ rvm:
6
6
  - ree
7
7
  branches:
8
8
  only:
9
- - master
9
+ - 2.0-stable
10
10
  before_script:
11
11
  - "sh -c 'cd spec/dummy && RAILS_ENV=test bundle exec rake db:schema:load'"
12
12
  script: "bundle exec rspec spec"
data/Gemfile CHANGED
@@ -6,7 +6,7 @@ gemspec
6
6
  group :development do
7
7
  if !ENV["CI"]
8
8
  gem 'guard-spork'
9
- gem 'ruby-debug19', :require => 'ruby-debug', :platform => :ruby_19
9
+ gem 'debugger', :platform => :ruby_19
10
10
  gem 'ruby-debug', :platform => :ruby_18
11
11
  end
12
12
  end
@@ -15,4 +15,5 @@ group :test do
15
15
  gem 'sqlite3'
16
16
  gem "database_cleaner"
17
17
  gem 'email_spec'
18
+ gem 'factory_girl'
18
19
  end
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  Alchemy CRM Module
2
2
  ==================
3
3
 
4
+ [![Build Status](https://secure.travis-ci.org/magiclabs/alchemy_crm.png?branch=2.0-stable)](http://travis-ci.org/magiclabs/alchemy_crm)
5
+
4
6
  Building and sending Newsletters has never been easier!
5
7
 
6
8
  About
@@ -20,7 +22,7 @@ http://guides.alchemy-cms.com/getting_started.html
20
22
  2. Put this line into your projects `Gemfile`:
21
23
 
22
24
  # Gemfile
23
- gem "alchemy_crm", :git => 'git://github.com/magiclabs/alchemy_crm'
25
+ gem "alchemy_crm", :git => 'git://github.com/magiclabs/alchemy_crm', :branch => '2.0-stable'
24
26
 
25
27
  Or install it via Rubygems:
26
28
 
@@ -47,7 +49,7 @@ Or install it via Rubygems:
47
49
  6. Seed the database:
48
50
 
49
51
  1. Put this line into your projects `db/seeds.rb` file:
50
-
52
+
51
53
  AlchemyCrm::Seeder.seed!
52
54
 
53
55
  2. And run this rake task:
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
17
17
  gem.require_paths = ["lib"]
18
18
  gem.version = AlchemyCrm::VERSION
19
19
 
20
- gem.add_dependency 'alchemy_cms', ["~> 2.1.9"]
20
+ gem.add_dependency 'alchemy_cms', ["~> 2.1.12"]
21
21
  gem.add_dependency 'vcard', ['~> 0.1.1']
22
22
  gem.add_dependency 'csv_magic', ['~> 0.2.2']
23
23
  gem.add_dependency 'delayed_job_active_record', ["~> 0.3.2"]
@@ -1,4 +1,5 @@
1
1
  # encoding: UTF-8
2
+
2
3
  module AlchemyCrm
3
4
  module Admin
4
5
  class ContactsController < AlchemyCrm::Admin::BaseController
@@ -25,6 +26,26 @@ module AlchemyCrm
25
26
 
26
27
  before_filter :load_tags, :only => [:new, :edit]
27
28
 
29
+ def index
30
+ if params[:query].blank?
31
+ @contacts = Contact.scoped
32
+ else
33
+ search_terms = ActiveRecord::Base.sanitize("%#{params[:query]}%")
34
+ @contacts = Contact.where(Contact::SEARCHABLE_ATTRIBUTES.map { |attribute|
35
+ "#{Contact.table_name}.#{attribute} LIKE #{search_terms}"
36
+ }.join(" OR "))
37
+ end
38
+ respond_to do |format|
39
+ format.html {
40
+ @contacts = @contacts.page(params[:page] || 1).per(per_page_value_for_screen_size)
41
+ }
42
+ format.csv {
43
+ @columns = AlchemyCrm::Contact::EXPORTABLE_COLUMNS
44
+ send_data render_to_string, :content_type => 'text/csv', :disposition => 'attachment', :filename => "contacts-#{Time.now.strftime('%Y-%m-%d_%H-%M')}.csv"
45
+ }
46
+ end
47
+ end
48
+
28
49
  def new
29
50
  @contact = Contact.new(:country => ::I18n.locale.to_s.upcase)
30
51
  render :layout => false
@@ -66,7 +66,8 @@ module AlchemyCrm
66
66
  def destroy
67
67
  @delivery = Delivery.find(params[:id])
68
68
  @delivery.destroy
69
- render :js => "window.location.replace('#{admin_mailings_path}'); Alchemy.growl('#{successfully_canceled_delivery}')"
69
+ flash[:notice] = alchemy_crm_t(:successfully_canceled_delivery)
70
+ render :js => "window.location.replace('#{admin_mailings_path}')"
70
71
  end
71
72
 
72
73
  private
@@ -5,7 +5,7 @@ module AlchemyCrm
5
5
 
6
6
  acts_as_taggable
7
7
 
8
- attr_accessible(
8
+ ACCESSIBLE_ATTRIBUTES = [
9
9
  :salutation,
10
10
  :title,
11
11
  :firstname,
@@ -22,7 +22,10 @@ module AlchemyCrm
22
22
  :verified,
23
23
  :disabled,
24
24
  :tag_list
25
- )
25
+ ]
26
+
27
+ attr_accessible(*ACCESSIBLE_ATTRIBUTES)
28
+ attr_accessible(*ACCESSIBLE_ATTRIBUTES, :as => :admin)
26
29
 
27
30
  has_many :subscriptions, :dependent => :destroy
28
31
  has_many :newsletters, :through => :subscriptions, :uniq => true
@@ -34,7 +37,7 @@ module AlchemyCrm
34
37
  validates_presence_of field.to_sym
35
38
  end
36
39
  validates_presence_of :email
37
- validates_uniqueness_of :email
40
+ validates_uniqueness_of :email, :if => proc { email.present? }
38
41
  validates_format_of :email, :with => ::Authlogic::Regex.email, :if => proc { errors[:email].blank? }
39
42
 
40
43
  before_save :update_sha1, :if => proc { email_sha1.blank? || email_changed? }
@@ -44,16 +47,40 @@ module AlchemyCrm
44
47
  scope :enabled, where(:disabled => false)
45
48
  scope :available, verified.enabled
46
49
 
50
+ SEARCHABLE_ATTRIBUTES = [
51
+ "salutation",
52
+ "title",
53
+ "firstname",
54
+ "lastname",
55
+ "company",
56
+ "address",
57
+ "zip",
58
+ "city",
59
+ "country",
60
+ "email",
61
+ "phone",
62
+ "mobile",
63
+ "cached_tag_list"
64
+ ]
65
+
66
+ EXPORTABLE_COLUMNS = SEARCHABLE_ATTRIBUTES + [
67
+ "verified",
68
+ "disabled"
69
+ ]
70
+
47
71
  COLUMN_NAMES = [
48
- [::I18n.t(:title, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Title'), "title"],
49
72
  [::I18n.t(:salutation, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Salutation'), "salutation"],
73
+ [::I18n.t(:title, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Title'), "title"],
50
74
  [::I18n.t(:firstname, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Firstname'), "firstname"],
51
75
  [::I18n.t(:lastname, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Lastname'), "lastname"],
76
+ [::I18n.t(:company, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Company'), "company"],
52
77
  [::I18n.t(:address, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Address'), "address"],
53
78
  [::I18n.t(:zip, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Zipcode'), "zip"],
54
79
  [::I18n.t(:city, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'City'), "city"],
55
80
  [::I18n.t(:country, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Country'), "country"],
56
- [::I18n.t(:company, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Company'), "company"]
81
+ [::I18n.t(:email, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Email'), "email"],
82
+ [::I18n.t(:phone, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Phone'), "phone"],
83
+ [::I18n.t(:mobile, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => 'Mobile'), "mobile"]
57
84
  ]
58
85
 
59
86
  INTERPOLATION_NAME_METHODS = %w(fullname name_with_title firstname lastname name email)
@@ -0,0 +1,7 @@
1
+ <%- csv = CSV.generate(:col_sep => ";", :row_sep => "\r\n", :force_quotes => true) do |csv| -%>
2
+ <%- csv << @columns.map { |h| ::I18n.t(h, :scope => 'activerecord.attributes.alchemy_crm/contact', :default => h.humanize) } -%>
3
+ <%- @contacts.each do |contact| -%>
4
+ <%- csv << @columns.map { |a| value = contact.send(a).to_s.strip; a == 'salutation' && !value.blank? ? ::I18n.t(value.to_sym, :scope => 'alchemy_crm.salutations', :default => value) : value } -%>
5
+ <%- end -%>
6
+ <%- end -%>
7
+ <%=raw csv %>
@@ -29,6 +29,15 @@
29
29
  :size => '400x300'
30
30
  },
31
31
  :if_permitted_to => [:import, :alchemy_crm_admin_contacts]
32
+ },
33
+ {
34
+ :icon => :file_download,
35
+ :label => alchemy_crm_t(:export_contacts),
36
+ :url => alchemy_crm.admin_contacts_path(:format => :csv, :query => params[:query]),
37
+ :title => alchemy_crm_t(:export_contacts),
38
+ :overlay => false,
39
+ :loading_indicator => false,
40
+ :if_permitted_to => [:index, :alchemy_crm_admin_contacts]
32
41
  }
33
42
  ]
34
43
  ) %>
@@ -39,6 +39,6 @@
39
39
  <% end -%>
40
40
  </table>
41
41
 
42
- <p style="margin: 8px 0; height: 25px">>
42
+ <p style="margin: 8px 0; height: 25px">
43
43
  <%= link_to t(:continue), admin_contacts_path, :class => 'button' %>
44
44
  </p>
@@ -52,6 +52,7 @@ de:
52
52
  errors_while_importing: 'Es sind Fehler beim Importieren aufgetaucht!'
53
53
  errors_while_importing_contacts: 'Diese Kontakte konnten auf Grund von Fehlern nicht importiert werden:'
54
54
  export_contact: Kontakt exportieren
55
+ export_contacts: Kontakte exportieren
55
56
  fake_contact_attributes:
56
57
  firstname: Kim
57
58
  lastname: Muster
@@ -103,6 +104,7 @@ de:
103
104
  salutations:
104
105
  mr: Herr
105
106
  ms: Frau
107
+ mrs: Frau
106
108
  sent_mailings: 'Versendete Mailings'
107
109
  seperate_tags_with_comma: 'Mehrere Tags mit Komma trennen.'
108
110
  seperate_emails_with_comma: 'Die E-Mail-Adressen bitte mit Komma trennen.'
@@ -152,10 +154,10 @@ de:
152
154
  contact_group_contacts_count: Anzahl der Zielgruppenkontakte
153
155
  contact_groups: Zielgruppen
154
156
  alchemy_crm/contact:
155
- salutation: "Anrede*"
157
+ salutation: Anrede
156
158
  title: Titel
157
- firstname: "Vorname*"
158
- lastname: "Name*"
159
+ firstname: Vorname
160
+ lastname: Name
159
161
  company: Firma
160
162
  address: Adresse
161
163
  zip: PLZ
@@ -163,10 +165,11 @@ de:
163
165
  country: Land
164
166
  phone: Telefon
165
167
  mobile: Mobil
166
- email: "E-Mail*"
168
+ email: E-Mail
167
169
  verified: verifiziert
168
170
  disabled: abgemeldet
169
171
  tag_list: Tags
172
+ cached_tag_list: Tags
170
173
  alchemy_crm/contact_group:
171
174
  contacts_count: Anzahl der Kontakte
172
175
  errors:
@@ -23,6 +23,7 @@ en:
23
23
  salutations:
24
24
  mr: Mr
25
25
  ms: Ms
26
+ mrs: Mrs
26
27
  show_as_plain_text: "Show as plain text"
27
28
  show_statistics: "Statistics for %{name} from %{date}"
28
29
  subscribe_form:
@@ -33,10 +34,8 @@ en:
33
34
  activerecord:
34
35
  attributes:
35
36
  alchemy_crm/contact:
36
- salutation: "Salutation*"
37
- firstname: "Firstname*"
38
- lastname: "Lastname*"
39
37
  tag_list: Tags
38
+ cached_tag_list: Tags
40
39
  disabled: unsubscribed
41
40
  errors:
42
41
  models:
@@ -1,3 +1,3 @@
1
1
  module AlchemyCrm
2
- VERSION = "2.0.3"
2
+ VERSION = "2.0.4.1"
3
3
  end
@@ -1,3 +1,4 @@
1
+
1
2
  # These elements are added by the Alchemy CRM module.
2
3
 
3
4
  - name: newsletter_signup_form
@@ -1,3 +1,4 @@
1
+
1
2
  # These page layouts are added by the Alchemy CRM module.
2
3
 
3
4
  - name: newsletter_signup
@@ -16,8 +16,8 @@ module AlchemyCrm
16
16
  copy_file "newsletters.text.erb", "#{Rails.root}/app/views/layouts/alchemy/newsletters.text.erb"
17
17
  copy_file "newsletter_layouts.yml", "#{Rails.root}/config/alchemy/newsletter_layouts.yml"
18
18
 
19
- append_file "#{Rails.root}/config/alchemy/elements.yml", YAML.load_file(File.expand_path('files/elements.yml', File.dirname(__FILE__))).to_yaml.gsub(/^-{3}\s{2}/, "\n# These elements are added by the Alchemy CRM module.\n\n")
20
- append_file "#{Rails.root}/config/alchemy/page_layouts.yml", YAML.load_file(File.expand_path('files/page_layouts.yml', File.dirname(__FILE__))).to_yaml.gsub(/^^-{3}\s{2}/, "\n# These page layouts are added by the Alchemy CRM module.\n\n")
19
+ append_file "#{Rails.root}/config/alchemy/elements.yml", File.open(File.expand_path('files/elements.yml', File.dirname(__FILE__))).read
20
+ append_file "#{Rails.root}/config/alchemy/page_layouts.yml", File.open(File.expand_path('files/page_layouts.yml', File.dirname(__FILE__))).read
21
21
 
22
22
  end
23
23
 
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ module AlchemyCrm
4
+ describe Admin::ContactsController do
5
+
6
+ render_views
7
+
8
+ describe 'csv rendering' do
9
+
10
+ let(:contact) { FactoryGirl.create(:contact) }
11
+ let(:jane) { FactoryGirl.create(:contact, :salutation => 'ms', :firstname => 'Jane', :email => 'jane@doe.com') }
12
+
13
+ before do
14
+ activate_authlogic
15
+ Alchemy::UserSession.create FactoryGirl.create(:admin_user)
16
+ contact
17
+ end
18
+
19
+ it "should return contacts as attached csv file" do
20
+ get :index, :format => 'csv', :use_route => :alchemy_crm
21
+ response.content_type.should == 'text/csv'
22
+ response.headers['Content-Disposition'].should match /attachment/
23
+ end
24
+
25
+ it "csv file should contain translated headers" do
26
+ get :index, :format => 'csv', :use_route => :alchemy_crm
27
+ response.body.should match /Firstname/
28
+ end
29
+
30
+ it "csv file should contain translated salutation" do
31
+ get :index, :format => 'csv', :use_route => :alchemy_crm
32
+ response.body.should match /Mr/
33
+ end
34
+
35
+ it "contacts shouldn't be paginated" do
36
+ jane
37
+ controller.stub!(:per_page_value_for_screen_size).and_return(1)
38
+ get :index, :format => 'csv', :use_route => :alchemy_crm
39
+ response.body.should match /Jane/
40
+ end
41
+
42
+ it "filename should contain timestamp" do
43
+ get :index, :format => 'csv', :use_route => :alchemy_crm
44
+ response.headers['Content-Disposition'].should match /[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}/
45
+ end
46
+
47
+ context "with search query" do
48
+
49
+ before { jane }
50
+
51
+ it "should return only the matched contacts" do
52
+ get :index, :format => 'csv', :use_route => :alchemy_crm, :query => 'Jon'
53
+ response.body.should match /Jon/
54
+ response.body.should_not match /Jane/
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+ end
@@ -15,6 +15,10 @@ def configure
15
15
  require "rails/test_help"
16
16
  require "rspec/rails"
17
17
  require "email_spec"
18
+ require 'factory_girl'
19
+
20
+ require 'authlogic/test_case'
21
+ include Authlogic::TestCase
18
22
 
19
23
  ActionMailer::Base.delivery_method = :test
20
24
  ActionMailer::Base.perform_deliveries = true
@@ -0,0 +1,21 @@
1
+ FactoryGirl.define do
2
+
3
+ factory :user, :class => 'Alchemy::User' do
4
+ email 'john@doe.com'
5
+ login "jdoe"
6
+ password 's3cr3t'
7
+ password_confirmation 's3cr3t'
8
+
9
+ factory :admin_user do
10
+ role "admin"
11
+ end
12
+ end
13
+
14
+ factory :contact, :class => 'AlchemyCrm::Contact' do
15
+ salutation 'mr'
16
+ firstname 'Jon'
17
+ lastname 'Doe'
18
+ email 'jon@doe.com'
19
+ end
20
+
21
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy_crm
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-16 00:00:00.000000000 Z
12
+ date: 2012-09-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: alchemy_cms
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 2.1.9
21
+ version: 2.1.12
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: 2.1.9
29
+ version: 2.1.12
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: vcard
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -254,6 +254,7 @@ files:
254
254
  - app/views/alchemy_crm/admin/contacts/edit.html.erb
255
255
  - app/views/alchemy_crm/admin/contacts/import.html.erb
256
256
  - app/views/alchemy_crm/admin/contacts/import.js.erb
257
+ - app/views/alchemy_crm/admin/contacts/index.csv.erb
257
258
  - app/views/alchemy_crm/admin/contacts/index.html.erb
258
259
  - app/views/alchemy_crm/admin/contacts/new.html.erb
259
260
  - app/views/alchemy_crm/admin/contacts/vcf_import_result.html.erb
@@ -359,6 +360,7 @@ files:
359
360
  - lib/tasks/routes.rake
360
361
  - spec/alchemy_mailings_spec.rb
361
362
  - spec/config_spec.rb
363
+ - spec/controllers/alchemy_crm/admin/contacts_controller_spec.rb
362
364
  - spec/controllers/alchemy_crm/contacts_controller_spec.rb
363
365
  - spec/controllers/alchemy_crm/mailings_controller_spec.rb
364
366
  - spec/controllers/alchemy_crm/recipients_controller_spec.rb
@@ -402,6 +404,7 @@ files:
402
404
  - spec/models/alchemy_crm/mailing_spec.rb
403
405
  - spec/models/alchemy_crm/newsletter_spec.rb
404
406
  - spec/spec_helper.rb
407
+ - spec/support/factories.rb
405
408
  - vendor/assets/javascripts/autocomplete-rails.js
406
409
  homepage: http://alchemy-cms.com
407
410
  licenses:
@@ -418,7 +421,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
418
421
  version: '0'
419
422
  segments:
420
423
  - 0
421
- hash: 1964275261730037542
424
+ hash: -3633263896018909153
422
425
  required_rubygems_version: !ruby/object:Gem::Requirement
423
426
  none: false
424
427
  requirements:
@@ -427,7 +430,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
427
430
  version: '0'
428
431
  segments:
429
432
  - 0
430
- hash: 1964275261730037542
433
+ hash: -3633263896018909153
431
434
  requirements: []
432
435
  rubyforge_project:
433
436
  rubygems_version: 1.8.24
@@ -437,6 +440,7 @@ summary: A fully featured CRM / Newsletter and Mailings Module for Alchemy CMS.
437
440
  test_files:
438
441
  - spec/alchemy_mailings_spec.rb
439
442
  - spec/config_spec.rb
443
+ - spec/controllers/alchemy_crm/admin/contacts_controller_spec.rb
440
444
  - spec/controllers/alchemy_crm/contacts_controller_spec.rb
441
445
  - spec/controllers/alchemy_crm/mailings_controller_spec.rb
442
446
  - spec/controllers/alchemy_crm/recipients_controller_spec.rb
@@ -480,3 +484,4 @@ test_files:
480
484
  - spec/models/alchemy_crm/mailing_spec.rb
481
485
  - spec/models/alchemy_crm/newsletter_spec.rb
482
486
  - spec/spec_helper.rb
487
+ - spec/support/factories.rb