alchemy_crm 2.0.3 → 2.0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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