instedd-pigeon 0.1.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.
Files changed (92) hide show
  1. data/.gitignore +25 -0
  2. data/.rvmrc +1 -0
  3. data/Gemfile +9 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +140 -0
  6. data/Rakefile +1 -0
  7. data/app/assets/images/pigeon/android_local_gateway_preview.png +0 -0
  8. data/app/assets/images/pigeon/android_local_gateway_qr.png +0 -0
  9. data/app/assets/images/pigeon/other_local_gateway_preview.png +0 -0
  10. data/app/assets/javascripts/pigeon/qst-server-wizard.js.coffee +58 -0
  11. data/app/assets/javascripts/pigeon/template.js.coffee +43 -0
  12. data/app/assets/javascripts/pigeon/twitter-template.js.coffee +38 -0
  13. data/app/assets/javascripts/pigeon/wizard.js.coffee +95 -0
  14. data/app/assets/javascripts/pigeon.js +2 -0
  15. data/app/assets/stylesheets/pigeon.css.sass +13 -0
  16. data/app/controllers/pigeon/twitter_controller.rb +44 -0
  17. data/app/helpers/.gitkeep +0 -0
  18. data/app/helpers/pigeon/channel_helper.rb +93 -0
  19. data/app/helpers/pigeon/renderer/base.rb +172 -0
  20. data/app/helpers/pigeon/renderer/channel_renderer.rb +58 -0
  21. data/app/helpers/pigeon/renderer.rb +8 -0
  22. data/app/helpers/pigeon/tag_helper.rb +26 -0
  23. data/app/helpers/pigeon/template_helper.rb +20 -0
  24. data/app/helpers/pigeon/text_helper.rb +16 -0
  25. data/app/models/.gitkeep +0 -0
  26. data/app/models/pigeon/channel.rb +220 -0
  27. data/app/models/pigeon/channel_attribute.rb +64 -0
  28. data/app/models/pigeon/channel_schema.rb +113 -0
  29. data/app/models/pigeon/nested_attribute.rb +23 -0
  30. data/app/models/pigeon/nested_scopes.rb +34 -0
  31. data/app/models/pigeon/nuntium_channel.rb +92 -0
  32. data/app/models/pigeon/verboice_channel.rb +82 -0
  33. data/app/views/pigeon/twitter/callback.html.erb +6 -0
  34. data/config/routes.rb +4 -0
  35. data/config/schemas/nuntium/nuntium.yml +210 -0
  36. data/config/schemas/nuntium/qst-server.yml +180 -0
  37. data/config/schemas/nuntium/twitter.yml +56 -0
  38. data/config/schemas/verboice/verboice.yml +76 -0
  39. data/lib/pigeon/engine.rb +30 -0
  40. data/lib/pigeon/errors.rb +28 -0
  41. data/lib/pigeon/initializer.rb +13 -0
  42. data/lib/pigeon/nuntium.rb +10 -0
  43. data/lib/pigeon/verboice.rb +10 -0
  44. data/lib/pigeon/version.rb +3 -0
  45. data/lib/pigeon.rb +25 -0
  46. data/pigeon.gemspec +24 -0
  47. data/spec/data/test_schemas.yml +21 -0
  48. data/spec/dummy/README.rdoc +261 -0
  49. data/spec/dummy/Rakefile +7 -0
  50. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  51. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  52. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  53. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  54. data/spec/dummy/app/mailers/.gitkeep +0 -0
  55. data/spec/dummy/app/models/.gitkeep +0 -0
  56. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  57. data/spec/dummy/config/application.rb +59 -0
  58. data/spec/dummy/config/boot.rb +10 -0
  59. data/spec/dummy/config/database.yml +25 -0
  60. data/spec/dummy/config/environment.rb +5 -0
  61. data/spec/dummy/config/environments/development.rb +37 -0
  62. data/spec/dummy/config/environments/production.rb +67 -0
  63. data/spec/dummy/config/environments/test.rb +37 -0
  64. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  65. data/spec/dummy/config/initializers/inflections.rb +15 -0
  66. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  67. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  68. data/spec/dummy/config/initializers/session_store.rb +8 -0
  69. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  70. data/spec/dummy/config/locales/en.yml +5 -0
  71. data/spec/dummy/config/routes.rb +3 -0
  72. data/spec/dummy/config.ru +4 -0
  73. data/spec/dummy/lib/assets/.gitkeep +0 -0
  74. data/spec/dummy/log/.gitkeep +0 -0
  75. data/spec/dummy/public/404.html +26 -0
  76. data/spec/dummy/public/422.html +26 -0
  77. data/spec/dummy/public/500.html +25 -0
  78. data/spec/dummy/public/favicon.ico +0 -0
  79. data/spec/dummy/script/rails +6 -0
  80. data/spec/helpers/pigeon/channel_helper_spec.rb +173 -0
  81. data/spec/helpers/pigeon/renderer/base_spec.rb +109 -0
  82. data/spec/helpers/pigeon/renderer/channel_renderer_spec.rb +61 -0
  83. data/spec/helpers/pigeon/tag_helper_spec.rb +36 -0
  84. data/spec/helpers/pigeon/template_helper_spec.rb +57 -0
  85. data/spec/models/pigeon/channel_attribute_spec.rb +98 -0
  86. data/spec/models/pigeon/channel_schema_spec.rb +63 -0
  87. data/spec/models/pigeon/channel_spec.rb +205 -0
  88. data/spec/models/pigeon/nuntium_channel_spec.rb +53 -0
  89. data/spec/spec_helper.rb +43 -0
  90. data/spec/support/active_model_lint.rb +15 -0
  91. data/spec/support/test_schemas.rb +12 -0
  92. metadata +254 -0
