chimpmunk 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d8f65e72ccad48b7480ebab56fc5b64d47db5433
4
+ data.tar.gz: 65dcf7c040d7b56806733af6230f8b2040000e14
5
+ SHA512:
6
+ metadata.gz: abb985ee363fead96538780e32aa4279ec985f2d6de6cd6b4dc575ea38402d9bd3de80cd6d406c9c5f71dc2831c225a11499ad125f5c8700cd75124814dceba6
7
+ data.tar.gz: 2654c63e2b08158f0566d9cd699e2c91cd631289a58241a752e1118441cd21fd3beddc2cacd15b6a0a30eac4ea2f8e961af3cbc9ed64078b68f017aba94fca0a
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in chimpmunk.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Nick Franken
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,43 @@
1
+ # Chimpmunk
2
+
3
+ Mailchimp list administration and Campaign builder. ( in development )
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'chimpmunk'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Install with (make sure you have followed all rails_admin install steps first)
16
+
17
+ $ rails g chimpmunk:install
18
+
19
+ ## Post Installation
20
+
21
+ Install migrations
22
+
23
+ $ rake chimpmunk_engine:install:migrations
24
+
25
+ Run migrations
26
+
27
+ $ rake db:migrate
28
+
29
+ Set your mailchimp api key:
30
+
31
+ Gibbon::API.api_key = "your_api_key"
32
+
33
+ ## Usage
34
+
35
+ TODO: Write usage instructions here
36
+
37
+ ## Contributing
38
+
39
+ 1. Fork it ( https://github.com/[my-github-username]/chimpmunk/fork )
40
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
41
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
42
+ 4. Push to the branch (`git push origin my-new-feature`)
43
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/chimpmunk.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'chimpmunk/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "chimpmunk"
8
+ spec.version = Chimpmunk::VERSION
9
+ spec.authors = ["Nick Franken"]
10
+ spec.email = ["nf@the42.com"]
11
+ spec.summary = %q{Mailchimp list administration and Campaign builder.}
12
+ spec.description = %q{Mailchimp list administration and Campaign builder.}
13
+ spec.homepage = "https://bitbucket.org/42dev/chimpmunk"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'activerecord', ['>= 3.2', '< 5']
22
+ spec.add_dependency 'gibbon', '>= 1.1'
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake"
26
+ end
@@ -0,0 +1,53 @@
1
+ en:
2
+ admin:
3
+ actions:
4
+ send_test_email:
5
+ title: 'Send Test Email'
6
+ menu: 'Send Test Email'
7
+ breadcrumb: 'Send Test Email'
8
+ link: 'Send Test Email'
9
+ email_management:
10
+ title: 'Email Management'
11
+ menu: 'Email Management'
12
+ breadcrumb: 'Email Management'
13
+ link: 'Email Management'
14
+ email_list_new:
15
+ title: 'New Email List'
16
+ menu: 'New Email List'
17
+ breadcrumb: 'New Email List'
18
+ link: 'New Email List'
19
+ duplicate_email_campaign:
20
+ title: 'Duplicate Email Campaign'
21
+ menu: 'Duplicate Email Campaign'
22
+ breadcrumb: 'Duplicate Email Campaign'
23
+ link: 'Duplicate Email Campaign'
24
+ send_email_campaign:
25
+ title: 'Send Email Campaign'
26
+ menu: 'Send Email Campaign'
27
+ breadcrumb: 'Send Email Campaign'
28
+ link: 'Send Email Campaign'
29
+ schedule_email_campaign:
30
+ title: 'Schedule Email Campaign'
31
+ menu: 'Schedule Email Campaign'
32
+ breadcrumb: 'Schedule Email Campaign'
33
+ link: 'Schedule Email Campaign'
34
+ un_schedule_email_campaign:
35
+ title: 'Un-Schedule Email Campaign'
36
+ menu: 'Un-Schedule Email Campaign'
37
+ breadcrumb: 'Un-Schedule Email Campaign'
38
+ link: 'Un-Schedule Email Campaign'
39
+ refresh_email_campaigns:
40
+ title: 'Refresh Email Campaigns'
41
+ menu: 'Refresh Email Campaigns'
42
+ breadcrumb: 'Refresh Email Campaigns'
43
+ link: 'Refresh Email Campaigns'
44
+ refresh_email_campaign_stats:
45
+ title: 'Refresh Email Campaigns Stats'
46
+ menu: 'Refresh Email Campaigns Stats'
47
+ breadcrumb: 'Refresh Email Campaigns Stats'
48
+ link: 'Refresh Email Campaigns Stats'
49
+ refresh_email_lists:
50
+ title: 'Refresh Email Lists'
51
+ menu: 'Refresh Email Lists'
52
+ breadcrumb: 'Refresh Email Lists'
53
+ link: 'Refresh Email Lists'
@@ -0,0 +1,102 @@
1
+ class ChimpmunkMigration < ActiveRecord::Migration
2
+ def self.up
3
+
4
+ # create email lists
5
+ create_table :email_lists do |t|
6
+ t.string :default_from_email
7
+ t.string :default_from_name
8
+ t.string :default_subject
9
+ t.string :mailchimp_id
10
+ t.string :name
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ # create email campaigns
16
+ create_table :email_campaigns do |t|
17
+ t.string :title
18
+ t.string :from_email
19
+ t.string :from_name
20
+ t.references :email_list, index: true
21
+ t.string :subject
22
+ t.references :email_template, index: true
23
+ t.string :mailchimp_list_id
24
+ t.datetime :send_date
25
+ t.string :mailchimp_campaign_id
26
+ t.string :mailchimp_list_id
27
+ t.integer :emails_sent
28
+ t.integer :clicked
29
+ t.integer :opened
30
+ t.string :status
31
+ t.integer :hard_bounces
32
+ t.integer :soft_bounces
33
+ t.integer :unsubscribes
34
+ t.integer :forwards
35
+ t.integer :forwards_opens
36
+ t.integer :opens
37
+ t.datetime :last_open
38
+ t.integer :unique_opens
39
+ t.integer :non_unique_clicks
40
+ t.integer :users_who_clicked
41
+ t.integer :unique_likes
42
+ t.integer :facebook_likes
43
+ t.string :campaign_kind
44
+ t.integer :template_id
45
+
46
+ t.timestamps
47
+ end
48
+
49
+ # create email list groups
50
+ create_table :email_list_groups do |t|
51
+ t.string :name
52
+ t.references :grouping, index: true
53
+
54
+ t.timestamps
55
+ end
56
+
57
+ # create email templates
58
+ create_table :email_templates do |t|
59
+ t.string :mailchimp_id
60
+ t.string :name
61
+ t.string :layout
62
+ t.string :preview_image
63
+
64
+ t.timestamps
65
+ end
66
+
67
+ # create email list groupings
68
+ create_table :email_list_groupings do |t|
69
+ t.string :name
70
+ t.references :email_list, index: true
71
+ t.integer :mailchimp_grouping_id
72
+
73
+ t.timestamps
74
+ end
75
+
76
+ # ceate email subscribers
77
+ create_table :email_subscribers do |t|
78
+ t.string :mailchimp_id
79
+ t.string :first_name
80
+ t.string :last_name
81
+ t.string :email
82
+ t.boolean :subscribed
83
+ t.references :email_list, index: true
84
+
85
+ t.timestamps
86
+ end
87
+
88
+ # create email list group subscribers join table
89
+ create_table :email_list_groups_subscribers, id: false do |t|
90
+ t.integer :email_list_group_id
91
+ t.integer :email_subscriber_id
92
+ end
93
+ end
94
+
95
+ def self.down
96
+ drop_table :email_lists
97
+ drop_table :email_campaigns
98
+ drop_table :email_list_groups
99
+ drop_table :email_templates
100
+ drop_table :email_list_groupings
101
+ end
102
+ end
data/lib/chimpmunk.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'active_record'
2
+ require 'rails_admin'
3
+ require 'gibbon'
4
+ require 'chimpmunk/engine'
5
+ require 'rails_admin/chimpmunk_custom_actions.rb'
6
+
7
+ module Chimpmunk
8
+ extend ActiveSupport::Autoload
9
+
10
+ autoload :EmailCampaign
11
+ autoload :EmailList
12
+ autoload :EmailListGroup
13
+ autoload :EmailListGrouping
14
+ autoload :EmailSubscriber
15
+ autoload :EmailTemplate
16
+ autoload :VERSION
17
+
18
+ def self.mailchimp
19
+ @mailchimp ||= ::Gibbon::API.new
20
+ end
21
+ end
@@ -0,0 +1,352 @@
1
+ # encoding: utf-8
2
+ module Chimpmunk
3
+ class EmailCampaign < ::ActiveRecord::Base
4
+ attr_accessor :skip_update_callbacks, :skip_create_callbacks
5
+
6
+ # rails 3
7
+ attr_accessible :title, :from_email, :from_name, :email_list_id, :subject, :email_template_id, :mailchimp_list_id, :send_date,
8
+ :mailchimp_campaign_id, :emails_sent, :clicked, :opened, :status, :hard_bounces, :soft_bounces, :unsubscribes, :forwards,
9
+ :forwards_opens, :opens, :last_open, :unique_opens, :non_unique_clicks, :users_who_clicked, :unique_likes, :facebook_likes,
10
+ :created_at, :updated_at, :campaign_kind, :template_id, :email_list_group_id if defined?(ActiveModel::MassAssignmentSecurity)
11
+
12
+ # Associations
13
+ belongs_to :email_list
14
+ belongs_to :email_template
15
+ belongs_to :email_list_group
16
+ belongs_to :email_template
17
+
18
+ # Validations
19
+ validates :subject, presence: true
20
+ validates :from_email, presence: true
21
+ validates :from_name, presence: true
22
+ validates :email_list, presence: true
23
+ validates :email_template, presence: true
24
+
25
+ # Callbacks
26
+ after_create :create_campaign, unless: Proc.new { |campaign| campaign.skip_create_callbacks }
27
+ before_update :update_campaign, unless: Proc.new{ |campaign| campaign.skip_update_callbacks }
28
+ before_update :update_content, if: Proc.new{|campaign| campaign.email_template_id_changed? && !campaign.skip_update_callbacks }
29
+ before_destroy :destroy_mailchimp_campaign
30
+
31
+ # TODO: figure out attachments, example below
32
+ # has_attached_file :intro_image
33
+ # validates_attachment_content_type :intro_image, :content_type => /\Aimage\/.*\Z/
34
+
35
+ # TODO: figure out association, example below
36
+ # has_many :email_campaign_trending_posts, dependent: :destroy
37
+ # has_many :trending_posts, source: :post, through: :email_campaign_trending_posts
38
+
39
+ ##
40
+ # CLASS METHODS
41
+ ##
42
+
43
+ ##
44
+ # Refreshes the list of email campaigns
45
+ def self.refresh_email_campaigns
46
+ Chimpmunk.mailchimp.campaigns.list()["data"].each do |campaign|
47
+ campaign_attributes = {
48
+ title: campaign["title"],
49
+ campaign_kind: campaign["type"],
50
+ mailchimp_list_id: campaign["list_id"],
51
+ email_list_id: Chimpmunk::EmailList.find_by_mailchimp_id(campaign["list_id"]),
52
+ subject: campaign["subject"],
53
+ from_email: campaign["from_email"],
54
+ from_name: campaign["from_name"],
55
+ template_id: campaign["template_id"],
56
+ mailchimp_campaign_id: campaign["id"]
57
+ }
58
+ unless self.where(campaign_attributes).any?
59
+ new_campaign = self.new(campaign_attributes)
60
+ new_campaign.skip_create_callbacks = true
61
+ new_campaign.save
62
+ end
63
+ end
64
+ end
65
+
66
+ ##
67
+ # Refreshes all of the email campaign stats
68
+ def self.refresh_email_campaign_stats
69
+ Chimpmunk.mailchimp.campaigns.list({status:"sent"})["data"].each do |campaign|
70
+ email_campaign = Chimpmunk::EmailCampaign.find_by_mailchimp_campaign_id(campaign["id"])
71
+ if email_campaign and campaign["summary"].any?
72
+ email_campaign.skip_update_callbacks = true
73
+ email_campaign.update_attributes(
74
+ status: "sent",
75
+ emails_sent: campaign["summary"]["emails_sent"],
76
+ opened: campaign["summary"]["unique_opens"],
77
+ clicked: campaign["summary"]["unique_clicks"],
78
+ hard_bounces: campaign["summary"]["hard_bounces"],
79
+ soft_bounces: campaign["summary"]["soft_bounces"],
80
+ unsubscribes: campaign["summary"]["unsubscribes"],
81
+ forwards: campaign["summary"]["forwards"],
82
+ forwards_opens: campaign["summary"]["forwards_opens"],
83
+ opens: campaign["summary"]["opens"],
84
+ last_open: campaign["summary"]["last_open"],
85
+ unique_opens: campaign["summary"]["unique_opens"],
86
+ non_unique_clicks: campaign["summary"]["non_unique_clicks"],
87
+ users_who_clicked: campaign["summary"]["users_who_clicked"],
88
+ unique_likes: campaign["summary"]["unique_likes"],
89
+ facebook_likes: campaign["summary"]["facebook_likes"]
90
+ )
91
+ end
92
+ end
93
+ end
94
+
95
+ ##
96
+ # INSTANCE METHODS
97
+ ##
98
+
99
+ ##
100
+ # send a mailchimp campaign
101
+ def send_campaign
102
+ response = Chimpmunk.mailchimp.campaigns.send({cid: self.mailchimp_campaign_id})
103
+ response['errors'].nil?
104
+ end
105
+
106
+ ##
107
+ # schedule a mailchimp campaign
108
+ def schedule_campaign
109
+ response = Chimpmunk.mailchimp.campaigns.schedule({
110
+ cid: self.mailchimp_campaign_id,
111
+ schedule_time: self.send_date.to_time.to_s.gsub(' UTC', '')
112
+ })
113
+ response['errors'].nil? && self.update_attribute(:scheduled, true)
114
+ end
115
+
116
+ ##
117
+ # un-schedule email campaign that has been scheduled
118
+ def unschedule_campaign
119
+ response = Chimpmunk.mailchimp.campaigns.unschedule({cid: self.mailchimp_campaign_id})
120
+ response['errors'].nil? && self.update_attribute(:scheduled, false)
121
+ end
122
+
123
+ ##
124
+ # opened percentage display as float
125
+ def opened_percentage
126
+ if opened and emails_sent
127
+ "%2.1f %" % (opened.to_f / emails_sent.to_f * 100)
128
+ end
129
+ end
130
+
131
+ ##
132
+ # clicked percentage display as float
133
+ def clicked_percentage
134
+ if clicked and emails_sent
135
+ "%2.1f %" % (clicked.to_f / emails_sent.to_f * 100)
136
+ end
137
+ end
138
+
139
+ private
140
+
141
+ def action_view
142
+ @action_view ||= ActionView::Base.new(Rails.configuration.paths["app/views"])
143
+ @action_view.class_eval do
144
+ include Rails.application.routes.url_helpers
145
+ include ApplicationHelper
146
+
147
+ def protect_against_forgery?
148
+ false
149
+ end
150
+ end
151
+ @action_view
152
+ end
153
+
154
+ ##
155
+ # destroy mailchimp campaign before db destroy
156
+ def destroy_mailchimp_campaign
157
+ # don't care if it fails (probably was deleted from mailchimp web before deleted here)
158
+ begin
159
+ Chimpmunk.mailchimp.campaigns.delete({cid: self.mailchimp_campaign_id})
160
+ rescue Gibbon::MailChimpError
161
+ true
162
+ end
163
+ end
164
+
165
+ ##
166
+ # updates the campaign content on mailchimp before db update
167
+ def update_content
168
+ response = Chimpmunk.mailchimp.campaigns.update(
169
+ cid: self.mailchimp_campaign_id,
170
+ name: "content",
171
+ value: get_content
172
+ )
173
+
174
+ !response['errors'].any?
175
+ end
176
+
177
+ ##
178
+ # updates the campaign on mailchimp before db update
179
+ def update_campaign
180
+ begin
181
+ response = Chimpmunk.mailchimp.campaigns.update({
182
+ cid: self.mailchimp_campaign_id,
183
+ name: "options",
184
+ value: campaign_update_hash
185
+ })
186
+ rescue Gibbon::MailChimpError => e
187
+ self.errors.add(:base, e.message)
188
+ return false
189
+ end
190
+
191
+ if response["errors"].empty?
192
+ data = response["data"]
193
+ self.mailchimp_list_id = data["list_id"]
194
+ self.title = data["title"]
195
+ self.subject = data["subject"]
196
+ self.from_name = data["from_name"]
197
+ self.from_email = data["from_email"]
198
+ true
199
+ else
200
+ false
201
+ end
202
+ end
203
+
204
+ ##
205
+ # returns the update hash needed for the mailchimp request
206
+ def campaign_update_hash
207
+ {
208
+ list_id: email_list.mailchimp_id,
209
+ title: title,
210
+ subject: subject,
211
+ from_name: from_name,
212
+ from_email: from_email
213
+ }.reject{|k, v| v.nil?}
214
+ end
215
+
216
+ ##
217
+ # create campaign on mailchimp before db creation
218
+ def create_campaign
219
+ opts = {
220
+ type: "regular",
221
+ options: {
222
+ subject: self.subject,
223
+ from_email: self.from_email,
224
+ from_name: self.from_name,
225
+ template_id: self.email_template.try(:mailchimp_id),
226
+ inline_css: true
227
+ },
228
+ content: get_content
229
+ }
230
+
231
+ # list or segment(group)
232
+ if group = self.email_list_group
233
+ opts[:segment_opts] = {
234
+ match: "all",
235
+ conditions: [
236
+ {
237
+ field: "interests-#{group.email_list_grouping.mailchimp_grouping_id}",
238
+ value: group.name,
239
+ op: 'one'
240
+ }
241
+ ]
242
+ }
243
+ opts[:options][:list_id] = group.email_list_grouping.email_list.mailchimp_id
244
+ else
245
+ opts[:options][:list_id] = self.email_list.try(:mailchimp_id)
246
+ end
247
+
248
+ response = Chimpmunk.mailchimp.campaigns.create(opts)
249
+ if response["errors"].nil?
250
+ self.skip_update_callbacks = true
251
+ self.update_attribute(:mailchimp_campaign_id, response["id"])
252
+ else
253
+ false
254
+ end
255
+ end
256
+
257
+ ##
258
+ # TODO: figure out how to do this
259
+ # returns the html content for the new campaign
260
+ def get_content
261
+ content = {sections: {}}
262
+
263
+ # insert intro section if it exists
264
+ unless intro_section_blank?
265
+ content[:sections][:intro_section] = action_view.render 'eflyers/newsletter/intro', email_campaign: self
266
+ end
267
+
268
+ # insert divider if both intro sections and featured post exist
269
+ unless intro_section_blank? || featured_post.nil?
270
+ content[:sections][:divider] = action_view.render 'eflyers/newsletter/divider'
271
+ end
272
+
273
+ # insert featured post if it exists
274
+ unless featured_post.nil?
275
+ content[:sections][:featured_article] = action_view.render 'eflyers/newsletter/featured_article', email_campaign: self
276
+ end
277
+
278
+ # insert tending posts
279
+ content[:sections][:trending_section] = ''
280
+ trending_posts.in_groups_of(2) do |first_post, second_post|
281
+ content[:sections][:trending_section] += action_view.render 'eflyers/newsletter/trending', first_post: first_post, second_post: second_post
282
+ end
283
+
284
+ # insert sponsored section if it exsists
285
+ unless sponsored_section_blank?
286
+ content[:sections][:sponsored_section] = action_view.render 'eflyers/newsletter/sponsored', email_campaign: self
287
+ end
288
+
289
+ content[:sections][:directory_section] = action_view.render 'eflyers/newsletter/directory',
290
+ teacher_1: self.directory_teachers.first,
291
+ teacher_2: self.directory_teachers.second,
292
+ event_1: self.directory_events.first,
293
+ event_2: self.directory_events.second,
294
+ studio_1: self.directory_studios.first,
295
+ studio_2: self.directory_studios.second
296
+
297
+ unless teacher_tip_post.nil?
298
+ content[:sections][:teacher_tip] = action_view.render 'eflyers/newsletter/teacher_tip', email_campaign: self
299
+ end
300
+
301
+ content
302
+ end
303
+
304
+ if defined?(RailsAdmin)
305
+
306
+ rails_admin do
307
+ navigation_label 'Mailchimp'
308
+
309
+ configure :background_color, :color
310
+ configure :foreground_color, :color
311
+ configure :send_date, :datetime
312
+
313
+ list do
314
+ field :title
315
+ field :email_list
316
+ field :status
317
+ field :emails_sent
318
+ field :opened_percentage do
319
+ label "Opened"
320
+ end
321
+ field :clicked_percentage do
322
+ label "Clicked"
323
+ end
324
+ field :subject
325
+ field :from_email
326
+ field :from_name
327
+ end
328
+
329
+ edit do
330
+ field :title
331
+ field :email_list do
332
+ inline_add false
333
+ inline_edit false
334
+ end
335
+ field :email_list_group
336
+ field :email_template do
337
+ inline_add false
338
+ inline_edit false
339
+ end
340
+ field :subject
341
+ field :from_name do
342
+ default_value 'FIXME'
343
+ end
344
+ field :from_email do
345
+ default_value 'FIXME'
346
+ end
347
+ field :send_date
348
+ end
349
+ end
350
+ end
351
+ end
352
+ end