vjt-zendesk 1.2.0

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.
@@ -0,0 +1,127 @@
1
+ Zendesk on Rails - Dropbox and Remote Authentication
2
+ ====================================================
3
+
4
+ Purpose
5
+ -------
6
+
7
+ The plugin implements the HTML generation code for the
8
+ [Zendesk dropbox](http://www.zendesk.com/blog/instant-support-access-with-drop-box)
9
+ and the necessary controller and routing code to implement
10
+ [Zendesk's remote authentication](http://www.zendesk.com/api/remote-authentication)
11
+
12
+
13
+ Installation
14
+ ------------
15
+
16
+ In Gemfile
17
+
18
+ gem 'vjt-zendesk', :require => 'zendesk'
19
+
20
+ Configuration
21
+ -------------
22
+
23
+ In your `config/routes.rb`:
24
+
25
+ zendesk :on => '/support', :controller => 'root'
26
+
27
+ The `/support` path will then respond to the methods that generate the query
28
+ string parameters required for Remote Authentication, while the `/support/exit`
29
+ path will simply set a notice in the flash and redirect the user to the app
30
+ `root_url`. You can override this behaviour by implementing a `zendesk_logout`
31
+ method in the controller.
32
+
33
+ Finally, in your config/application.rb:
34
+
35
+ config.zendesk = {
36
+ :token => 'Your Zendesk token',
37
+ :hostname => 'example.zendesk.com',
38
+ :login => proc { [current_user.name, current_user.email] },
39
+ :login_url => :login_url,
40
+ :dropbox => {
41
+ :title => 'Dropbox title',
42
+ :email => proc { current_user.email rescue nil }
43
+ }
44
+ }
45
+
46
+ The required options are:
47
+
48
+ * `:token` -- your zendesk [shared secret](http://www.zendesk.com/api/remote-authentication)
49
+ * `:hostname` -- your zendesk account host name
50
+ * `:login` -- a `Proc` object evaluated in the controller instance context,
51
+ that must return an `Array` whose first element is the current user name and the second its email.
52
+ This `Proc` is evaluated iff the `logged_in?` instance method of your controller returns true.
53
+ * `:login_url` -- The name of the named route helper that generates the full URL of your login page.
54
+ We use `:ssl_login_url` thanks to our [SSL Helper](http://github.com/vjt/ssl_helper) plugin.
55
+
56
+ The `:dropbox` option is for the [Zendesk dropbox](http://www.zendesk.com/blog/instant-support-access-with-drop-box)
57
+ configuration, it should be an hash with symbolized keys and it is converted to
58
+ `JSON` and bound to the `zendesk_params` Javascript variable.
59
+
60
+ To facilitate the Dropbox usage, the `:email` option can be a `Proc` object that
61
+ is then evaluated in the controller instance context and should return the current
62
+ user e-mail or nil if the user is not logged in. If the `:email` option is unset
63
+ no e-mail appears precompiled in the Dropbox for, or you could even set a static
64
+ email for every feedback request (dunno why should you do that, though :-).
65
+
66
+
67
+ Usage
68
+ -----
69
+
70
+ To embed the Dropbox tags, use the `zendesk_dropbox_tags` helper
71
+ in your layout:
72
+
73
+ <%= zendesk_dropbox_tags %>
74
+
75
+ To display a link that displays the dropbox when clicked use the
76
+ `zendesk_dropbox_link_to` helper in your views:
77
+
78
+ <%= zendesk_dropbox_link_to 'Send feedback' %>
79
+
80
+ To display a link that starts the Remote Authentication process
81
+ use the `zendesk_link_to` helper in your views:
82
+
83
+ <%= zendesk_link_to 'Support' %>
84
+
85
+ The second parameter of said helper is passed to Rails' `link_to`
86
+ one to customize the link tag attributes.
87
+
88
+
89
+ Caching
90
+ -------
91
+
92
+ If you implement asset minifization and concatenation, you'll surely
93
+ want to reduce HTTP requests to external services. While it's not the
94
+ best practice in the world to cache said services assets, to speed up
95
+ your application you may be forced to do it.
96
+
97
+ [Panmind](http://panmind.com), where this project originated, is doing
98
+ this, both to reduce the number of HTTP requests and because the lag with
99
+ `assets0.zendesk.com` from Europe is quite high.
100
+
101
+ To make a long story short, if you're including the Zendesk assets in
102
+ your minified blobs, you can use just the `zendesk_dropbox_config` view
103
+ helper to generate the dropbox configuration, placing it before the
104
+ inclusion of your JS blobs: this way the `zenbox_params` variable will
105
+ be already defined when the JS is evaluated.
106
+
107
+
108
+ Compatibility
109
+ -------------
110
+
111
+ Tested with Rails 3.0.x running under Ruby 1.9.2.
112
+
113
+
114
+ TODO
115
+ ----
116
+
117
+ * Your login action must implement a `redirect_to params[:return_to] || some_other_url`
118
+ or redirects to Zendesk won't work: remove relying on this assumption. Cleanly.
119
+ * Clean up configuration by requiring less variables: *convention over configuration*!
120
+ * Configuration of the `logged_in?` method name
121
+ * Allow options passing to the `zendesk_dropbox_link_to` helper
122
+ * Code documentation
123
+ * Tests (yuck!)
124
+
125
+ Please fork the project and send us a pull request if you check off any of these items
126
+ from the to-do list, or for any other improvement. Thanks! :-)
127
+
@@ -0,0 +1,48 @@
1
+ require 'rake'
2
+ require 'rake/rdoctask'
3
+
4
+ require 'lib/zendesk/version'
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gemspec|
9
+ gemspec.name = 'vjt-zendesk'
10
+
11
+ gemspec.summary = 'Zendesk on Rails - Dropbox and Remote Authentication'
12
+ gemspec.description = 'The plugin implements the HTML generation code for the ' \
13
+ 'Zendesk dropbox and the necessary controller and routing ' \
14
+ 'code to implement remote authentication'
15
+
16
+ gemspec.authors = ['Marcello Barnaba']
17
+ gemspec.email = 'vjt@openssl.it'
18
+ gemspec.homepage = 'http://github.com/vjt/zendesk'
19
+
20
+ gemspec.files = %w( README.md Rakefile rails/init.rb ) + Dir['lib/**/*']
21
+ gemspec.extra_rdoc_files = %w( README.md )
22
+ gemspec.has_rdoc = true
23
+
24
+ gemspec.version = Zendesk::Version
25
+ gemspec.date = '2010-11-23'
26
+
27
+ gemspec.require_path = 'lib'
28
+
29
+ gemspec.add_dependency('rails', '~> 3.0')
30
+ end
31
+ rescue LoadError
32
+ puts 'Jeweler not available. Install it with: gem install jeweler'
33
+ end
34
+
35
+ desc 'Generate the rdoc'
36
+ Rake::RDocTask.new do |rdoc|
37
+ rdoc.rdoc_files.add %w( README.md lib/**/*.rb )
38
+
39
+ rdoc.main = 'README.md'
40
+ rdoc.title = 'Zendesk on Rails - Dropbox and Remote Authentication'
41
+ end
42
+
43
+ desc 'Will someone help write tests?'
44
+ task :default do
45
+ puts
46
+ puts 'Can you help in writing tests? Please do :-)'
47
+ puts
48
+ end
@@ -0,0 +1,72 @@
1
+ require 'zendesk/controller'
2
+ require 'zendesk/helpers'
3
+ require 'zendesk/routing'
4
+ require 'zendesk/version'
5
+ require 'zendesk/railtie'
6
+
7
+ # Zendesk remote authentication helper for Rails. Implements JS generation,
8
+ # controller actions and route helpers. Have a look at the code, because it
9
+ # is more explanatory than a thousand words :-)
10
+ #
11
+ # Kudos to the Zendesk staff for such a simple and effective interface.
12
+ #
13
+ # (C) 2010 Panmind, Released under the terms of the Ruby License.
14
+ # (C) 2011 vjt@openssl.it
15
+ #
16
+ # - vjt Wed May 18 23:01:09 CEST 2011
17
+ #
18
+ module Zendesk
19
+ class ConfigurationError < StandardError; end
20
+
21
+ class << self
22
+ attr_reader :token, :hostname
23
+
24
+ def auth_url; @auth_url ||= "http://#{hostname}/access/remote/".freeze end
25
+ def return_url; @return_url ||= "http://#{hostname}/login".freeze end
26
+ def support_url; @support_url ||= "http://#{hostname}/home".freeze end
27
+
28
+ # TODO these should become attr_readers and we set @variables directly
29
+ attr_accessor :dropbox, :login, :login_url, :js_asset_path, :js_asset_name, :css_asset_path, :css_asset_name
30
+
31
+ def check_configuration!
32
+ options = Rails.application.config.zendesk rescue nil
33
+
34
+ bail "Zendesk configuration missing: please define config.zendesk" unless options.present?
35
+
36
+ self.token, self.hostname, self.login, self.login_url =
37
+ options.values_at(:token, :hostname, :login, :login_url)
38
+
39
+ bail "API token is missing" unless self.token.present?
40
+ bail "Support hostname is missing" unless self.hostname.present?
41
+ bail "Login proc is missing" unless self.login.present?
42
+ bail "Login URL named route is missing" unless self.login_url.present?
43
+
44
+ # Dropbox specific customizations, defaults in place
45
+ self.dropbox = (options[:dropbox] || {}).reverse_merge(
46
+ :dropboxID => 'feedback',
47
+ :url => Zendesk.hostname
48
+ ).freeze
49
+
50
+ # Path and name for css and asset required for zenbox 2.0
51
+ self.js_asset_path = options[:js_asset_path] || '//assets0.zendesk.com/external/zenbox'
52
+ self.js_asset_name = options[:js_asset_name] || 'zenbox-2.0'
53
+ self.css_asset_path = options[:css_asset_path] || '//assets0.zendesk.com/external/zenbox'
54
+ self.css_asset_name = options[:css_asset_name] || 'zenbox-2.0'
55
+ end
56
+
57
+ def enabled?
58
+ # FIXME we should not disable this code in the
59
+ # test environment, rather test it appropriately
60
+ Rails.env.production? || Rails.env.development?
61
+ end
62
+
63
+ private
64
+ def token=(token); @token = token.freeze rescue nil end
65
+ def hostname=(hostname); @hostname = hostname.freeze end
66
+
67
+ def bail(message)
68
+ raise ConfigurationError, message
69
+ end
70
+ end
71
+
72
+ end
@@ -0,0 +1,53 @@
1
+ require 'digest/md5'
2
+
3
+ module Zendesk
4
+
5
+ module Controller
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before_filter :zendesk_handle_guests, :only => :zendesk_login
10
+ end
11
+
12
+ def zendesk_login
13
+ name, email = instance_exec(&Zendesk.login)
14
+
15
+ now = params[:timestamp] || Time.now.to_i.to_s
16
+ hash = Digest::MD5.hexdigest(name + email + Zendesk.token + now)
17
+ back = params[:return_to] || Zendesk.return_url
18
+
19
+ auth_params = [
20
+ '?name=' + CGI.escape(name),
21
+ '&email=' + CGI.escape(email),
22
+ '&timestamp=' + now,
23
+ '&hash=' + hash,
24
+ '&return_to=' + back
25
+ ].join
26
+
27
+ redirect_to(Zendesk.auth_url + auth_params)
28
+ end
29
+
30
+ def zendesk_logout
31
+ flash[:notice] = "Thanks for visiting our support forum."
32
+ redirect_to root_url
33
+ end
34
+
35
+ private
36
+ def zendesk_handle_guests
37
+ return if logged_in? rescue false # TODO add another option
38
+
39
+ if params[:timestamp] && params[:return_to]
40
+ # User clicked on Zendesk "login", thus redirect to our
41
+ # login page, that'll redirect him/her back to Zendesk.
42
+ #
43
+ redirect_to send(Zendesk.login_url, :return_to => support_url)
44
+ else
45
+ # User clicked on our "support" link, and maybe doesn't
46
+ # have an account yet: redirect him/her to the support.
47
+ #
48
+ redirect_to Zendesk.support_url
49
+ end
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,32 @@
1
+ module Zendesk
2
+
3
+ module Helpers
4
+ def zendesk_dropbox_config
5
+ config = Zendesk.dropbox
6
+
7
+ [:requester_email, :requester_name].each do |key|
8
+ config = config.merge(key => instance_exec(&config[key])) if config[key].kind_of?(Proc)
9
+ end
10
+
11
+ javascript_tag("var zenbox_params = #{config.to_json};").html_safe
12
+ end
13
+
14
+ def zendesk_dropbox_tags
15
+ return unless Zendesk.enabled?
16
+
17
+ %(#{zendesk_dropbox_config}
18
+ <style type='text/css' media='screen,projection'>@import url('#{Zendesk.css_asset_path}/#{Zendesk.css_asset_name}.css');</style>
19
+ <script type='text/javascript' src='#{Zendesk.js_asset_path}/#{Zendesk.js_asset_name}.js'></script>).html_safe
20
+ end
21
+
22
+ def zendesk_link_to(text, options = {})
23
+ return unless Zendesk.enabled?
24
+ link_to text, support_path, options
25
+ end
26
+
27
+ def zendesk_dropbox_link_to(text)
28
+ link_to text, '#', :onclick => 'Zenbox.render (); return false'
29
+ end
30
+ end
31
+
32
+ end
@@ -0,0 +1,20 @@
1
+ require 'zendesk'
2
+
3
+ module Zendesk
4
+
5
+ class Railtie < Rails::Railtie
6
+ initializer 'zendesk.insert_into_action_view' do
7
+ ActiveSupport.on_load :action_view do
8
+ ActionView::Base.instance_eval { include Zendesk::Helpers }
9
+ ActionDispatch::Routing::Mapper.instance_eval { include Zendesk::Routing }
10
+ end
11
+ end
12
+
13
+ initializer 'zendesk.check_configuration' do
14
+ ActiveSupport.on_load :after_initialize do
15
+ Zendesk.check_configuration!
16
+ end
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,24 @@
1
+ module Zendesk
2
+
3
+ module Routing
4
+ def zendesk(options = {})
5
+ return unless Zendesk.enabled?
6
+
7
+ base = options[:on] || '/zendesk'
8
+ ctrl = options[:controller]
9
+
10
+ unless ctrl.present?
11
+ raise ConfigurationError, "Missing :controller option"
12
+ end
13
+
14
+ scope base.to_s, :controller => ctrl do
15
+ get '/', :action => :zendesk_login, :as => base.to_sym
16
+ get '/exit', :action => :zendesk_logout, :as => nil
17
+ end
18
+
19
+ # Install the methods into the given controller
20
+ "#{ctrl.camelize}Controller".constantize.instance_eval { include Controller }
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,3 @@
1
+ module Zendesk
2
+ Version = '1.2.0'
3
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vjt-zendesk
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 2
9
+ - 0
10
+ version: 1.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Marcello Barnaba
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-23 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rails
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ version: "3.0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description: The plugin implements the HTML generation code for the Zendesk dropbox and the necessary controller and routing code to implement remote authentication
37
+ email: vjt@openssl.it
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - README.md
44
+ files:
45
+ - README.md
46
+ - Rakefile
47
+ - lib/zendesk.rb
48
+ - lib/zendesk/controller.rb
49
+ - lib/zendesk/helpers.rb
50
+ - lib/zendesk/railtie.rb
51
+ - lib/zendesk/routing.rb
52
+ - lib/zendesk/version.rb
53
+ has_rdoc: true
54
+ homepage: http://github.com/vjt/zendesk
55
+ licenses: []
56
+
57
+ post_install_message:
58
+ rdoc_options: []
59
+
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ hash: 3
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 3
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ requirements: []
81
+
82
+ rubyforge_project:
83
+ rubygems_version: 1.4.1
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Zendesk on Rails - Dropbox and Remote Authentication
87
+ test_files: []
88
+