radiant-database_mailer-extension 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +159 -0
- data/Rakefile +120 -0
- data/app/controllers/admin/form_datas_controller.rb +77 -0
- data/app/controllers/database_mailer_processing.rb +19 -0
- data/app/helpers/admin/form_datas_helper.rb +57 -0
- data/app/models/form_data.rb +93 -0
- data/app/models/form_data_asset.rb +14 -0
- data/app/views/admin/form_datas/_export.html.haml +33 -0
- data/app/views/admin/form_datas/_filters.html.haml +27 -0
- data/app/views/admin/form_datas/index.html.haml +34 -0
- data/app/views/admin/form_datas/show.html.haml +49 -0
- data/config/routes.rb +7 -0
- data/database_mailer_extension.rb +31 -0
- data/db/migrate/001_create_form_datas.rb +16 -0
- data/db/migrate/002_add_data_columns.rb +13 -0
- data/db/migrate/20090722135916_create_form_data_assets.rb +21 -0
- data/features/datasets/database_mailer_dataset.rb +19 -0
- data/features/datasets/mailers_dataset.rb +69 -0
- data/features/fixtures/attachment.jpg +0 -0
- data/features/saving_emails_to_database.feature +45 -0
- data/features/step_definitions/admin_steps.rb +6 -0
- data/features/step_definitions/email_steps.rb +73 -0
- data/features/step_definitions/form_data_steps.rb +3 -0
- data/features/step_definitions/webrat_steps.rb +119 -0
- data/features/support/env.rb +28 -0
- data/features/support/paths.rb +25 -0
- data/lib/radiant-database_mailer-extension.rb +8 -0
- data/lib/tasks/database_mailer_extension_tasks.rake +31 -0
- data/public/javascripts/admin/database_mailer.js +73 -0
- data/public/stylesheets/sass/admin/database_mailer.sass +235 -0
- data/radiant-database_mailer-extension.gemspec +26 -0
- data/spec/controllers/form_datas_controller_spec.rb +272 -0
- data/spec/controllers/mail_controller_spec.rb +40 -0
- data/spec/helpers/form_datas_helper_spec.rb +5 -0
- data/spec/models/form_data_asset_spec.rb +11 -0
- data/spec/models/form_data_spec.rb +151 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/views/index.html.erb_spec.rb +25 -0
- metadata +139 -0
data/README.md
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
Database Mailer
|
2
|
+
===
|
3
|
+
|
4
|
+
About
|
5
|
+
---
|
6
|
+
|
7
|
+
A [Radiant][rd] Extension by [Aissac][ai] that adds database persistence to emailed forms. It works on top of the Radiant [Mailer Extension][rme] and the fields recorded to the database are user defined. The extension adds a tab to the Radiant admin interface allowing you to browse saved records.
|
8
|
+
|
9
|
+
Tested on Radiant 0.7.1, 0.8 and 0.9 RC1.
|
10
|
+
|
11
|
+
Check out the [screencast][rce]
|
12
|
+
|
13
|
+
Features
|
14
|
+
---
|
15
|
+
|
16
|
+
* Save posted form fields and entire mail message to the database
|
17
|
+
* Save e-mail attachments using paperclip
|
18
|
+
* Configurable save-to-database for mailer forms
|
19
|
+
* Add fields to be saved without loosing data
|
20
|
+
* Admin interface to browse saved records
|
21
|
+
* Export data to CSV and XLS
|
22
|
+
|
23
|
+
Important Notice!
|
24
|
+
---
|
25
|
+
|
26
|
+
The git branches on this repository hold stable versions of the extension for older versions of Radiant CMS. For example the _0.8_ branch is compatible with Radiant 0.8.
|
27
|
+
|
28
|
+
To checkout one of these branches:
|
29
|
+
|
30
|
+
git clone git://github.com/Aissac/radiant-database-mailer-extension.git vendor/extensions/database_mailer
|
31
|
+
cd vendor/extensions/database_mailer
|
32
|
+
git checkout -b <branch-name> origin/<remote-branch-name>
|
33
|
+
|
34
|
+
As an example if you're working on Radiant 0.8 you will need to checkout the 0.8 branch:
|
35
|
+
|
36
|
+
cd vendor/extensions/database_mailer
|
37
|
+
git checkout -b my_branch origin/0.8
|
38
|
+
|
39
|
+
Installation
|
40
|
+
---
|
41
|
+
|
42
|
+
Radiant Database Mailer Extension has three dependecies, the Radiant Mailer Extension, the `will_paginate` gem/plugin and the `paperclip` gem/plugin
|
43
|
+
|
44
|
+
Install the `mailer` extension:
|
45
|
+
|
46
|
+
git clone git://github.com/radiant/radiant-mailer-extension.git vendor/extensions/mailer
|
47
|
+
|
48
|
+
###Note
|
49
|
+
|
50
|
+
At the time being you will need Aissac's version of the [Radiant Mailer Extension][arme], as it incorporates sending e-mails with attachments.
|
51
|
+
|
52
|
+
the `will_paginate` gem/plugin:
|
53
|
+
|
54
|
+
git clone git://github.com/mislav/will_paginate.git vendor/plugins/will_paginate
|
55
|
+
|
56
|
+
or
|
57
|
+
|
58
|
+
sudo gem install will_paginate
|
59
|
+
|
60
|
+
and the `paperclip` gem/plugin
|
61
|
+
|
62
|
+
git clone git://github.com/thoughtbot/paperclip.git vendor/plugins/paperclip
|
63
|
+
|
64
|
+
or
|
65
|
+
|
66
|
+
sudo gem install paperclip
|
67
|
+
|
68
|
+
Next edit `config/environment.rb` and add desired fields to be recorded:
|
69
|
+
|
70
|
+
DATABASE_MAILER_COLUMNS = {
|
71
|
+
:name => :string,
|
72
|
+
:message => :text,
|
73
|
+
:email => :string
|
74
|
+
}
|
75
|
+
|
76
|
+
And finally add the [Database Mailer Extension][rdme]:
|
77
|
+
|
78
|
+
git clone git://github.com/Aissac/radiant-database-mailer-extension.git vendor/extensions/database_mailer
|
79
|
+
|
80
|
+
Migrate and update the extension:
|
81
|
+
|
82
|
+
rake radiant:extensions:database_mailer:migrate
|
83
|
+
rake radiant:extensions:database_mailer:update
|
84
|
+
|
85
|
+
Configuration
|
86
|
+
---
|
87
|
+
|
88
|
+
Adding fields to the `DATABASE_MAILER_COLUMNS` hash and re-running `rake radiant:extensions:database_mailer:migrate` nondestructively adds fields to be saved. Fields removed from the hash are not deleted.
|
89
|
+
|
90
|
+
Look at the Mailer Extension README for information on how to configure mail delivery.
|
91
|
+
|
92
|
+
If you set `save_to_database` to false in the Mailer config, saving to the database is skipped and just mail delivery takes place. Example (in the `mailer` page part):
|
93
|
+
|
94
|
+
subject: From the website of Whatever
|
95
|
+
from: noreply@example.com
|
96
|
+
redirect_to: /contact/thank-you
|
97
|
+
save_to_database: false
|
98
|
+
recipients:
|
99
|
+
- one@one.com
|
100
|
+
- two@two.com
|
101
|
+
|
102
|
+
Any attachments that the e-mail might have will be saved on the file system. They can be downloaded from the details page of every record.
|
103
|
+
|
104
|
+
If you want to take advantage of the blob field you need to create a `email` page part. The blob field keeps the sent version of the email.
|
105
|
+
|
106
|
+
Fields that are not specified by `DATABASE_MAILER_COLUMNS` are silently ignored.
|
107
|
+
|
108
|
+
Usage
|
109
|
+
---
|
110
|
+
|
111
|
+
Create your Mailer pages and make sure to use the same field names:
|
112
|
+
|
113
|
+
<r:mailer:form>
|
114
|
+
<label for="name">Name:</label><br/>
|
115
|
+
<r:mailer:text name="name" /><br/>
|
116
|
+
|
117
|
+
<label for="email">Email:</label><br/>
|
118
|
+
<r:mailer:text name="email" /><br/>
|
119
|
+
|
120
|
+
<label for="message">Message:</label><br/>
|
121
|
+
<r:mailer:textarea name="message" /> <br/>
|
122
|
+
|
123
|
+
<label for="attachment">Image:</label><br/>
|
124
|
+
<r:mailer:file name="attachment" /><br/>
|
125
|
+
|
126
|
+
<input type="submit" value="Send" />
|
127
|
+
</r:mailer:form>
|
128
|
+
|
129
|
+
Create the `mailer` page part:
|
130
|
+
|
131
|
+
subject: From the website of Whatever
|
132
|
+
from: noreply@example.com
|
133
|
+
redirect_to: /contact/thank-you
|
134
|
+
recipients:
|
135
|
+
- one@one.com
|
136
|
+
- two@two.com
|
137
|
+
|
138
|
+
Create an `email` page part (to take advantage of the blob field):
|
139
|
+
|
140
|
+
<r:mailer>
|
141
|
+
Name: <r:get name="name" />
|
142
|
+
Email: <r:get name="email" />
|
143
|
+
Message: <r:get name="message" />
|
144
|
+
</r:mailer>
|
145
|
+
|
146
|
+
Contributors
|
147
|
+
---
|
148
|
+
|
149
|
+
* Cristi Duma ([@cristi_duma][cd])
|
150
|
+
* Istvan Hoka ([@ihoka][ih])
|
151
|
+
|
152
|
+
[rd]: http://radiantcms.org/
|
153
|
+
[ai]: http://www.aissac.ro/
|
154
|
+
[rme]: http://github.com/radiant/radiant-mailer-extension
|
155
|
+
[arme]: http://github.com/Aissac/radiant-mailer-extension
|
156
|
+
[rdme]: http://blog.aissac.ro/radiant/database-mailer-extension/
|
157
|
+
[cd]: http://twitter.com/cristi_duma
|
158
|
+
[ih]: http://twitter.com/ihoka
|
159
|
+
[rce]:http://blog.aissac.ro/2010/03/16/episode-5-radiant-database-mailer-extension/
|
data/Rakefile
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
# I think this is the one that should be moved to the extension Rakefile template
|
2
|
+
|
3
|
+
# In rails 1.2, plugins aren't available in the path until they're loaded.
|
4
|
+
# Check to see if the rspec plugin is installed first and require
|
5
|
+
# it if it is. If not, use the gem version.
|
6
|
+
|
7
|
+
# Determine where the RSpec plugin is by loading the boot
|
8
|
+
unless defined? RADIANT_ROOT
|
9
|
+
ENV["RAILS_ENV"] = "test"
|
10
|
+
case
|
11
|
+
when ENV["RADIANT_ENV_FILE"]
|
12
|
+
require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
|
13
|
+
when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
|
14
|
+
require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
|
15
|
+
else
|
16
|
+
require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake'
|
21
|
+
require 'rake/rdoctask'
|
22
|
+
require 'rake/testtask'
|
23
|
+
|
24
|
+
rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
|
25
|
+
$LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
|
26
|
+
require 'spec/rake/spectask'
|
27
|
+
# require 'spec/translator'
|
28
|
+
|
29
|
+
# Cleanup the RADIANT_ROOT constant so specs will load the environment
|
30
|
+
Object.send(:remove_const, :RADIANT_ROOT)
|
31
|
+
|
32
|
+
extension_root = File.expand_path(File.dirname(__FILE__))
|
33
|
+
|
34
|
+
task :default => :spec
|
35
|
+
task :stats => "spec:statsetup"
|
36
|
+
|
37
|
+
desc "Run all specs in spec directory"
|
38
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
39
|
+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
|
40
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
41
|
+
end
|
42
|
+
|
43
|
+
namespace :spec do
|
44
|
+
desc "Run all specs in spec directory with RCov"
|
45
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
46
|
+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
|
47
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
48
|
+
t.rcov = true
|
49
|
+
t.rcov_opts = ["--exclude", "spec/*,gems/*", "--rails"]
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "Print Specdoc for all specs"
|
53
|
+
Spec::Rake::SpecTask.new(:doc) do |t|
|
54
|
+
t.spec_opts = ["--format", "specdoc", "--dry-run"]
|
55
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
56
|
+
end
|
57
|
+
|
58
|
+
[:models, :controllers, :views, :helpers].each do |sub|
|
59
|
+
desc "Run the specs under spec/#{sub}"
|
60
|
+
Spec::Rake::SpecTask.new(sub) do |t|
|
61
|
+
t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
|
62
|
+
t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Hopefully no one has written their extensions in pre-0.9 style
|
67
|
+
# desc "Translate specs from pre-0.9 to 0.9 style"
|
68
|
+
# task :translate do
|
69
|
+
# translator = ::Spec::Translator.new
|
70
|
+
# dir = RAILS_ROOT + '/spec'
|
71
|
+
# translator.translate(dir, dir)
|
72
|
+
# end
|
73
|
+
|
74
|
+
# Setup specs for stats
|
75
|
+
task :statsetup do
|
76
|
+
require 'code_statistics'
|
77
|
+
::STATS_DIRECTORIES << %w(Model\ specs spec/models)
|
78
|
+
::STATS_DIRECTORIES << %w(View\ specs spec/views)
|
79
|
+
::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
|
80
|
+
::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
|
81
|
+
::CodeStatistics::TEST_TYPES << "Model specs"
|
82
|
+
::CodeStatistics::TEST_TYPES << "View specs"
|
83
|
+
::CodeStatistics::TEST_TYPES << "Controller specs"
|
84
|
+
::CodeStatistics::TEST_TYPES << "Helper specs"
|
85
|
+
::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
|
86
|
+
end
|
87
|
+
|
88
|
+
namespace :db do
|
89
|
+
namespace :fixtures do
|
90
|
+
desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
|
91
|
+
task :load => :environment do
|
92
|
+
require 'active_record/fixtures'
|
93
|
+
ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
|
94
|
+
(ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
|
95
|
+
Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
desc 'Generate documentation for the database_mailer extension.'
|
103
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
104
|
+
rdoc.rdoc_dir = 'rdoc'
|
105
|
+
rdoc.title = 'DatabaseMailerExtension'
|
106
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
107
|
+
rdoc.rdoc_files.include('README')
|
108
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
109
|
+
end
|
110
|
+
|
111
|
+
# For extensions that are in transition
|
112
|
+
desc 'Test the database_mailer extension.'
|
113
|
+
Rake::TestTask.new(:test) do |t|
|
114
|
+
t.libs << 'lib'
|
115
|
+
t.pattern = 'test/**/*_test.rb'
|
116
|
+
t.verbose = true
|
117
|
+
end
|
118
|
+
|
119
|
+
# Load any custom rakefiles for extension
|
120
|
+
Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
|
@@ -0,0 +1,77 @@
|
|
1
|
+
class Admin::FormDatasController < ApplicationController
|
2
|
+
|
3
|
+
require 'fastercsv'
|
4
|
+
before_filter :attach_assets
|
5
|
+
LIST_PARAMS_BASE = [:page, :sort_by, :sort_order]
|
6
|
+
EXPORT_COLUMNS = FormData::SORT_COLUMNS.sort - ["exported"] + ["blob"]
|
7
|
+
def index
|
8
|
+
|
9
|
+
@urls = FormData.find_all_group_by_url
|
10
|
+
filter_by_params(FormData::FILTER_COLUMNS)
|
11
|
+
respond_to do |format|
|
12
|
+
format.html {
|
13
|
+
@saved_items = FormData.form_paginate(list_params)
|
14
|
+
}
|
15
|
+
|
16
|
+
exported_at = Time.now
|
17
|
+
selected_export_columns = EXPORT_COLUMNS.reject{|k| params["export_#{k}"].blank?}
|
18
|
+
|
19
|
+
format.csv {
|
20
|
+
csv_string = FormData.export_csv(list_params, selected_export_columns, exported_at, !params[:include_all].blank?)
|
21
|
+
send_data csv_string,
|
22
|
+
:type => "text/csv",
|
23
|
+
:filename => "export_#{exported_at.strftime("%Y-%m-%d_%H-%M")}.csv",
|
24
|
+
:disposition => 'attachment'
|
25
|
+
}
|
26
|
+
format.xls {
|
27
|
+
xls_path = FormData.export_xls(list_params, selected_export_columns, exported_at, !params[:include_all].blank?)
|
28
|
+
send_file xls_path,
|
29
|
+
:type => "application/vnd.ms-excel",
|
30
|
+
:filename => "form_data_#{exported_at.strftime("%Y-%m-%d_%H-%M")}.xls",
|
31
|
+
:disposition => 'attachment'
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def show
|
37
|
+
@form_data = FormData.find(params[:id])
|
38
|
+
end
|
39
|
+
|
40
|
+
def destroy
|
41
|
+
@form_data = FormData.find(params[:id])
|
42
|
+
@form_data.destroy
|
43
|
+
flash[:notice] = "Record deleted!"
|
44
|
+
redirect_to admin_form_datas_path
|
45
|
+
end
|
46
|
+
|
47
|
+
def list_params
|
48
|
+
@list_params ||= {}
|
49
|
+
end
|
50
|
+
helper_method :list_params
|
51
|
+
|
52
|
+
protected
|
53
|
+
def filter_by_params(args)
|
54
|
+
args = args + LIST_PARAMS_BASE
|
55
|
+
args.each do |arg|
|
56
|
+
list_params[arg] = params[:reset] ? params[arg] : params[arg] || cookies[arg]
|
57
|
+
end
|
58
|
+
list_params[:page] ||= "1"
|
59
|
+
|
60
|
+
update_list_params_cookies(args)
|
61
|
+
|
62
|
+
# pentru will_paginate
|
63
|
+
params[:page] = list_params[:page]
|
64
|
+
end
|
65
|
+
|
66
|
+
def update_list_params_cookies(args)
|
67
|
+
args.each do |key|
|
68
|
+
cookies[key] = { :value => list_params[key], :path => "/#{controller_path}" }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def attach_assets
|
73
|
+
include_stylesheet "admin/database_mailer"
|
74
|
+
include_javascript "admin/database_mailer"
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module DatabaseMailerProcessing
|
2
|
+
|
3
|
+
def process_mail_with_database(mail, config)
|
4
|
+
if mail.valid?
|
5
|
+
page = mail.page
|
6
|
+
plain_body = (page.part( :email ) ? page.render_part( :email ) : page.render_part( :email_plain ))
|
7
|
+
|
8
|
+
if config[:save_to_database] || config[:save_to_database].nil?
|
9
|
+
fd = FormData.create(mail.data.merge(:url => mail.page.url, :blob => plain_body))
|
10
|
+
mail.data.each do |k, v|
|
11
|
+
if v.class.to_s == "Tempfile"
|
12
|
+
FormDataAsset.create(:form_data_id => fd.id, :field_name => k, :attachment => v)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
process_mail_without_database(mail, config)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Admin::FormDatasHelper
|
2
|
+
SORT_CYCLE = {'asc' => 'desc', 'desc' => 'none', 'none' => 'asc'}
|
3
|
+
|
4
|
+
def sortable_column_head(label, attribute)
|
5
|
+
current_order = (currently_sorting_by?(attribute) && %w(none asc desc).include?(list_params[:sort_order])) ? list_params[:sort_order] : 'none'
|
6
|
+
dom_class = currently_sorting_by?(attribute) ? "sort_#{current_order}" : nil
|
7
|
+
|
8
|
+
link_to(label,
|
9
|
+
params.merge(list_params).merge(:sort_by => attribute, :sort_order => SORT_CYCLE[current_order], :reset => 1),
|
10
|
+
:class => dom_class)
|
11
|
+
end
|
12
|
+
|
13
|
+
def filter_actions_tag
|
14
|
+
submit_tag("Filter") + content_tag('span', ' | ' + reset_filters_tag)
|
15
|
+
end
|
16
|
+
|
17
|
+
def reset_filters_tag
|
18
|
+
link_to("Reset", :reset => 1)
|
19
|
+
end
|
20
|
+
|
21
|
+
def each_data_column(&block)
|
22
|
+
DATABASE_MAILER_COLUMNS.each_key do |key|
|
23
|
+
yield key
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def data_columns
|
28
|
+
DATABASE_MAILER_COLUMNS.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def date_format(timestamp)
|
32
|
+
timestamp && l(timestamp, :format => :long)
|
33
|
+
end
|
34
|
+
|
35
|
+
def filters_present(&block)
|
36
|
+
if (DATABASE_MAILER_COLUMNS.keys + [:url]).any? { |k| !list_params[k].blank?}
|
37
|
+
yield
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_filters
|
42
|
+
all_filters = DATABASE_MAILER_COLUMNS.keys + [:url]
|
43
|
+
all_filters.map do |k|
|
44
|
+
k unless list_params[k].blank?
|
45
|
+
end.compact.join(", ")
|
46
|
+
end
|
47
|
+
|
48
|
+
def export_columns
|
49
|
+
Admin::FormDatasController::EXPORT_COLUMNS
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def currently_sorting_by?(attribute)
|
55
|
+
list_params[:sort_by] == attribute.to_s
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'fastercsv'
|
2
|
+
require 'spreadsheet'
|
3
|
+
|
4
|
+
class FormData < ActiveRecord::Base
|
5
|
+
|
6
|
+
has_many :form_data_assets, :dependent => :destroy
|
7
|
+
|
8
|
+
SORT_COLUMNS = DATABASE_MAILER_COLUMNS.keys.map(&:to_s) + ['created_at', 'url', 'exported']
|
9
|
+
FILTER_COLUMNS = DATABASE_MAILER_COLUMNS.keys + [:url]
|
10
|
+
|
11
|
+
DATABASE_MAILER_COLUMNS.each_key do | col |
|
12
|
+
FormData.named_scope :"by_#{col}", lambda { |item|
|
13
|
+
{:conditions => ["LOWER(#{col}) LIKE ?", "%#{item.to_s.downcase}%"]}
|
14
|
+
}
|
15
|
+
end
|
16
|
+
named_scope :by_url, lambda{ |item| {:conditions => ["url = ?", item]}}
|
17
|
+
named_scope :not_exported, :conditions => {:exported => nil}
|
18
|
+
|
19
|
+
def self.form_paginate(params)
|
20
|
+
options = {
|
21
|
+
:page => params[:page],
|
22
|
+
:per_page => 10,
|
23
|
+
}
|
24
|
+
if SORT_COLUMNS.include?(params[:sort_by]) && %w(asc desc).include?(params[:sort_order])
|
25
|
+
options[:order] = "#{params[:sort_by]} #{params[:sort_order]}"
|
26
|
+
end
|
27
|
+
params.reject { |k, v| !FILTER_COLUMNS.include?(k) }.
|
28
|
+
inject(FormData) { |scope, pair| pair[1].blank? ? scope : scope.send(:"by_#{pair[0]}", pair[1]) }.
|
29
|
+
paginate(options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.find_all_group_by_url
|
33
|
+
find(:all, :group => 'url', :select => 'url')
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.find_for_export(params, export_all)
|
37
|
+
options = {}
|
38
|
+
if SORT_COLUMNS.include?(params[:sort_by]) && %w(asc desc).include?(params[:sort_order])
|
39
|
+
options[:order] = "#{params[:sort_by]} #{params[:sort_order]}"
|
40
|
+
end
|
41
|
+
|
42
|
+
initial = export_all ? FormData : FormData.not_exported
|
43
|
+
|
44
|
+
params.reject { |k, v| !FILTER_COLUMNS.include?(k) }.
|
45
|
+
inject(initial) { |scope, pair| pair[1].blank? ? scope : scope.send(:"by_#{pair[0]}", pair[1]) }.find(:all, :order => options[:order])
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.export_csv(params, selected_export_columns, exported_at, export_all=false)
|
49
|
+
@items = find_for_export(params, export_all)
|
50
|
+
|
51
|
+
FasterCSV.generate do |csv|
|
52
|
+
csv << selected_export_columns.map{|k| k.capitalize}
|
53
|
+
@items.each do |ei|
|
54
|
+
csv << selected_export_columns.map do |k|
|
55
|
+
formatting_for_csv(ei.send(k))
|
56
|
+
end
|
57
|
+
ei.exported = exported_at.to_s(:db)
|
58
|
+
ei.save
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.export_xls(params, selected_export_columns, exported_at, export_all=false)
|
64
|
+
items = find_for_export(params, export_all)
|
65
|
+
book = Spreadsheet::Workbook.new
|
66
|
+
sheet = book.create_worksheet :name => 'Form Data'
|
67
|
+
|
68
|
+
sheet.row(0).replace(selected_export_columns.map{|k| k.capitalize})
|
69
|
+
|
70
|
+
items.each_with_index do |item, i|
|
71
|
+
sheet.row(i+1).replace(selected_export_columns.map {|k| item.send(k)})
|
72
|
+
item.exported = exported_at.to_s(:db)
|
73
|
+
item.save
|
74
|
+
end
|
75
|
+
|
76
|
+
tmp_file = Tempfile.new("form_data")
|
77
|
+
book.write tmp_file
|
78
|
+
tmp_file.path
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.formatting_for_csv(item)
|
82
|
+
if Time === item
|
83
|
+
item.to_s(:db)
|
84
|
+
else
|
85
|
+
item.to_s.gsub(/\s/, ' ')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def initialize(params={})
|
90
|
+
data = params.dup.delete_if { |k, v| !self.class.column_names.include?(k.to_s) }
|
91
|
+
super(data)
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'paperclip'
|
2
|
+
|
3
|
+
class FormDataAsset < ActiveRecord::Base
|
4
|
+
belongs_to :form_data
|
5
|
+
|
6
|
+
has_attached_file :attachment, :styles => { :thumb => '100x100>' }
|
7
|
+
|
8
|
+
IMAGE_CONTENT_TYPES = ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/jpg']
|
9
|
+
|
10
|
+
def image?
|
11
|
+
IMAGE_CONTENT_TYPES.include? attachment_content_type
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#x_filters
|
2
|
+
%a#x_expander.expand{:href => "javascript:;"} Export
|
3
|
+
#x_form{:style => "display:none"}
|
4
|
+
- form_tag(admin_form_datas_path, {:method => :get}) do
|
5
|
+
= list_params.map {|k,v| hidden_field_tag(k,v)}.join
|
6
|
+
%table.export
|
7
|
+
%tr
|
8
|
+
%td{:colspan => "2"} Choose the columns you want to export:
|
9
|
+
- export_columns.each do |ec|
|
10
|
+
%tr
|
11
|
+
%th= check_box_tag "export_#{ec}", ec, true
|
12
|
+
%td
|
13
|
+
%label{:for => "export_#{ec}"}
|
14
|
+
= ec.to_s.capitalize
|
15
|
+
%tr
|
16
|
+
%th= check_box_tag "include_all", "yes"
|
17
|
+
%td
|
18
|
+
%label{:for => "include_all"} Include allready exported
|
19
|
+
%tr
|
20
|
+
%td.sep{:colspan => "2"} Choose the format:
|
21
|
+
%tr
|
22
|
+
%th= radio_button_tag "format", "csv"
|
23
|
+
%td
|
24
|
+
%label{:for => "format_csv"} Comma separated values (CSV)
|
25
|
+
%tr
|
26
|
+
%th= radio_button_tag "format", "xls"
|
27
|
+
%td
|
28
|
+
%label{:for => "format_xls"} Microsoft Excel Sheet (XLS)
|
29
|
+
%tr
|
30
|
+
%th
|
31
|
+
%td
|
32
|
+
= submit_tag "Export"
|
33
|
+
%a.close{:href => "javascript:closeX()"} Close
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#filters
|
2
|
+
%a#expander.expand{:href => 'javascript:;'} Filter
|
3
|
+
#current_filters
|
4
|
+
- filters_present do
|
5
|
+
Applied filters:
|
6
|
+
= current_filters
|
7
|
+
= link_to 'Reset', :reset => 1
|
8
|
+
#form{:style => "display:none"}
|
9
|
+
- form_tag({}, {:method => :get}) do
|
10
|
+
= hidden_field_tag(:reset => 1)
|
11
|
+
%table.search
|
12
|
+
%tr
|
13
|
+
%th
|
14
|
+
%label{:for => "url"} URL:
|
15
|
+
%td
|
16
|
+
= select_tag("url", '<option value="">- All -</option>' + options_from_collection_for_select(@urls, "url", "url", list_params[:url]))
|
17
|
+
- each_data_column do |k|
|
18
|
+
%tr
|
19
|
+
%th
|
20
|
+
%label{:for => k}
|
21
|
+
= k.to_s.capitalize + ":"
|
22
|
+
%td
|
23
|
+
= text_field_tag k, list_params[k]
|
24
|
+
%tr
|
25
|
+
%th
|
26
|
+
%td= filter_actions_tag
|
27
|
+
%a.close{:href => "javascript:close()"} Close
|
@@ -0,0 +1,34 @@
|
|
1
|
+
.grey
|
2
|
+
#filtering
|
3
|
+
= render :partial => "filters"
|
4
|
+
= render :partial => "export"
|
5
|
+
#results
|
6
|
+
%table.results
|
7
|
+
%thead
|
8
|
+
%tr
|
9
|
+
%th.created_at= sortable_column_head "Created at", :created_at
|
10
|
+
%th.url= sortable_column_head "URL", :url
|
11
|
+
- each_data_column do |k|
|
12
|
+
%th= sortable_column_head k.to_s.capitalize, k
|
13
|
+
%th.exported= sortable_column_head "Exported", :exported
|
14
|
+
%th.actions Actions
|
15
|
+
%tbody
|
16
|
+
- @saved_items.each do |si|
|
17
|
+
%tr
|
18
|
+
%td= date_format(si.created_at)
|
19
|
+
%td= si.url
|
20
|
+
= data_columns.map { |k| "<td>#{si.send(k)}</td>" }
|
21
|
+
%td= si.exported ? date_format(si.exported) : "no"
|
22
|
+
%td.actions
|
23
|
+
= link_to "Show", admin_form_data_path(si)
|
24
|
+
= link_to 'Delete', admin_form_data_path(si.id), :method => :delete, :confirm => "Really delete record?"
|
25
|
+
- if @saved_items.empty?
|
26
|
+
%tr
|
27
|
+
%td{:colspan => data_columns.size + 2} No Results!
|
28
|
+
%tfoot
|
29
|
+
%tr
|
30
|
+
%th{:colspan => 4}
|
31
|
+
= page_entries_info @saved_items
|
32
|
+
%th{:colspan => "#{data_columns.size}"}
|
33
|
+
= will_paginate @saved_items, :inner_window => 1, :outer_window => 1
|
34
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
|
2
|
+
%h1 Form Data
|
3
|
+
|
4
|
+
#show.clearfix
|
5
|
+
#tab_control
|
6
|
+
#tabs.tabs
|
7
|
+
%a#details_lnk.tab.here{ :href => "#", :onclick => "show_details();" }
|
8
|
+
%span details
|
9
|
+
- unless @form_data
|
10
|
+
%a#attachments_lnk.tab{ :href => "#", :onclick => "show_attachments();" }
|
11
|
+
%span attachments
|
12
|
+
#pages.pages
|
13
|
+
#details.page
|
14
|
+
%table.result
|
15
|
+
%tr
|
16
|
+
%th Created_at
|
17
|
+
%td= date_format(@form_data.created_at)
|
18
|
+
%th Sent version of the email
|
19
|
+
%tr
|
20
|
+
%th URL:
|
21
|
+
%td= @form_data.url
|
22
|
+
%td{ :rowspan => "#{data_columns.size + 2}" }= simple_format(@form_data.blob)
|
23
|
+
- data_columns.each do |dc|
|
24
|
+
%tr
|
25
|
+
%th= dc.to_s.capitalize
|
26
|
+
%td= @form_data.send(dc)
|
27
|
+
%tr
|
28
|
+
%th Exported
|
29
|
+
%td= @form_data.exported? ? date_format(@form_data.exported) : "no"
|
30
|
+
- unless @form_data
|
31
|
+
#attachments.page{ :style => "display:none;"}
|
32
|
+
%table.attachments
|
33
|
+
%thead
|
34
|
+
%tr
|
35
|
+
%th Field Name
|
36
|
+
%th Link
|
37
|
+
%th Thumbnail
|
38
|
+
%tbody
|
39
|
+
- @form_data.form_data_assets.each do |att|
|
40
|
+
%tr
|
41
|
+
%td= att.field_name.blank? ? "Field:" : att.field_name.capitalize
|
42
|
+
%td
|
43
|
+
= link_to att.attachment_file_name, att.attachment.url
|
44
|
+
- if att.image?
|
45
|
+
%td
|
46
|
+
= image_tag att.attachment.url(:thumb)
|
47
|
+
- else
|
48
|
+
%td
|
49
|
+
= link_to "Back", admin_form_datas_path, :class => "back"
|