blythedunham-sms_on_rails 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/Manifest +101 -0
- data/README +163 -0
- data/README.rdoc +211 -0
- data/Rakefile +76 -0
- data/app/controllers/admin/sms_on_rails/base_controller.rb +11 -0
- data/app/controllers/admin/sms_on_rails/drafts_controller.rb +75 -0
- data/app/controllers/admin/sms_on_rails/outbounds_controller.rb +117 -0
- data/app/controllers/admin/sms_on_rails/phone_carriers_controller.rb +85 -0
- data/app/controllers/admin/sms_on_rails/phone_numbers_controller.rb +101 -0
- data/app/controllers/sms_on_rails/creation_support.rb +99 -0
- data/app/controllers/sms_on_rails_controller.rb +14 -0
- data/app/helpers/admin/sms_on_rails/drafts_helper.rb +2 -0
- data/app/helpers/admin/sms_on_rails/phone_carriers_helper.rb +2 -0
- data/app/helpers/sms_on_rails/phone_numbers_helper.rb +9 -0
- data/app/helpers/sms_on_rails/sms_helper.rb +44 -0
- data/app/models/sms_on_rails/draft.rb +9 -0
- data/app/models/sms_on_rails/outbound.rb +17 -0
- data/app/models/sms_on_rails/phone_carrier.rb +14 -0
- data/app/models/sms_on_rails/phone_number.rb +8 -0
- data/app/views/admin/sms_on_rails/base/index.html.erb +5 -0
- data/app/views/admin/sms_on_rails/drafts/_show.html.erb +34 -0
- data/app/views/admin/sms_on_rails/drafts/edit.html.erb +36 -0
- data/app/views/admin/sms_on_rails/drafts/index.html.erb +32 -0
- data/app/views/admin/sms_on_rails/drafts/new.html.erb +34 -0
- data/app/views/admin/sms_on_rails/drafts/send_sms.html.erb +3 -0
- data/app/views/admin/sms_on_rails/drafts/show.html.erb +4 -0
- data/app/views/admin/sms_on_rails/outbounds/edit.html.erb +68 -0
- data/app/views/admin/sms_on_rails/outbounds/index.html.erb +37 -0
- data/app/views/admin/sms_on_rails/outbounds/new.html.erb +54 -0
- data/app/views/admin/sms_on_rails/outbounds/show.html.erb +69 -0
- data/app/views/admin/sms_on_rails/phone_carriers/edit.html.erb +24 -0
- data/app/views/admin/sms_on_rails/phone_carriers/index.html.erb +24 -0
- data/app/views/admin/sms_on_rails/phone_carriers/new.html.erb +22 -0
- data/app/views/admin/sms_on_rails/phone_carriers/show.html.erb +24 -0
- data/app/views/admin/sms_on_rails/phone_numbers/edit.html.erb +33 -0
- data/app/views/admin/sms_on_rails/phone_numbers/index.html.erb +28 -0
- data/app/views/admin/sms_on_rails/phone_numbers/new.html.erb +31 -0
- data/app/views/admin/sms_on_rails/phone_numbers/show.html.erb +32 -0
- data/app/views/layouts/sms_on_rails/basic.html.erb +26 -0
- data/app/views/sms_on_rails/_phone_carrier_form_item.html.erb +6 -0
- data/app/views/sms_on_rails/_send_sms.html.erb +33 -0
- data/app/views/sms_on_rails/index.html.erb +8 -0
- data/app/views/sms_on_rails/send_sms.html.erb +3 -0
- data/app/views/sms_on_rails/show.html.erb +29 -0
- data/config/routes.rb +19 -0
- data/db/data/fixtures/sms_phone_carriers.yml +110 -0
- data/db/migrate/sms_on_rails_carrier_tables.rb +9 -0
- data/db/migrate/sms_on_rails_model_tables.rb +48 -0
- data/db/migrate/sms_on_rails_phone_number_tables.rb +11 -0
- data/db/seed_data.rb +16 -0
- data/generators/sms_on_rails/USAGE +31 -0
- data/generators/sms_on_rails/commands/inserts.rb +63 -0
- data/generators/sms_on_rails/commands/timestamps.rb +33 -0
- data/generators/sms_on_rails/runners/add_all_models.rb +6 -0
- data/generators/sms_on_rails/runners/dependencies.rb +1 -0
- data/generators/sms_on_rails/runners/remove_all_models.rb +5 -0
- data/generators/sms_on_rails/runners/sms_on_rails_routes.rb +14 -0
- data/generators/sms_on_rails/sms_on_rails_generator.rb +255 -0
- data/generators/sms_on_rails/templates/configuration/clickatell.rb +6 -0
- data/generators/sms_on_rails/templates/configuration/email_gateway.rb +7 -0
- data/generators/sms_on_rails/templates/migrate/schema_migration.rb +15 -0
- data/generators/sms_on_rails/templates/migrate/sms_on_rails_update_phone_numbers.rb +40 -0
- data/generators/sms_on_rails/templates/phone_number_collision.rb +2 -0
- data/init.rb +3 -0
- data/install.rb +1 -0
- data/lib/sms_on_rails.rb +8 -0
- data/lib/sms_on_rails/activerecord_extensions/acts_as_deliverable.rb +92 -0
- data/lib/sms_on_rails/activerecord_extensions/acts_as_substitutable.rb +80 -0
- data/lib/sms_on_rails/activerecord_extensions/has_a_sms_service_provider.rb +101 -0
- data/lib/sms_on_rails/activerecord_extensions/lockable_record.rb +186 -0
- data/lib/sms_on_rails/all_models.rb +3 -0
- data/lib/sms_on_rails/model_support/draft.rb +178 -0
- data/lib/sms_on_rails/model_support/outbound.rb +136 -0
- data/lib/sms_on_rails/model_support/phone_carrier.rb +77 -0
- data/lib/sms_on_rails/model_support/phone_number.rb +248 -0
- data/lib/sms_on_rails/model_support/phone_number_associations.rb +13 -0
- data/lib/sms_on_rails/schema_helper.rb +51 -0
- data/lib/sms_on_rails/service_providers/base.rb +222 -0
- data/lib/sms_on_rails/service_providers/clickatell.rb +52 -0
- data/lib/sms_on_rails/service_providers/dummy.rb +19 -0
- data/lib/sms_on_rails/service_providers/email_gateway.rb +68 -0
- data/lib/sms_on_rails/service_providers/email_gateway_support/errors.rb +20 -0
- data/lib/sms_on_rails/service_providers/email_gateway_support/sms_mailer.rb +21 -0
- data/lib/sms_on_rails/service_providers/email_gateway_support/sms_mailer/sms_through_gateway.erb +6 -0
- data/lib/sms_on_rails/util/sms_error.rb +12 -0
- data/lib/smsonrails.rb +1 -0
- data/public/images/sms_on_rails/railsYoDawg.jpg +0 -0
- data/public/stylesheets/sms_on_rails.css +137 -0
- data/sms_on_rails.gemspec +32 -0
- data/tasks/sms_on_rails_tasks.rake +67 -0
- data/test/active_record_extensions/delivery_and_locking_test.rb +84 -0
- data/test/models/draft_test.rb +72 -0
- data/test/models/outbound_test.rb +89 -0
- data/test/models/phone_number_test.rb +131 -0
- data/test/run.rb +18 -0
- data/test/service_providers/abstract_test_support.rb +104 -0
- data/test/service_providers/clickatell_test.rb +39 -0
- data/test/service_providers/email_gateway_test.rb +30 -0
- data/test/test_helper.rb +24 -0
- data/uninstall.rb +1 -0
- metadata +187 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
<p>
|
3
|
+
<b>Message:</b>
|
4
|
+
<%=h @draft.actual_message %>
|
5
|
+
</p>
|
6
|
+
|
7
|
+
<p>
|
8
|
+
<b>Status:</b>
|
9
|
+
<%=h @draft.status %>
|
10
|
+
</p>
|
11
|
+
|
12
|
+
<p>
|
13
|
+
<b>Deliver after:</b>
|
14
|
+
<%=h @draft.deliver_after %>
|
15
|
+
</p>
|
16
|
+
|
17
|
+
<p>
|
18
|
+
<b>Delivery date:</b>
|
19
|
+
<%=h @draft.delivery_date %>
|
20
|
+
</p>
|
21
|
+
|
22
|
+
<p>
|
23
|
+
<b> Phone Numbers: </b><br>
|
24
|
+
<% @draft.outbounds.each do |outbound| %>
|
25
|
+
<%= outbound.phone_number.human_display %><br>
|
26
|
+
<% end %>
|
27
|
+
</p>
|
28
|
+
|
29
|
+
<%= link_to 'Send More SMS Messages', new_sms_path %>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
ActionController::Routing::Routes.draw do |map|
|
2
|
+
|
3
|
+
#Resources for sms on rails admin routes
|
4
|
+
#url: localhost:3000/admin/sms/drafts goes to the app/controllers/admin/sms_on_rails/draft_controller.rb
|
5
|
+
|
6
|
+
map.resources :sms_drafts, :new => {:send_sms => :any}, :as => 'admin/sms/drafts', :controller => 'admin/sms_on_rails/drafts' do |draft|
|
7
|
+
draft.resources :outbounds, :collection => {:deliver_sms => :any}, :controller => 'admin/sms_on_rails/outbounds'
|
8
|
+
end
|
9
|
+
|
10
|
+
map.resources :sms_drafts, :collection => {:send_sms => :any}, :as => 'admin/sms/drafts', :controller => 'admin/sms_on_rails/drafts'
|
11
|
+
|
12
|
+
map.resources :sms_phone_numbers, :as => 'admin/sms/phone_numbers', :controller => 'admin/sms_on_rails/phone_numbers'
|
13
|
+
map.resources :sms_phone_carriers, :as => 'admin/sms/phone_carriers', :controller => 'admin/sms_on_rails/phone_carriers'
|
14
|
+
|
15
|
+
map.resources :sms, :as => 'sms', :controller => 'sms_on_rails', :only => [:create, :show, :new, :index], :singular => 'sms'
|
16
|
+
|
17
|
+
map.sms_admin '/admin/sms', :controller => 'admin/sms_on_rails/base', :action => 'index'
|
18
|
+
|
19
|
+
end#end sms routeM
|
@@ -0,0 +1,110 @@
|
|
1
|
+
carrier_1:
|
2
|
+
id: "1"
|
3
|
+
name: Verizon
|
4
|
+
email_domain: "vtext.com"
|
5
|
+
|
6
|
+
carrier_2:
|
7
|
+
id: "2"
|
8
|
+
name: Alltel
|
9
|
+
email_domain: "message.alltel.com"
|
10
|
+
|
11
|
+
carrier_3:
|
12
|
+
id: "3"
|
13
|
+
name: Cingular mmode
|
14
|
+
email_domain: "mmode.com"
|
15
|
+
notes: "formerly AT&T, then Cingular, now AT&T Wireless - Original grandfathered rateplan customers"
|
16
|
+
|
17
|
+
carrier_4:
|
18
|
+
id: "4"
|
19
|
+
name: Cellular One
|
20
|
+
email_domain: "mobile.celloneusa.com"
|
21
|
+
|
22
|
+
carrier_5:
|
23
|
+
id: "5"
|
24
|
+
name: AT&T
|
25
|
+
email_domain: "txt.att.net"
|
26
|
+
|
27
|
+
carrier_6:
|
28
|
+
id: "6"
|
29
|
+
name: Nextel
|
30
|
+
email_domain: "page.nextel.com"
|
31
|
+
|
32
|
+
carrier_7:
|
33
|
+
id: "7"
|
34
|
+
name: OmnipointPCS
|
35
|
+
email_domain: "omnipointpcs.com"
|
36
|
+
|
37
|
+
carrier_8:
|
38
|
+
id: "8"
|
39
|
+
name: Qwest
|
40
|
+
email_domain: "qwestmp.com"
|
41
|
+
|
42
|
+
carrier_9:
|
43
|
+
id: "9"
|
44
|
+
name: Sprint
|
45
|
+
email_domain: "messaging.sprintpcs.com"
|
46
|
+
|
47
|
+
carrier_10:
|
48
|
+
id: "10"
|
49
|
+
name: T-Mobile
|
50
|
+
email_domain: "tmomail.net"
|
51
|
+
|
52
|
+
carrier_11:
|
53
|
+
id: "11"
|
54
|
+
name: Virgin Mobile
|
55
|
+
email_domain: "vmobl.com"
|
56
|
+
|
57
|
+
carrier_12:
|
58
|
+
id: "12"
|
59
|
+
name: US Cellular
|
60
|
+
email_domain: "email.uscc.com"
|
61
|
+
|
62
|
+
carrier_13:
|
63
|
+
id: "13"
|
64
|
+
name: Amp'd
|
65
|
+
email_domain: "ampdpix.com"
|
66
|
+
|
67
|
+
carrier_14:
|
68
|
+
id: 14
|
69
|
+
name: AT&T Formerly Cingular
|
70
|
+
email_domain: "cingularme.com"
|
71
|
+
|
72
|
+
carrier_15:
|
73
|
+
id: 15
|
74
|
+
name: AT&T Formerly Cingular MMS
|
75
|
+
email_domain: "mms.att.net"
|
76
|
+
|
77
|
+
carrier_16:
|
78
|
+
id: 16
|
79
|
+
name: Alaska Communications Systems
|
80
|
+
email_domain: "msg.acsalaska.com"
|
81
|
+
|
82
|
+
carrier_17:
|
83
|
+
id: 17
|
84
|
+
name: AT&T Enterprise Paging
|
85
|
+
email_domain: "number@page.att.net"
|
86
|
+
|
87
|
+
carrier_18:
|
88
|
+
id: 22
|
89
|
+
name: MetroPCS
|
90
|
+
email_domain: "mymetropcs.com"
|
91
|
+
|
92
|
+
carrier_19:
|
93
|
+
id: 19
|
94
|
+
name: Plateau Wireless
|
95
|
+
email_domain: "smsx.plateaugsm.com"
|
96
|
+
|
97
|
+
carrier_20:
|
98
|
+
id: 20
|
99
|
+
name: 7-11 Speakout
|
100
|
+
email_domain: "cingularme.com"
|
101
|
+
|
102
|
+
carrier_21:
|
103
|
+
id: 21
|
104
|
+
name: Cricket
|
105
|
+
email_domain: "sms.mycricket.com"
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
|
2
|
+
create_table :sms_phone_carriers, :force => true do |t|
|
3
|
+
t.string :name, :length => 100, :null => false
|
4
|
+
t.string :email_domain, :length => 100, :default => nil
|
5
|
+
t.string :notes, :default => nil
|
6
|
+
t.string :options, :default => nil
|
7
|
+
end
|
8
|
+
|
9
|
+
add_index :sms_phone_carriers, :name, :unique => 'true', :name => 'uk_phone_carriers_name'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
use_fk = respond_to?(:add_foreign_key)
|
2
|
+
puts "#{use_fk ? '': 'NOT'} USING FOREIGN KEYS"
|
3
|
+
|
4
|
+
create_table :sms_drafts, :force => true do |t|
|
5
|
+
t.column :message, :string, :default => nil
|
6
|
+
t.column :header, :string, :default => nil
|
7
|
+
t.column :footer, :string, :default => nil
|
8
|
+
t.column :status, :string, :limit => 15, :null => false, :default => 'NOT_PROCESSED'
|
9
|
+
t.column :deliver_after, :datetime, :default => nil
|
10
|
+
t.column :delivery_date, :datetime, :default => nil
|
11
|
+
t.column :sender_id, :integer, :default => nil
|
12
|
+
t.column :lock_version, :integer, :null => false, :default => 0, :limit => 1
|
13
|
+
t.column :options, :string, :default => nil
|
14
|
+
t.column :updated_at, :string, :default => nil
|
15
|
+
t.column :created_at, :string, :default => nil
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
#Add a unique id to track vendor
|
20
|
+
create_table :sms_outbounds, :force => true do |t|
|
21
|
+
t.column :sms_phone_number_id, :integer, :null => false, :references => :phone_number, :on_delete => :cascade
|
22
|
+
t.column :sms_draft_id, :integer, :default => nil, :on_delete => :cascade
|
23
|
+
t.column :status, :string, :limit => 15, :null => false, :default => 'NOT_PROCESSED'
|
24
|
+
t.column :retry_count, :integer, :limit => 1, :null => false, :default => 0
|
25
|
+
t.column :sub_status, :string, :limit => 35, :default => nil
|
26
|
+
t.column :notes, :string, :limit => 80, :default => nil
|
27
|
+
t.column :created_at, :datetime, :default => nil
|
28
|
+
t.column :processed_on, :datetime, :default => nil
|
29
|
+
t.column :lock_version, :integer, :null => false, :default => 0, :limit => 1
|
30
|
+
t.column :sms_service_provider_id, :integer, :limit => 4, :default => nil, :references => nil
|
31
|
+
t.column :options, :string, :default => nil
|
32
|
+
t.column :send_priority, :integer, :limit => 4, :null => false, :default => 0
|
33
|
+
t.column :actual_message, :string, :limit => 160, :null => true, :default => nil
|
34
|
+
end
|
35
|
+
|
36
|
+
execute "ALTER TABLE sms_outbounds ADD COLUMN `unique_id` varchar(255) character set latin1 collate latin1_bin default NULL"
|
37
|
+
add_index :sms_outbounds, :unique_id, :unique => 'true', :name => 'uk_sms_outbounds_unique_id'
|
38
|
+
add_index :sms_outbounds, [:sms_draft_id, :sms_phone_number_id], :unique => 'true', :name => 'uk_sms_outbounds_draft_phone_number'
|
39
|
+
|
40
|
+
# Add composite accross sms_outbounds for lookup speed
|
41
|
+
#add_index :sms_outbounds, [:status, :send_priority, :sms_draft_id], :name => 'idx_sms_outbounds_status_priority_draft'
|
42
|
+
|
43
|
+
#Add a unique id to track vendor
|
44
|
+
unless use_fk
|
45
|
+
#add_index :sms_outbounds, :sms_draft_id
|
46
|
+
#do not index :sms_draft_id because their is already a composite on
|
47
|
+
add_index :sms_outbounds, :sms_phone_number_id
|
48
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
create_table :phone_numbers, :force => true do |t|
|
2
|
+
t.string :number, :length => 20, :null => false
|
3
|
+
t.integer :carrier_id, :default => nil
|
4
|
+
t.integer :owner_id, :default => nil
|
5
|
+
t.boolean :white_list, :null => false, :default => false
|
6
|
+
t.string :do_not_send, :length => 30, :default => nil
|
7
|
+
t.integer :country_code, :length => 2, :default => 1
|
8
|
+
end
|
9
|
+
|
10
|
+
add_index :phone_numbers, :number, :unique => 'true', :name => 'uk_phone_numbers_number'
|
11
|
+
|
data/db/seed_data.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'active_record/fixtures'
|
2
|
+
|
3
|
+
unless defined?(SmsOnRails::PhoneCarrier)
|
4
|
+
require 'sms_on_rails/phone_carrier'
|
5
|
+
end
|
6
|
+
|
7
|
+
fixture_class_names = {
|
8
|
+
:sms_phone_carriers => 'SmsOnRails::PhoneCarrier',
|
9
|
+
}
|
10
|
+
|
11
|
+
fixture_path = File.dirname(__FILE__) + '/data/fixtures'
|
12
|
+
|
13
|
+
fixture_files = Dir.glob(fixture_path + '/*.yml').collect{|f| File.basename(f, '.yml')}
|
14
|
+
fixture_class_names.values.each {|klass| klass.constantize.delete_all }
|
15
|
+
|
16
|
+
Fixtures.create_fixtures(fixture_path, fixture_files, fixture_class_names)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Description:
|
2
|
+
Setup Sms On Rails
|
3
|
+
|
4
|
+
The following actions can be specified seperately or together
|
5
|
+
|
6
|
+
environment (default)
|
7
|
+
- add the configuration to config/environment.rb and runs dependencies
|
8
|
+
models
|
9
|
+
- copy the vanilla models up to app/models/sms_on_rails so they can be
|
10
|
+
edited/overwritten accordingly
|
11
|
+
dependencies
|
12
|
+
- install dependent plugins and gems (enviroment does this automatically)
|
13
|
+
migration (default)
|
14
|
+
- creates three migration templates for sms tables. To skip one, for example if
|
15
|
+
only the carriers and phone numbers are desired,
|
16
|
+
use --skip-models, --skip-phone-number or --skip-carriers to skip
|
17
|
+
|
18
|
+
Example:
|
19
|
+
Set up the environment and create models in app/models/sms_on_rails
|
20
|
+
./script/generate sms_on_rails setup environment models
|
21
|
+
|
22
|
+
Just setup the environment and create the migration
|
23
|
+
./script/generate sms_on_rails setup
|
24
|
+
|
25
|
+
Setup the views
|
26
|
+
./script/generate sms_on_rails setup views
|
27
|
+
|
28
|
+
Create a migration skipping models migration
|
29
|
+
./script/generate sms_on_rails setup migration --skip-models
|
30
|
+
|
31
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# Most of this was derived from the clearance gem work
|
2
|
+
Rails::Generator::Commands::Base.class_eval do
|
3
|
+
|
4
|
+
# Return true if the file contains the line (String or Regexp)
|
5
|
+
def file_contains?(relative_destination, line)
|
6
|
+
File.read(destination_path(relative_destination)).scan(line).any?
|
7
|
+
end
|
8
|
+
|
9
|
+
def margin_text(options={})
|
10
|
+
margin = ' ' * (options[:margin]||2)
|
11
|
+
margin
|
12
|
+
end
|
13
|
+
|
14
|
+
def append_to_file(relative_destination, content)
|
15
|
+
path = destination_path(relative_destination)
|
16
|
+
File.open(path, 'ab') { |file| file.write("\n" + content + "\n") }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Rails::Generator::Commands::Create.class_eval do
|
21
|
+
|
22
|
+
# Insert the new line into the file
|
23
|
+
# +file+ - the name of the file to update
|
24
|
+
# +new_line+ - the new line to insert
|
25
|
+
# == Options
|
26
|
+
# <tt>:quiet</tt> - turn off logging
|
27
|
+
# <tt>:append</tt> - when true append to the end of the file instead of <tt>:insert_after</tt>
|
28
|
+
# <tt>:match</tt> - (String or Regexp). If the file contents matches then do not add this line again. This defaults to the actual line itself
|
29
|
+
# <tt>:replace</tt> - (Regexp) Replace the matching regexp completely with the new line. If nothing matches the replace regexp, append to the end of the file. <tt>:insert_after</tt> value is ignored.
|
30
|
+
# <tt>:insert_after</tt> (Regexp) Insert the new line after this match. By default, the line is inserted after a class or module
|
31
|
+
# <tt>:margin</tt> - length of the margin to add before the line. Defaults to 2.
|
32
|
+
def insert_into(file, new_line, options={})
|
33
|
+
logger.insert "#{new_line} into #{file}" unless options[:quiet]
|
34
|
+
|
35
|
+
line = margin_text(options) + new_line
|
36
|
+
|
37
|
+
unless options[:pretend] || file_contains?(file, options[:match]||line)
|
38
|
+
if options[:append] || (options[:replace] && !file_contains?(file, options[:replace]))
|
39
|
+
append_to_file file, line
|
40
|
+
else
|
41
|
+
regex = options[:insert_after]||options[:replace]||/^(class|module) .+$/
|
42
|
+
gsub_file file, regex do |match|
|
43
|
+
options[:replace] ? line : "#{match}\n#{line}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Rails::Generator::Commands::Destroy.class_eval do
|
51
|
+
def insert_into(file, line, options={})
|
52
|
+
logger.remove "#{line} from #{file}"
|
53
|
+
unless options[:pretend]
|
54
|
+
gsub_file file, "\n#{margin_text(options)}#{line}", ''
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
Rails::Generator::Commands::List.class_eval do
|
60
|
+
def insert_into(file, line)
|
61
|
+
logger.insert "#{line} into #{file}"
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Rails::Generator::Commands::Create.class_eval do
|
2
|
+
|
3
|
+
#overwrite next migration string to add a count to the timestamp
|
4
|
+
def next_migration_string(padding = 3)#:nodoc:
|
5
|
+
if ActiveRecord::Base.timestamped_migrations
|
6
|
+
time_str = Time.now.utc.strftime("%Y%m%d%H%M%S")
|
7
|
+
time_str << "#{migration_count}" if migration_count > 1
|
8
|
+
time_str
|
9
|
+
else
|
10
|
+
"%.#{padding}d" % next_migration_number
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def migration_count
|
15
|
+
@@mig_count||=0
|
16
|
+
end
|
17
|
+
|
18
|
+
def increment_migration_count
|
19
|
+
@@mig_count = migration_count + 1
|
20
|
+
end
|
21
|
+
|
22
|
+
# When creating a migration, it knows to find the first available file in db/migrate and use the migration.rb template.
|
23
|
+
def migration_template(relative_source, relative_destination, template_options = {})#:nodoc:
|
24
|
+
increment_migration_count
|
25
|
+
migration_directory relative_destination
|
26
|
+
migration_file_name = template_options[:migration_file_name] || file_name
|
27
|
+
if migration_exists?(migration_file_name)
|
28
|
+
logger.exists "#{existing_migrations(migration_file_name).first}"
|
29
|
+
else
|
30
|
+
template(relative_source, "#{relative_destination}/#{next_migration_string}_#{migration_file_name}.rb", template_options)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
plugin 'static_record_cache', :git => 'git://github.com/blythedunham/static_record_cache.git'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
route <<-EOS
|
3
|
+
|
4
|
+
#Resources for sms on rails admin routes
|
5
|
+
#url: localhost:3000/admin/sms/drafts goes to the app/controllers/admin/sms_on_rails/draft_controller.rb
|
6
|
+
map.resources :sms_drafts, :as => 'admin/sms/drafts', :controller => 'admin/sms_on_rails/drafts' do |draft|
|
7
|
+
draft.resources :outbounds, :controller => 'admin/sms_on_rails/outbounds'
|
8
|
+
end
|
9
|
+
map.resources :sms_phone_numbers, :as => 'admin/sms/phone_numbers', :controller => 'admin/sms_on_rails/phone_numbers'
|
10
|
+
map.resources :sms_outbounds, :as => 'admin/sms/outbounds', :controller => 'admin/sms_on_rails/outbounds'
|
11
|
+
map.resources :sms_phone_carriers, :as => 'admin/sms/phone_carriers', :controller => 'admin/sms_on_rails/phone_carriers'
|
12
|
+
EOS
|
13
|
+
|
14
|
+
|
@@ -0,0 +1,255 @@
|
|
1
|
+
require 'rails_generator/generators/applications/app/template_runner'
|
2
|
+
require File.dirname(__FILE__) + '/commands/inserts.rb'
|
3
|
+
require File.dirname(__FILE__) + '/commands/timestamps.rb'
|
4
|
+
|
5
|
+
class SmsOnRailsGenerator < Rails::Generator::NamedBase
|
6
|
+
|
7
|
+
default_options :skip_models => false, :skip_carriers => false,
|
8
|
+
:skip_phone_numbers => false, :skip_migration => false,
|
9
|
+
:default_service_provider => :email_gateway
|
10
|
+
|
11
|
+
unless defined?(SERVICE_PROVIDERS)
|
12
|
+
SERVICE_PROVIDERS = [:clickatell, :email_gateway]
|
13
|
+
SET_SERVICE_PROVIDER_CONFIG = "SmsOnRails::ServiceProviders::Base.set_default_service_provider"
|
14
|
+
end
|
15
|
+
|
16
|
+
def manifest
|
17
|
+
@actions = (actions.blank?) ? %w(environment migration phone_collision assets) : self.actions
|
18
|
+
@actions.sort! #we want environment to run first
|
19
|
+
@actions.delete('dependencies') if @actions.include?('environment')
|
20
|
+
|
21
|
+
record do |m|
|
22
|
+
@actions.each do |action|
|
23
|
+
case(action)
|
24
|
+
when 'views' then create_views(m)
|
25
|
+
when 'models' then copy_models(m)
|
26
|
+
when 'environment' then add_configuation_options(m)
|
27
|
+
when 'dependencies' then add_dependencies(m)
|
28
|
+
when 'migration' then generate_migration_templates(m)
|
29
|
+
when 'phone_collision' then handle_phone_number_collision(m)
|
30
|
+
when 'assets' then copy_assets(m)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def after_generate
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def banner
|
42
|
+
"Usage: #{$0} sms_on_rails setup [models views environment]"
|
43
|
+
end
|
44
|
+
|
45
|
+
# options specific to sms on rails generator
|
46
|
+
def add_options!(opt)
|
47
|
+
opt.separator ''
|
48
|
+
opt.separator 'Options:'
|
49
|
+
opt.on("-m", "--skip-models",
|
50
|
+
"Skip the models migration",
|
51
|
+
"Default: false") { |v| options[:skip_models] = v }
|
52
|
+
opt.on("-c", "--skip-carriers",
|
53
|
+
"Skip the phone carriers migrations",
|
54
|
+
"Default: false") { |v| options[:skip_carriers] = v }
|
55
|
+
opt.on("-p", "--skip-phone-numbers",
|
56
|
+
"Skip the phone numbers migrations",
|
57
|
+
"Default: false") { |v| options[:skip_phone_numbers] = v }
|
58
|
+
opt.on("-s", "--default-service-provider=[name]",
|
59
|
+
"Name of the default service provider: clickatell or email_gateway",
|
60
|
+
"Default: email_gateway") { |v| options[:default_service_provider] = v.to_s.downcase.underscore.to_sym }
|
61
|
+
end
|
62
|
+
|
63
|
+
# If app/models/phone_number.rb exists, add include the Sms functionality
|
64
|
+
# and define app/models/sms_on_rails/phone_number.rb to point to PhoneNumber
|
65
|
+
def handle_phone_number_collision(m)
|
66
|
+
#if the phone_number.rb file exists on the main
|
67
|
+
phone_number_model = "app/models/phone_number.rb"
|
68
|
+
if File.exists?(phone_number_model)
|
69
|
+
m.insert_into phone_number_model, "include SmsOnRails::ModelSupport::PhoneNumber # include custom sms on rails phone number handling"
|
70
|
+
m.insert_into phone_number_model, "include SmsOnRails::ModelSupport::PhoneNumberAssociations # remove this for custom sms on rails associations"
|
71
|
+
|
72
|
+
sms_on_rails_dir = File.join("app", "models", "sms_on_rails")
|
73
|
+
m.directory sms_on_rails_dir
|
74
|
+
m.file "phone_number_collision.rb", File.join(sms_on_rails_dir, "phone_number.rb")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# add sms on rails dependencies such as the clickatell gem and static record cache
|
79
|
+
def add_dependencies(m)
|
80
|
+
add_clickatell_gem(m) if options[:default_service_provider] == :clickatell
|
81
|
+
logger.log 'plugin', 'static_record_cache'
|
82
|
+
run_template 'dependencies'
|
83
|
+
end
|
84
|
+
|
85
|
+
# add the clickatell gem dependency to the app's config/enviornment.rb file
|
86
|
+
def add_clickatell_gem(m)
|
87
|
+
logger.log 'gem', 'clickatell'
|
88
|
+
m.insert_into 'config/environment.rb', "config.gem 'clickatell'\n",
|
89
|
+
:margin => 2, :insert_after => /Rails::Initializer\.run.*\n/, :quiet => true
|
90
|
+
end
|
91
|
+
|
92
|
+
#copy up the public folder
|
93
|
+
def copy_assets(m)
|
94
|
+
create_app_files(m, 'public', :dest_base => '.', :relative_src => '/../../../')
|
95
|
+
end
|
96
|
+
|
97
|
+
# Use template runner to run specified template and output message
|
98
|
+
def run_template(template_name, message = nil)
|
99
|
+
logger.log message.first, message.last if message
|
100
|
+
logger.quiet = true
|
101
|
+
Rails::TemplateRunner.new(File.join(File.dirname(__FILE__),'runners', template_name + '.rb'), @destination_root)
|
102
|
+
ensure
|
103
|
+
logger.quiet = options[:quiet]
|
104
|
+
end
|
105
|
+
|
106
|
+
# generate the 3 sms on rails migrations by creating them in the main app dir
|
107
|
+
def generate_migration_templates(m)
|
108
|
+
generate_migration_template(m, :carrier) unless options[:skip_carriers]
|
109
|
+
generate_migration_template(m, :phone_number, phone_mig_options) unless options[:skip_phone_numbers]
|
110
|
+
generate_migration_template(m, :model) unless options[:skip_models]
|
111
|
+
end
|
112
|
+
|
113
|
+
#change to update if phone number exists
|
114
|
+
def phone_mig_options
|
115
|
+
if ActiveRecord::Base.connection.table_exists?(:phone_numbers)
|
116
|
+
{:migration_file_name => 'sms_on_rails_update_phone_numbers' }
|
117
|
+
else
|
118
|
+
{}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
#generate the specified migration template
|
123
|
+
def generate_migration_template(m, migration_name, options={})
|
124
|
+
return if options[:skip_migration]
|
125
|
+
|
126
|
+
migration_file_name = options[:migration_file_name]||"sms_on_rails_create_#{migration_name}s"
|
127
|
+
template_file_name = (options[:migration_file_name]||'schema_migration') +'.rb'
|
128
|
+
|
129
|
+
m.migration_template "migrate/#{template_file_name}", 'db/migrate', :assigns => {
|
130
|
+
:migration_name => "#{migration_file_name.classify}s",
|
131
|
+
:files => ["sms_on_rails_#{migration_name}_tables"]
|
132
|
+
}, :migration_file_name => migration_file_name
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
def add_configuation_options(m)
|
137
|
+
add_require_all_models unless supports_engines?
|
138
|
+
add_dependencies(m)
|
139
|
+
|
140
|
+
logger.update "configuration options in environment.rb"
|
141
|
+
disable_logger do
|
142
|
+
add_service_provider_configuration(m)
|
143
|
+
add_default_service_provider(m)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
protected
|
148
|
+
|
149
|
+
def disable_logger(&block)
|
150
|
+
logger.quiet = true
|
151
|
+
yield
|
152
|
+
ensure
|
153
|
+
logger.quiet = options[:quiet]
|
154
|
+
end
|
155
|
+
|
156
|
+
def add_service_provider_configuration(m)
|
157
|
+
SERVICE_PROVIDERS.each do |sp_name|
|
158
|
+
config_file = File.dirname(__FILE__) + "/templates/configuration/#{sp_name}.rb"
|
159
|
+
if File.exists?(config_file)
|
160
|
+
m.insert_into 'config/environment.rb', File.read(config_file),
|
161
|
+
:margin => 0, :append => true, :quiet => true,
|
162
|
+
:match => "SmsOnRails::ServiceProviders::#{sp_name.to_s.classify}.config"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
def add_default_service_provider(m)
|
169
|
+
line = "#{SET_SERVICE_PROVIDER_CONFIG} #{options[:default_service_provider].to_sym.inspect}"
|
170
|
+
|
171
|
+
m.insert_into "config/environment.rb", line, :margin => 0, :quiet => true,
|
172
|
+
:replace => Regexp.new("#{SET_SERVICE_PROVIDER_CONFIG}.*(\\n|$)")
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
##############################################################################
|
177
|
+
# Pre Rails engine support: copy to app directly
|
178
|
+
##############################################################################
|
179
|
+
|
180
|
+
def create_views(m)
|
181
|
+
create_admin_view_files m
|
182
|
+
create_helper_files m
|
183
|
+
create_controller_files m
|
184
|
+
add_sms_routes
|
185
|
+
end
|
186
|
+
|
187
|
+
def copy_models(m)
|
188
|
+
create_app_files(m, 'models/sms_on_rails')
|
189
|
+
remove_require_all_models
|
190
|
+
end
|
191
|
+
|
192
|
+
def add_sms_routes
|
193
|
+
return if supports_engines?
|
194
|
+
run_template 'sms_on_rails_routes', ['routes', 'sms_on_rails routes']
|
195
|
+
end
|
196
|
+
|
197
|
+
#return true if the rails version has support for engines
|
198
|
+
def supports_engines?
|
199
|
+
@@supports_engines ||= ActiveRecord::VERSION::STRING >= '2.3.0'
|
200
|
+
end
|
201
|
+
|
202
|
+
# remove the require 'sms_on_rails/all_models.rb from environment.rb'
|
203
|
+
def remove_require_all_models
|
204
|
+
run_template 'remove_all_models', ['removing', 'references to vanilla models']
|
205
|
+
end
|
206
|
+
|
207
|
+
# add the require 'sms_on_rails/all_models.rb from environment.rb'
|
208
|
+
def add_require_all_models
|
209
|
+
if !@actions.include?('models') && !File.exists?(File.join(@destination_root, 'app/models/sms_on_rails'))
|
210
|
+
run_template 'add_all_models', ['using', 'all vanilla models']
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# create admin views by copying to main app/views
|
215
|
+
def create_admin_view_files(m)
|
216
|
+
create_app_files(m, 'views/admin/sms_on_rails')
|
217
|
+
end
|
218
|
+
|
219
|
+
# create admin views by copying to main app/helper
|
220
|
+
def create_helper_files(m)
|
221
|
+
create_app_files(m, 'helpers/admin/sms_on_rails')
|
222
|
+
create_app_files(m, 'helpers/sms_on_rails')
|
223
|
+
end
|
224
|
+
|
225
|
+
# create admin views by copying to main app/controller
|
226
|
+
def create_controller_files(m)
|
227
|
+
create_app_files(m, 'controllers/admin/sms_on_rails')
|
228
|
+
end
|
229
|
+
|
230
|
+
#recursively copy files from templates/* to app/*
|
231
|
+
def create_app_files(m, dir, options={})
|
232
|
+
|
233
|
+
dest_base = options[:dest_base]||'app'
|
234
|
+
relative_src = (options[:relative_src]||'/../../../app').to_s
|
235
|
+
actual_src = File.join(source_root, relative_src)
|
236
|
+
|
237
|
+
m.directory(File.join(dest_base, dir))
|
238
|
+
|
239
|
+
Dir.glob(File.join(actual_src, dir, '*')) do |f|
|
240
|
+
relative_path = relative_source_path(f, actual_src)
|
241
|
+
if File.directory?(f)
|
242
|
+
create_app_files(m, relative_path, options)
|
243
|
+
else
|
244
|
+
m.file(File.join(relative_src, relative_path) , File.join(dest_base, relative_path))
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
#path relative to the source root
|
250
|
+
def relative_source_path(path, src_base = source_root)
|
251
|
+
File.expand_path(path).gsub(File.expand_path(src_base) + '/', '')
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
|