data/.gitignore ADDED
@@ -0,0 +1,25 @@
1
+ *.gem
2
+ *.rbc
3
+ *.swp
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
19
+ spec/dummy/db/*.sqlite3
20
+ spec/dummy/log/*.log
21
+ spec/dummy/tmp/
22
+ spec/dummy/.sass-cache
23
+ spec/dummy/config/initializers/pigeon.rb
24
+
25
+
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3@pigeon --create
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in pigeon.gemspec
4
+ gemspec
5
+
6
+ gem 'rspec-rails'
7
+ gem 'sqlite3'
8
+ gem 'rspec-html-matchers', :group => :test
9
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Ary Borenszweig
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,140 @@
1
+ # Pigeon
2
+
3
+ This gem handles creating, updating and destroying
4
+ [Nuntium](http://nuntium.instedd.org) and
5
+ [Verboice](http://verboice.instedd.org) channels in your Rails application.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'instedd-pigeon', :require => 'pigeon'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ ## Usage
18
+
19
+ Create an initializer to configure Pigeon (eg. `config/initializers/pigeon.rb`):
20
+
21
+ Pigeon.setup do |config|
22
+ config.application_name = 'My application'
23
+
24
+ config.nuntium_host = 'http://nuntium.instedd.org'
25
+ config.nuntium_account = 'nuntium_account'
26
+ config.nuntium_app = 'nuntium_application'
27
+ config.nuntium_app_password = 'password'
28
+
29
+ config.verboice_host = 'http://verboice.instedd.org'
30
+ config.verboice_account = 'account@example.com'
31
+ config.verboice_password = 'password'
32
+ config.verboice_default_call_flow = 'Default Call Flow'
33
+
34
+ # If you want to support Nuntium Twitter channels, get your Twitter
35
+ # consumer keys from https://dev.twitter.com/apps
36
+ config.twitter_consumer_key = 'CONSUMER_KEY'
37
+ config.twitter_consumer_secret = 'CONSUMER_SECRET'
38
+ end
39
+
40
+ Add Pigeon assets to your application, for example by adding to
41
+ `app/assets/javascripts/application.js` the line
42
+
43
+ //= require pigeon
44
+
45
+ and to `app/assets/stylesheets/application.css`
46
+
47
+ /*
48
+ *= require pigeon
49
+ */
50
+
51
+ If you need to support Nuntium Twitter channels, mount the Pigeon engine by
52
+ adding to your `routes.rb`
53
+
54
+ mount Pigeon::Engine => '/pigeon'
55
+
56
+ It is **strongly advised** to filter the engine's request through
57
+ authentication. If your application uses Devise, you can easily do it by
58
+ mounting the engine with `authenticate`:
59
+
60
+ authenticate :user do
61
+ mount Pigeon::Engine => '/pigeon'
62
+ end
63
+
64
+ Once properly configured, the gem provides a couple of classes
65
+ `Pigeon::NuntiumChannel` and `Pigeon::VerboiceChannel` to manipulate channels
66
+ which act as ActiveModels and provide a similar API to
67
+ [ActiveResource](https://github.com/rails/activeresource).
68
+
69
+ Pigeon channels should have a `kind` linking them to schemas which provide
70
+ information about the specific attributes required to configure each channel
71
+ type. The class methods `schemas` and `find_schema` provide access to all known
72
+ schemas.
73
+
74
+ Sample interaction session:
75
+
76
+ > c = Pigeon::NuntiumChannel.new name: 'foo', kind: 'pop3'
77
+ => #<Pigeon::NuntiumChannel:0xa45938c>
78
+ > c.schema.kind
79
+ => "pop3"
80
+ > c.attributes
81
+ => {"protocol"=>"mailto", "priority"=>100, "enabled"=>true, "direction"=>"bidirectional", "configuration"=>{}, "name"=>"foo", "kind"=>"pop3"}
82
+ > c.schema.user_attributes
83
+ => ["configuration[host]", "configuration[port]", "configuration[user]", "configuration[password]", "configuration[use_ssl]", "configuration[remove_quoted_text_or_text_after_first_empty_line]"]
84
+ > c.configuration[:host] = 'example.com'
85
+ => "example.com"
86
+ > c.assign_attributes('configuration[user]' => 'foo', 'configuration[password]' => 'bar')
87
+ => {"configuration[user]"=>"foo", "configuration[password]"=>"bar"}
88
+ > c.save
89
+ => false
90
+ > c.errors.full_messages
91
+ => ["port is not a number"]
92
+ > c.write_attribute('configuration[port]', 110)
93
+ => 110
94
+ > c.new_record?
95
+ => true
96
+ > c.save
97
+ => true
98
+ > Pigeon::NuntiumChannel.list
99
+ => ["foo"]
100
+ > c = Pigeon::NuntiumChannel.find('foo')
101
+ => #<Pigeon::NuntiumChannel:0xb027708>
102
+ > c.kind
103
+ => "pop3"
104
+ > c.new_record?
105
+ => false
106
+ > c.destroy
107
+ => true
108
+ > c.destroyed?
109
+ => true
110
+
111
+ The gem also provides helpers to aid in the rendering of the channel's
112
+ configuration form. The most important ones are
113
+ `pigeon_nuntium_channel_kinds_for_select` and
114
+ `pigeon_verboice_channel_kinds_for_select` to use as options generators for the
115
+ `select_tag` Rails helper, and `pigeon_render_channel` which will render
116
+ the fields required for a user to configure the given channel.
117
+
118
+ For example, in the view:
119
+
120
+ <%= form_tag('/channels') do %>
121
+ <%= hidden_field_tag :name, @channel.name %>
122
+ <%= pigeon_render_channel @channel %>
123
+ <%= end %>
124
+
125
+ Then in the controller:
126
+
127
+ def update
128
+ @channel = Pigeon::NuntiumChannel.find(params[:name])
129
+ @channel.assign_attributes(params[:channel])
130
+ @channel.save!
131
+ redirect_to channels_path
132
+ end
133
+
134
+ ## Contributing
135
+
136
+ 1. Fork it
137
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
138
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
139
+ 4. Push to the branch (`git push origin my-new-feature`)
140
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,58 @@
1
+ #= require pigeon/wizard
2
+
3
+ class QstServerWizard extends PigeonWizard
4
+ onPhoneType: (type) ->
5
+ @pages.each (index, page) ->
6
+ page_phone_type = $(page).data('phone-type')
7
+ if page_phone_type
8
+ page.disabled = page_phone_type != type
9
+ true
10
+ @attribute('phone_type').val(type)
11
+ @updateNavigation()
12
+
13
+ initPhoneType: (type) ->
14
+ @phone_type_radios.each (index, radio) ->
15
+ $(radio).attr('checked', radio.value == type)
16
+ @onPhoneType type
17
+
18
+ initWizard: ->
19
+ self = this
20
+
21
+ @navigation.show()
22
+ @pages[0].disabled = true
23
+
24
+ @ticket_code_fields = $('.ticket_code', @div)
25
+ @phone_type_radios = $('.phone_type', @div)
26
+
27
+ @initPhoneType @attribute('phone_type').val()
28
+ @phone_type_radios.click ->
29
+ self.onPhoneType @value
30
+
31
+ @ticket_code_fields.change ->
32
+ # update both ticket_code fields to make sure the current value gets
33
+ # posted
34
+ self.attribute('ticket_code').val(@value)
35
+
36
+ password_field = @attribute('configuration[password]')
37
+ if password_field.val() == ''
38
+ password_field.val(@generatePassword())
39
+
40
+ @attribute('ticket_message').val("This phone will be used for #{@app_name}.")
41
+ @attribute('use_ticket').val(true)
42
+
43
+ initPersisted: ->
44
+ $('#qst-reconfigure', @div).click =>
45
+ @initWizard()
46
+ @selectPage 1
47
+ @navigation.hide()
48
+ @selectPage 0
49
+
50
+ run: ->
51
+ if @persisted
52
+ @initPersisted()
53
+ else
54
+ @initWizard()
55
+ @selectDefaultPage()
56
+
57
+ PigeonWizard.registerClass 'qst-server', QstServerWizard
58
+
@@ -0,0 +1,43 @@
1
+ class PigeonTemplate
2
+ @klasses = {}
3
+
4
+ @registerClass: (type, klass) ->
5
+ @klasses[type] = klass
6
+
7
+ constructor: (@div) ->
8
+ div = $(@div)
9
+ @scope = div.data('scope')
10
+ @channel_name = div.data('name')
11
+ @channel_kind = div.data('kind')
12
+ @persisted = div.data('persisted')
13
+ @app_name = div.data('application-name') || 'Pigeon'
14
+
15
+ scoped_name: (name) ->
16
+ if @scope
17
+ bracket = name.indexOf('[')
18
+ if bracket >= 0
19
+ @scope + '[' + name[0..bracket-1] + ']' + name[bracket..-1]
20
+ else
21
+ @scope + '[' + name + ']'
22
+ else
23
+ name
24
+
25
+ attribute: (name) ->
26
+ $("[name=\"#{@scoped_name(name)}\"]", @div)
27
+
28
+ run: ->
29
+
30
+ window.PigeonTemplate = PigeonTemplate
31
+
32
+ jQuery.fn.pigeonTemplate = ->
33
+ @each (index, template) ->
34
+ type = $(template).data('type')
35
+ klass = PigeonTemplate.klasses[type]
36
+ if klass
37
+ new klass(template).run()
38
+ else
39
+ new PigeonTemplate(template).run()
40
+
41
+ jQuery ->
42
+ $('.pigeon.pigeon_template').pigeonTemplate()
43
+
@@ -0,0 +1,38 @@
1
+ #= require pigeon/template
2
+
3
+ class TwitterTemplate extends PigeonTemplate
4
+ onAuthorized: ->
5
+ $('.twitter_not_authorized').hide()
6
+ $('.twitter_authorized').show()
7
+ $('.screen_name').text(@screen_name.val())
8
+
9
+ beginTwitterAuthorization: ->
10
+ callback = 'pigeon_callback_' + (Math.round(Math.random() * 1000000))
11
+ window[callback] = (token, secret, screen_name) =>
12
+ @token.val(token)
13
+ @secret.val(secret)
14
+ @screen_name.val(screen_name)
15
+ @onAuthorized()
16
+
17
+ url = @twitter_auth_url + '?js_callback=' + callback
18
+ window.open(url, 'pigeon_twitter', 'menubar=no,location=yes,width=593,height=533')
19
+
20
+ run: ->
21
+ @screen_name = @attribute('configuration[screen_name]')
22
+ @token = @attribute('configuration[token]')
23
+ @secret = @attribute('configuration[secret]')
24
+
25
+ @button = $('.twitter_authorize_button')
26
+ @twitter_auth_url = $(@div).data('twitter-path')
27
+
28
+ if @screen_name.val() != ''
29
+ @onAuthorized()
30
+ else
31
+ $('.twitter_not_authorized').show()
32
+ $('.twitter_authorized').hide()
33
+
34
+ @button.click =>
35
+ @beginTwitterAuthorization()
36
+
37
+ PigeonTemplate.registerClass 'twitter', TwitterTemplate
38
+
@@ -0,0 +1,95 @@
1
+ #= require pigeon/template
2
+
3
+ class PigeonWizard extends PigeonTemplate
4
+ @klasses = {}
5
+
6
+ @registerClass: (type, klass) ->
7
+ @klasses[type] = klass
8
+
9
+ constructor: (@div) ->
10
+ super
11
+ @prevButton = $('<button type="button">Prev</button>')
12
+ @nextButton = $('<button type="button">Next</button>')
13
+ @pages = $(@div).find('.pigeon_wizard_page')
14
+ @navigation = $('<div class="pigeon_wizard_navigation"></div>').append(@prevButton).append(@nextButton).appendTo(@div)
15
+ @current = -1
16
+
17
+ @prevButton.click =>
18
+ prev = @prevActivePage(@current)
19
+ @selectPage prev if prev >= 0
20
+
21
+ @nextButton.click =>
22
+ next = @nextActivePage(@current)
23
+ @selectPage next if next >= 0
24
+
25
+ prevActivePage: (index) ->
26
+ index--
27
+ while index >= 0 && @pages[index].disabled
28
+ index--
29
+ index
30
+
31
+ nextActivePage: (index) ->
32
+ index++
33
+ while index < @pages.length && @pages[index].disabled
34
+ index++
35
+ if index >= @pages.length then -1 else index
36
+
37
+ selectPage: (index) ->
38
+ $(@pages[@current]).removeClass('active') unless @current < 0
39
+ $(@pages[index]).addClass('active')
40
+ @current = index
41
+ @updateNavigation()
42
+
43
+ updateNavigation: ->
44
+ if @prevActivePage(@current) < 0
45
+ @prevButton.attr('disabled', 'disabled')
46
+ else
47
+ @prevButton.removeAttr('disabled')
48
+ if @nextActivePage(@current) < 0
49
+ @nextButton.attr('disabled', 'disabled')
50
+ else
51
+ @nextButton.removeAttr('disabled')
52
+
53
+ selectDefaultPage: ->
54
+ # If any active page has a field with an error, select that
55
+ # Otherwise, select the first active page
56
+ pages_with_errors = $('.field_with_errors').
57
+ parents('.pigeon_wizard_page').filter -> !@disabled
58
+ found = -1
59
+ if pages_with_errors.length > 0
60
+ pages_with_errors.each (index, page) =>
61
+ index_in_pages = $.inArray(page, @pages)
62
+ if found < 0 || (index_in_pages >= 0 && index_in_pages < found)
63
+ found = index_in_pages
64
+
65
+ if found >= 0
66
+ @selectPage found
67
+ else
68
+ @selectPage @nextActivePage(-1)
69
+
70
+ run: ->
71
+ @selectDefaultPage()
72
+
73
+ generatePassword: (length = 8) ->
74
+ charset = "abcdefghijklnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
75
+ retVal = ""
76
+ n = charset.length
77
+ for i in [0..length]
78
+ retVal += charset.charAt(Math.floor(Math.random() * n))
79
+ retVal
80
+
81
+
82
+ window.PigeonWizard = PigeonWizard
83
+
84
+ jQuery.fn.pigeonWizard = ->
85
+ @each (index, wizard) ->
86
+ type = $(wizard).data('type')
87
+ klass = PigeonWizard.klasses[type]
88
+ if klass
89
+ new klass(wizard).run()
90
+ else
91
+ new PigeonWizard(wizard).run()
92
+
93
+ jQuery ->
94
+ $('.pigeon.pigeon_wizard').pigeonWizard()
95
+
@@ -0,0 +1,2 @@
1
+ //= require_self
2
+ //= require_tree ./pigeon
@@ -0,0 +1,13 @@
1
+ .pigeon
2
+ &.pigeon_template
3
+ .pigeon_attribute
4
+ margin-top: 20px
5
+ input[type=text], input[type=password], input[type=email], input[type=url]
6
+ width: 300px
7
+
8
+ &.pigeon_wizard
9
+ .pigeon_wizard_page
10
+ display: none
11
+ &.active
12
+ display: block
13
+
@@ -0,0 +1,44 @@
1
+ require 'twitter_oauth'
2
+
3
+ module Pigeon
4
+ class TwitterController < ActionController::Base
5
+ def begin
6
+ client = new_twitter_client
7
+
8
+ request_token = client.request_token(:oauth_callback => twitter_callback_url)
9
+ session[:pigeon] ||= {}
10
+ session[:pigeon][:twitter] = {
11
+ token: request_token.token,
12
+ secret: request_token.secret
13
+ }
14
+ session[:pigeon][:js_callback] = params[:js_callback]
15
+ redirect_to request_token.authorize_url
16
+ end
17
+
18
+ def callback
19
+ if session[:pigeon].nil? || session[:pigeon][:twitter].nil?
20
+ redirect_to twitter_url
21
+ end
22
+
23
+ client = new_twitter_client
24
+
25
+ request_token = session[:pigeon][:twitter]
26
+ @access_token = client.authorize(
27
+ request_token[:token],
28
+ request_token[:secret],
29
+ :oauth_verifier => params[:oauth_verifier]
30
+ )
31
+ @callback = session[:pigeon][:js_callback] || 'pigeon_twitter_callback'
32
+ @screen_name = client.info['screen_name']
33
+ end
34
+
35
+ private
36
+
37
+ def new_twitter_client
38
+ client = TwitterOAuth::Client.new(
39
+ :consumer_key => Pigeon.config.twitter_consumer_key,
40
+ :consumer_secret => Pigeon.config.twitter_consumer_secret
41
+ )
42
+ end
43
+ end
44
+ end
File without changes
@@ -0,0 +1,93 @@
1
+ module Pigeon
2
+ module ChannelHelper
3
+ include ActionView::Helpers::CaptureHelper
4
+ include ActionView::Helpers::FormHelper
5
+ include ActionView::Helpers::FormOptionsHelper
6
+
7
+ def pigeon_attribute_field(attribute, value = nil, options = {})
8
+ scope = options.delete(:scope)
9
+ field_name = attribute.scoped_name(scope)
10
+ field_value = value || ''
11
+ forced_type = options.delete(:type)
12
+ render_type = (forced_type || attribute.type).to_s
13
+
14
+ case render_type
15
+ when "string"
16
+ text_field_tag(field_name, field_value, options)
17
+ when "password"
18
+ password_field_tag(field_name, field_value, options)
19
+ when "integer"
20
+ number_field_tag(field_name, field_value, options)
21
+ when "enum"
22
+ choices = attribute.options
23
+ if choices.length > 0 && choices[0].is_a?(Hash)
24
+ choices = choices.map { |h| [h["display"], h["value"]] }
25
+ end
26
+ select_tag(field_name, options_for_select(choices, field_value), options)
27
+ when "timezone"
28
+ select_tag(field_name, time_zone_options_for_select(field_value), options)
29
+ when "boolean"
30
+ check_box_tag(field_name, '1', field_value.present?, options)
31
+ when "hidden"
32
+ hidden_field_tag(field_name, field_value, options)
33
+ else
34
+ text_field_tag(field_name, field_value,
35
+ { :type => render_type }.merge(options))
36
+ end
37
+ end
38
+
39
+ def pigeon_attribute_label(attribute, options = {})
40
+ return '' if attribute.type == :hidden
41
+ scope = options.delete(:scope)
42
+ field_name = attribute.scoped_name(scope)
43
+ label_tag(field_name, attribute.label, options)
44
+ end
45
+
46
+ def pigeon_attribute(attribute, value = nil, options = {})
47
+ scope = options.delete(:scope)
48
+ field_with_errors = options.delete(:field_with_errors)
49
+ content_tag :div, options do
50
+ label = pigeon_attribute_label(attribute, scope: scope)
51
+ field = pigeon_attribute_field(attribute, value, scope: scope)
52
+ if field_with_errors.present?
53
+ field = content_tag :div, field, :class => 'field_with_errors'
54
+ end
55
+ if attribute.type == :boolean
56
+ safe_join([field, label])
57
+ elsif attribute.type == :hidden
58
+ field
59
+ else
60
+ safe_join([label, tag(:br), field])
61
+ end
62
+ end
63
+ end
64
+
65
+ def pigeon_channel_attribute_field(channel, attr_name, options = {})
66
+ value = channel.read_attribute(attr_name)
67
+ attribute = channel.schema.try(:find_attribute, attr_name)
68
+ attribute ||= ChannelAttribute.build_default(attr_name, value)
69
+ field = pigeon_attribute_field(attribute, value, options)
70
+ if channel.errors.include?(attr_name.to_sym)
71
+ content_tag :div, field, :class => 'field_with_errors'
72
+ else
73
+ field
74
+ end
75
+ end
76
+
77
+ def pigeon_channel_attribute_label(channel, attr_name, options = {})
78
+ attribute = channel.schema.try(:find_attribute, attr_name)
79
+ attribute ||= ChannelAttribute.build_default(attr_name)
80
+ pigeon_attribute_label(attribute, options)
81
+ end
82
+
83
+ def pigeon_channel_attribute(channel, attr_name, options = {})
84
+ value = channel.read_attribute(attr_name)
85
+ attribute = channel.schema.try(:find_attribute, attr_name)
86
+ attribute ||= ChannelAttribute.build_default(attr_name, value)
87
+ if channel.errors.include?(attr_name.to_sym)
88
+ options[:field_with_errors] = true
89
+ end
90
+ pigeon_attribute(attribute, value, options)
91
+ end
92
+ end
93
+ end