alchemy_crm 2.0.4.1 → 2.0.5
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.
- data/.travis.yml +1 -3
- data/alchemy_crm.gemspec +2 -1
- data/app/controllers/alchemy_crm/admin/contacts_controller.rb +17 -5
- data/app/views/alchemy_crm/admin/contacts/export.html.erb +32 -0
- data/app/views/alchemy_crm/admin/contacts/index.csv.erb +17 -7
- data/app/views/alchemy_crm/admin/contacts/index.html.erb +5 -3
- data/app/views/alchemy_crm/admin/contacts/index.xls.erb +34 -0
- data/config/initializers/xls_mime_type.rb +1 -0
- data/config/locales/alchemy_crm.de.yml +8 -1
- data/config/locales/alchemy_crm.en.yml +2 -0
- data/config/routes.rb +1 -0
- data/lib/alchemy_crm/version.rb +1 -1
- data/spec/controllers/alchemy_crm/admin/contacts_controller_spec.rb +77 -29
- metadata +9 -9
data/.travis.yml
CHANGED
@@ -1,12 +1,10 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 1.8.7
|
4
3
|
- 1.9.2
|
5
4
|
- 1.9.3
|
6
|
-
- ree
|
7
5
|
branches:
|
8
6
|
only:
|
9
7
|
- 2.0-stable
|
10
8
|
before_script:
|
11
|
-
- "sh -c 'cd spec/dummy
|
9
|
+
- "sh -c 'cd spec/dummy; RAILS_ENV=test bundle exec rake db:setup'"
|
12
10
|
script: "bundle exec rspec spec"
|
data/alchemy_crm.gemspec
CHANGED
@@ -9,6 +9,7 @@ Gem::Specification.new do |gem|
|
|
9
9
|
gem.summary = %q{A fully featured CRM / Newsletter and Mailings Module for Alchemy CMS.}
|
10
10
|
gem.homepage = "http://alchemy-cms.com"
|
11
11
|
gem.license = 'BSD New'
|
12
|
+
gem.required_ruby_version = '>= 1.9.2'
|
12
13
|
|
13
14
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
15
|
gem.files = `git ls-files`.split("\n")
|
@@ -19,7 +20,7 @@ Gem::Specification.new do |gem|
|
|
19
20
|
|
20
21
|
gem.add_dependency 'alchemy_cms', ["~> 2.1.12"]
|
21
22
|
gem.add_dependency 'vcard', ['~> 0.1.1']
|
22
|
-
gem.add_dependency 'csv_magic', ['~> 0.2.
|
23
|
+
gem.add_dependency 'csv_magic', ['~> 0.2.3']
|
23
24
|
gem.add_dependency 'delayed_job_active_record', ["~> 0.3.2"]
|
24
25
|
gem.add_dependency 'acts-as-taggable-on', ['~> 2.1.0']
|
25
26
|
gem.add_dependency 'rails3-jquery-autocomplete', ['~> 1.0.4']
|
@@ -40,8 +40,10 @@ module AlchemyCrm
|
|
40
40
|
@contacts = @contacts.page(params[:page] || 1).per(per_page_value_for_screen_size)
|
41
41
|
}
|
42
42
|
format.csv {
|
43
|
-
|
44
|
-
|
43
|
+
export_file_as(:csv)
|
44
|
+
}
|
45
|
+
format.xls {
|
46
|
+
export_file_as(:xls)
|
45
47
|
}
|
46
48
|
end
|
47
49
|
end
|
@@ -68,9 +70,13 @@ module AlchemyCrm
|
|
68
70
|
end
|
69
71
|
|
70
72
|
def export
|
71
|
-
|
72
|
-
|
73
|
-
|
73
|
+
if params[:id].present?
|
74
|
+
@contact = Contact.find(params[:id])
|
75
|
+
@contact.to_vcard
|
76
|
+
send_file("#{Rails.root.to_s}/tmp/#{@contact.fullname}.vcf")
|
77
|
+
else
|
78
|
+
render :layout => false
|
79
|
+
end
|
74
80
|
end
|
75
81
|
|
76
82
|
def autocomplete_tag_list
|
@@ -133,6 +139,12 @@ module AlchemyCrm
|
|
133
139
|
content.starts_with?("BEGIN:VCARD")
|
134
140
|
end
|
135
141
|
|
142
|
+
def export_file_as(format)
|
143
|
+
@columns = AlchemyCrm::Contact::EXPORTABLE_COLUMNS
|
144
|
+
filename = "#{AlchemyCrm::Contact.model_name.human(:count => @contacts.count)}-#{Time.now.strftime('%Y-%m-%d_%H-%M')}"
|
145
|
+
send_data render_to_string, :type => format.to_sym, :filename => "#{filename}.#{format}"
|
146
|
+
end
|
147
|
+
|
136
148
|
end
|
137
149
|
end
|
138
150
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<div class="with_padding">
|
2
|
+
<p><%= alchemy_crm_t('Please choose format') %></p>
|
3
|
+
<table id="export_format">
|
4
|
+
<tr>
|
5
|
+
<td class="submit">
|
6
|
+
<%= link_to(
|
7
|
+
'Excel',
|
8
|
+
alchemy_crm.admin_contacts_path(
|
9
|
+
:format => :xls,
|
10
|
+
:query => params[:query]
|
11
|
+
),
|
12
|
+
:class => 'button'
|
13
|
+
) %>
|
14
|
+
</td>
|
15
|
+
</tr>
|
16
|
+
<tr>
|
17
|
+
<td class="submit">
|
18
|
+
<%= link_to(
|
19
|
+
'CSV',
|
20
|
+
alchemy_crm.admin_contacts_path(
|
21
|
+
:format => :csv,
|
22
|
+
:query => params[:query]
|
23
|
+
),
|
24
|
+
:class => 'button'
|
25
|
+
) %>
|
26
|
+
</td>
|
27
|
+
</tr>
|
28
|
+
</table>
|
29
|
+
</div>
|
30
|
+
<script type="text/javascript">
|
31
|
+
$('.button', '#export_format').on('click', Alchemy.closeCurrentWindow);
|
32
|
+
</script>
|
@@ -1,7 +1,17 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
<% csv = CSV.generate(:col_sep => ";", :row_sep => "\r\n", :force_quotes => true) do |csv| %>
|
2
|
+
<% csv << @columns.map { |h| AlchemyCrm::Contact.human_attribute_name(h) } %>
|
3
|
+
<% @contacts.each do |contact| %>
|
4
|
+
<%
|
5
|
+
csv << @columns.map do |a|
|
6
|
+
value = contact.send(a).to_s.strip
|
7
|
+
if a == 'salutation' && !value.blank?
|
8
|
+
::I18n.t(value.to_sym, :scope => 'alchemy_crm.salutations', :default => value)
|
9
|
+
elsif !value.blank? && a == 'verified' || a == 'disabled'
|
10
|
+
alchemy_crm_t(value.to_sym)
|
11
|
+
else
|
12
|
+
value
|
13
|
+
end
|
14
|
+
end %>
|
15
|
+
<% end %>
|
16
|
+
<% end %>
|
17
|
+
<%= raw csv %>
|
@@ -33,10 +33,12 @@
|
|
33
33
|
{
|
34
34
|
:icon => :file_download,
|
35
35
|
:label => alchemy_crm_t(:export_contacts),
|
36
|
-
:url => alchemy_crm.
|
36
|
+
:url => alchemy_crm.export_admin_contacts_path(:query => params[:query]),
|
37
37
|
:title => alchemy_crm_t(:export_contacts),
|
38
|
-
:
|
39
|
-
|
38
|
+
:overlay_options => {
|
39
|
+
:title => alchemy_crm_t(:export_contacts),
|
40
|
+
:size => '200x150'
|
41
|
+
},
|
40
42
|
:if_permitted_to => [:index, :alchemy_crm_admin_contacts]
|
41
43
|
}
|
42
44
|
]
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
|
3
|
+
xmlns:o="urn:schemas-microsoft-com:office:office"
|
4
|
+
xmlns:x="urn:schemas-microsoft-com:office:excel"
|
5
|
+
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
|
6
|
+
xmlns:html="http://www.w3.org/TR/REC-html40">
|
7
|
+
<Worksheet ss:Name="<%= AlchemyCrm::Contact.model_name.human(:count => @contacts.count) -%>">
|
8
|
+
<Table>
|
9
|
+
<Row>
|
10
|
+
<% @columns.each do |col| %>
|
11
|
+
<Cell>
|
12
|
+
<Data ss:Type="String"><%= AlchemyCrm::Contact.human_attribute_name(col) %></Data>
|
13
|
+
</Cell>
|
14
|
+
<% end %>
|
15
|
+
</Row>
|
16
|
+
<% @contacts.each do |contact| %>
|
17
|
+
<Row>
|
18
|
+
<% @columns.each do |col| %>
|
19
|
+
<% value = contact.send(col).to_s.strip %>
|
20
|
+
<Cell>
|
21
|
+
<% if col == 'salutation' && !value.blank? %>
|
22
|
+
<Data ss:Type="String"><%= ::I18n.t(value.to_sym, :scope => 'alchemy_crm.salutations', :default => value) %></Data>
|
23
|
+
<% elsif !value.blank? && (col == 'verified' || col == 'disabled') %>
|
24
|
+
<Data ss:Type="String"><%= alchemy_crm_t(value) %></Data>
|
25
|
+
<% else %>
|
26
|
+
<Data ss:Type="String"><%= value %></Data>
|
27
|
+
<% end %>
|
28
|
+
</Cell>
|
29
|
+
<% end %>
|
30
|
+
</Row>
|
31
|
+
<% end %>
|
32
|
+
</Table>
|
33
|
+
</Worksheet>
|
34
|
+
</Workbook>
|
@@ -0,0 +1 @@
|
|
1
|
+
Mime::Type.register "application/xls", :xls
|
@@ -53,6 +53,7 @@ de:
|
|
53
53
|
errors_while_importing_contacts: 'Diese Kontakte konnten auf Grund von Fehlern nicht importiert werden:'
|
54
54
|
export_contact: Kontakt exportieren
|
55
55
|
export_contacts: Kontakte exportieren
|
56
|
+
'false': ''
|
56
57
|
fake_contact_attributes:
|
57
58
|
firstname: Kim
|
58
59
|
lastname: Muster
|
@@ -94,6 +95,7 @@ de:
|
|
94
95
|
or_replace_it_with_an_existing_tag: 'Oder Sie ersetzen es durch ein vorhandenes Tag'
|
95
96
|
please_check_highlighted_vcards_on_errors: "Bitte überprüfen Sie die markierten Visitenkarten auf Fehler."
|
96
97
|
please_choose: 'Bitte wählen'
|
98
|
+
'Please choose format': 'Bitte wählen Sie ein Format'
|
97
99
|
please_confirm: Bitte bestätigen
|
98
100
|
read_in_browser_notice: "Falls der Newsletter nicht richtig dargestellt wird, klicken Sie bitte %{link}."
|
99
101
|
remove_filter: 'Filter entfernen'
|
@@ -125,16 +127,21 @@ de:
|
|
125
127
|
signout_form:
|
126
128
|
button_label: abbestellen
|
127
129
|
statistics: Statistiken
|
130
|
+
tags_get_created_while_tagging_contacts: 'Tags werden automatisch erstellt, sobald Sie es bei einem Kontakt das erste mal verwenden.'
|
128
131
|
this_mailing_has_not_been_delivered_yet: 'Dieses Mailing wurde noch nie versendet'
|
129
132
|
this_list_shows_all_deliveries: Dies ist eine Liste aller Sendungen dieses Mailings
|
130
133
|
total_recipients_count: Empfänger insgesamt
|
131
|
-
|
134
|
+
'true': 'Ja'
|
132
135
|
without: ohne
|
133
136
|
you_can_rename_this_tag: "Sie können dieses Tag umbenennen"
|
134
137
|
you_can_open_statistics_for_delivered_mailings: Für bereits versendete Mailings können Statistiken aufgerufen werden
|
135
138
|
you_have_no_contact_groups_yet: 'Sie haben noch keine Empfänger Zielgruppen gebildet'
|
136
139
|
|
137
140
|
activerecord:
|
141
|
+
models:
|
142
|
+
alchemy_crm/contact:
|
143
|
+
one: Kontakt
|
144
|
+
other: Kontakte
|
138
145
|
attributes:
|
139
146
|
acts_as_taggable_on/tag:
|
140
147
|
contacts_count: Anzahl der Kontakte
|
@@ -13,6 +13,7 @@ en:
|
|
13
13
|
csv_format: 'A comma seperated file (.csv) with a list of contacts'
|
14
14
|
import_format_notice: 'You may import '
|
15
15
|
invalid_file_type: 'Invalid file type: %{mime_type}'
|
16
|
+
'false': ''
|
16
17
|
text_interpolation_notice: "Tip: You can insert the contact's name with %{name}."
|
17
18
|
mail_text_interpolation_notice: "Tip: You can insert the contact's name with %{name}. Please insert the confirmation link with %{link}."
|
18
19
|
mandatory_fields: "*Mandatory"
|
@@ -30,6 +31,7 @@ en:
|
|
30
31
|
button_label: subscribe
|
31
32
|
signout_form:
|
32
33
|
button_label: unsubscribe
|
34
|
+
'true': 'Yes'
|
33
35
|
|
34
36
|
activerecord:
|
35
37
|
attributes:
|
data/config/routes.rb
CHANGED
data/lib/alchemy_crm/version.rb
CHANGED
@@ -5,7 +5,7 @@ module AlchemyCrm
|
|
5
5
|
|
6
6
|
render_views
|
7
7
|
|
8
|
-
describe '
|
8
|
+
describe 'exporting contacts' do
|
9
9
|
|
10
10
|
let(:contact) { FactoryGirl.create(:contact) }
|
11
11
|
let(:jane) { FactoryGirl.create(:contact, :salutation => 'ms', :firstname => 'Jane', :email => 'jane@doe.com') }
|
@@ -16,42 +16,90 @@ module AlchemyCrm
|
|
16
16
|
contact
|
17
17
|
end
|
18
18
|
|
19
|
-
|
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
|
19
|
+
context "as csv file" do
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
it "should return contacts as attached csv file" do
|
22
|
+
get :index, :format => 'csv', :use_route => :alchemy_crm
|
23
|
+
response.content_type.should == 'text/csv'
|
24
|
+
response.headers['Content-Disposition'].should match /attachment/
|
25
|
+
end
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
it "file should contain translated headers" do
|
28
|
+
get :index, :format => 'csv', :use_route => :alchemy_crm
|
29
|
+
response.body.should match /Firstname/
|
30
|
+
end
|
34
31
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
32
|
+
it "file should contain translated salutation" do
|
33
|
+
get :index, :format => 'csv', :use_route => :alchemy_crm
|
34
|
+
response.body.should match /Mr/
|
35
|
+
end
|
36
|
+
|
37
|
+
it "contacts shouldn't be paginated" do
|
38
|
+
jane
|
39
|
+
controller.stub!(:per_page_value_for_screen_size).and_return(1)
|
40
|
+
get :index, :format => 'csv', :use_route => :alchemy_crm
|
41
|
+
response.body.should match /Jane/
|
42
|
+
end
|
43
|
+
|
44
|
+
it "filename should contain timestamp" do
|
45
|
+
get :index, :format => 'csv', :use_route => :alchemy_crm
|
46
|
+
response.headers['Content-Disposition'].should match /[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}/
|
47
|
+
end
|
48
|
+
|
49
|
+
context "with search query" do
|
50
|
+
|
51
|
+
before { jane }
|
52
|
+
|
53
|
+
it "should return only the matched contacts" do
|
54
|
+
get :index, :format => 'csv', :use_route => :alchemy_crm, :query => 'Jon'
|
55
|
+
response.body.should match /Jon/
|
56
|
+
response.body.should_not match /Jane/
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
41
60
|
|
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
61
|
end
|
46
62
|
|
47
|
-
context "
|
63
|
+
context "as xls file" do
|
64
|
+
|
65
|
+
it "should return contacts as attached xls file" do
|
66
|
+
get :index, :format => 'xls', :use_route => :alchemy_crm
|
67
|
+
response.content_type.should == 'application/xls'
|
68
|
+
response.headers['Content-Disposition'].should match /attachment/
|
69
|
+
end
|
70
|
+
|
71
|
+
it "file should contain translated headers" do
|
72
|
+
get :index, :format => 'xls', :use_route => :alchemy_crm
|
73
|
+
response.body.should match /Firstname/
|
74
|
+
end
|
75
|
+
|
76
|
+
it "file should contain translated salutation" do
|
77
|
+
get :index, :format => 'xls', :use_route => :alchemy_crm
|
78
|
+
response.body.should match /Mr/
|
79
|
+
end
|
80
|
+
|
81
|
+
it "contacts shouldn't be paginated" do
|
82
|
+
jane
|
83
|
+
controller.stub!(:per_page_value_for_screen_size).and_return(1)
|
84
|
+
get :index, :format => 'xls', :use_route => :alchemy_crm
|
85
|
+
response.body.should match /Jane/
|
86
|
+
end
|
87
|
+
|
88
|
+
it "filename should contain timestamp" do
|
89
|
+
get :index, :format => 'xls', :use_route => :alchemy_crm
|
90
|
+
response.headers['Content-Disposition'].should match /[0-9]{4}-[0-9]{2}-[0-9]{2}_[0-9]{2}-[0-9]{2}/
|
91
|
+
end
|
92
|
+
|
93
|
+
context "with search query" do
|
94
|
+
|
95
|
+
before { jane }
|
48
96
|
|
49
|
-
|
97
|
+
it "should return only the matched contacts" do
|
98
|
+
get :index, :format => 'xls', :use_route => :alchemy_crm, :query => 'Jon'
|
99
|
+
response.body.should match /Jon/
|
100
|
+
response.body.should_not match /Jane/
|
101
|
+
end
|
50
102
|
|
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
103
|
end
|
56
104
|
|
57
105
|
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.
|
4
|
+
version: 2.0.5
|
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-09-
|
12
|
+
date: 2012-09-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: alchemy_cms
|
@@ -50,7 +50,7 @@ dependencies:
|
|
50
50
|
requirements:
|
51
51
|
- - ~>
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.2.
|
53
|
+
version: 0.2.3
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -58,7 +58,7 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.2.
|
61
|
+
version: 0.2.3
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: delayed_job_active_record
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -252,10 +252,12 @@ files:
|
|
252
252
|
- app/views/alchemy_crm/admin/contacts/_form.html.erb
|
253
253
|
- app/views/alchemy_crm/admin/contacts/destroy.rjs
|
254
254
|
- app/views/alchemy_crm/admin/contacts/edit.html.erb
|
255
|
+
- app/views/alchemy_crm/admin/contacts/export.html.erb
|
255
256
|
- app/views/alchemy_crm/admin/contacts/import.html.erb
|
256
257
|
- app/views/alchemy_crm/admin/contacts/import.js.erb
|
257
258
|
- app/views/alchemy_crm/admin/contacts/index.csv.erb
|
258
259
|
- app/views/alchemy_crm/admin/contacts/index.html.erb
|
260
|
+
- app/views/alchemy_crm/admin/contacts/index.xls.erb
|
259
261
|
- app/views/alchemy_crm/admin/contacts/new.html.erb
|
260
262
|
- app/views/alchemy_crm/admin/contacts/vcf_import_result.html.erb
|
261
263
|
- app/views/alchemy_crm/admin/deliveries/_delivery.html.erb
|
@@ -305,6 +307,7 @@ files:
|
|
305
307
|
- config/authorization_rules.rb
|
306
308
|
- config/initializers/assets.rb
|
307
309
|
- config/initializers/delayed_job.rb
|
310
|
+
- config/initializers/xls_mime_type.rb
|
308
311
|
- config/locales/alchemy.de.yml
|
309
312
|
- config/locales/alchemy.en.yml
|
310
313
|
- config/locales/alchemy_crm.de.yml
|
@@ -418,10 +421,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
418
421
|
requirements:
|
419
422
|
- - ! '>='
|
420
423
|
- !ruby/object:Gem::Version
|
421
|
-
version:
|
422
|
-
segments:
|
423
|
-
- 0
|
424
|
-
hash: -3633263896018909153
|
424
|
+
version: 1.9.2
|
425
425
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
426
426
|
none: false
|
427
427
|
requirements:
|
@@ -430,7 +430,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
430
430
|
version: '0'
|
431
431
|
segments:
|
432
432
|
- 0
|
433
|
-
hash:
|
433
|
+
hash: 1068326471216601821
|
434
434
|
requirements: []
|
435
435
|
rubyforge_project:
|
436
436
|
rubygems_version: 1.8.24
|