zendesk-tools 0.0.4

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: f5dbb43b53a5d36b8267fa908f235123036edb28
4
+ data.tar.gz: 49cc7c1bda607fcf622a777363ce58c907a835f4
5
+ SHA512:
6
+ metadata.gz: 62bbbe159db16acd407f30808ebb066215a04404a2c206f31ba681706304b71f0f3c5f8a1c8a07559840801e250ad1d6790cef131136821e9ce8fc4815f401ae
7
+ data.tar.gz: cc76ed280eead3c76219de63451da42b8300512f1fb1b6b3a7c016f3cfa9fc8b696fdca7ff287cfced5bd42eed526aaa84d06aa3ffd854448da5484c8c4cda92
data/.gitattributes ADDED
@@ -0,0 +1,22 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
3
+
4
+ # Custom for Visual Studio
5
+ *.cs diff=csharp
6
+ *.sln merge=union
7
+ *.csproj merge=union
8
+ *.vbproj merge=union
9
+ *.fsproj merge=union
10
+ *.dbproj merge=union
11
+
12
+ # Standard to msysgit
13
+ *.doc diff=astextplain
14
+ *.DOC diff=astextplain
15
+ *.docx diff=astextplain
16
+ *.DOCX diff=astextplain
17
+ *.dot diff=astextplain
18
+ *.DOT diff=astextplain
19
+ *.pdf diff=astextplain
20
+ *.PDF diff=astextplain
21
+ *.rtf diff=astextplain
22
+ *.RTF diff=astextplain
data/.gitignore ADDED
@@ -0,0 +1,17 @@
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
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in zendesk-tools.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 FINN.no AS
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,35 @@
1
+ # ZendeskTools
2
+
3
+ Tools to automate common tasks in ZenDesk.
4
+
5
+ ## Installation
6
+
7
+ Install the gem:
8
+
9
+ $ gem install zendesk-tools --source "http://gems.finn.no"
10
+
11
+ ## Usage
12
+
13
+ Add a JSON config to ~/.zendesk-tools.json (TODO: make command line ovveride):
14
+
15
+ {
16
+
17
+ // mandatory
18
+ "username": "user@example.com",
19
+ "token": "your_token_here",
20
+
21
+ // optional
22
+ "log_level": "debug",
23
+ "log_file": "/some/path"
24
+
25
+ }
26
+
27
+ Clean suspended tickets:
28
+
29
+ $ zendesk-tools clean-suspended
30
+
31
+ Upload files to ticket:
32
+
33
+ $ zendesk-tools upload-files-to-ticket <ticket_id> <files>
34
+
35
+
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ require 'bundler/setup'
2
+ require 'rake/clean'
3
+
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ CLEAN << "pkg"
7
+ CLEAN << "*.gem"
8
+
9
+ GEM_NAME = "zendesk-tools-#{ZendeskTools::VERSION}.gem"
10
+
11
+ zdt_gem = file "pkg/#{GEM_NAME}" do |t|
12
+ mkdir_p "pkg"
13
+ sh "gem build zendesk-tools.gemspec"
14
+ mv GEM_NAME, t.name
15
+ end
16
+
17
+ desc "Build #{zdt_gem.name}"
18
+ task :build => [:clean, zdt_gem.name]
19
+
data/bin/zendesk-tools ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'zendesk-tools'
4
+
5
+ cmd = ARGV.shift
6
+
7
+ if cmd.nil?
8
+ ZendeskTools.show_config
9
+ exit 1
10
+ end
11
+
12
+ case cmd
13
+ when 'clean-suspended'
14
+ ZendeskTools::CleanSuspended.run(ARGV)
15
+ when 'upload-files-to-ticket'
16
+ ZendeskTools::UploadFilesToTicket.run(ARGV)
17
+ when 'recover-suspended'
18
+ ZendeskTools::RecoverSuspended.run(ARGV)
19
+ else
20
+ abort "Sorry, I don't know how to #{cmd.inspect}"
21
+ end
@@ -0,0 +1,60 @@
1
+ require "zendesk-tools/version"
2
+ require "zendesk_api"
3
+ require 'json'
4
+ require 'pathname'
5
+ require 'pp'
6
+ require 'logger'
7
+ require 'log4r'
8
+ require 'log4r/config'
9
+
10
+ require 'zendesk-tools/loggable'
11
+ require 'zendesk-tools/command'
12
+ require 'zendesk-tools/clean_suspended'
13
+ require 'zendesk-tools/upload_files_to_ticket'
14
+ require 'zendesk-tools/recover_suspended'
15
+
16
+ module ZendeskTools
17
+ CONFIG_FILE = Pathname.new(File.expand_path("~/.zendesk-tools.json"))
18
+
19
+ def self.config
20
+ @config ||= (
21
+ if CONFIG_FILE.exist?
22
+ JSON.parse(CONFIG_FILE.read)
23
+ else
24
+ raise "Sorry, could not find JSON config in #{CONFIG_FILE}"
25
+ end
26
+ )
27
+ end
28
+
29
+ def self.show_config
30
+ pp config
31
+ end
32
+
33
+ def self.client
34
+ @client ||= (ZendeskAPI::Client.new do |c|
35
+ # Mandatory:
36
+
37
+ c.url = config['url'] || "https://finn.zendesk.com/api/v2"
38
+ c.username = config.fetch('username')
39
+ c.token = config.fetch('token')
40
+
41
+ # Optional:
42
+
43
+ if %w[debug trace].include? config['log_level']
44
+ c.logger = Loggable.logger_for("ZendeskAPI")
45
+ end
46
+
47
+ # Retry uses middleware to notify the user
48
+ # when hitting the rate limit, sleep automatically,
49
+ # then retry the request.
50
+ c.retry = true
51
+
52
+ # Changes Faraday adapter
53
+ # config.adapter = :patron
54
+
55
+ # Merged with the default client options hash
56
+ # config.client_options = { :ssl => false }
57
+ end
58
+ )
59
+ end
60
+ end
@@ -0,0 +1,40 @@
1
+ module ZendeskTools
2
+ class CleanSuspended < Command
3
+ include Loggable
4
+
5
+ DELETE_CAUSES = [
6
+ "Detected email as being from a system user",
7
+ "Detected as mail loop",
8
+ "Automated response mail"
9
+ ]
10
+
11
+ DELETE_SUBJECTS = [
12
+ "Returned mail: see transcript",
13
+ "Delivery Status Notification (Failure)",
14
+ "Undeliverable:",
15
+ "Kan ikke leveres:",
16
+ "Automatisk svar"
17
+ ]
18
+
19
+ def run
20
+ @client.suspended_tickets.each do |suspended_ticket|
21
+ if should_delete?(suspended_ticket)
22
+ log.info "Deleting: #{suspended_ticket.subject}"
23
+ suspended_ticket.destroy
24
+ else
25
+ log.info "Keeping: #{suspended_ticket.subject}"
26
+ end
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def should_delete?(suspended_ticket)
33
+ cause = suspended_ticket.cause
34
+ subject = suspended_ticket.subject
35
+
36
+ DELETE_CAUSES.any? { |delete_cause| cause.include?(delete_cause) } ||
37
+ DELETE_SUBJECTS.any? { |delete_subject| subject.include?(delete_subject) }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,15 @@
1
+ module ZendeskTools
2
+ class Command
3
+ include Loggable
4
+
5
+ def self.run(args)
6
+ new(ZendeskTools.client, args).run
7
+ end
8
+
9
+ def initialize(client, args)
10
+ @client = client
11
+ @args = args
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,33 @@
1
+ Log4r.define_levels(*Log4r::Log4rConfig::LogLevels)
2
+
3
+ module ZendeskTools
4
+ module Loggable
5
+ def self.logger_for(name)
6
+ name = self.class.name
7
+ log = Log4r::Logger.new(name)
8
+ formatter = Log4r::PatternFormatter.new(:pattern => "[%l @ %d] %c: %M")
9
+
10
+ log_file = ZendeskTools.config['log_file']
11
+ if log_file
12
+ FileUtils.mkdir_p File.dirname(log_file)
13
+
14
+ log.add Log4r::FileOutputter.new(name, :filename => log_file, :formatter => formatter)
15
+ else
16
+ outputter = Log4r::Outputter.stdout
17
+ outputter.formatter = formatter
18
+ log.add outputter
19
+ end
20
+
21
+ level = ZendeskTools.config['log_level']
22
+ if level
23
+ log.level = Log4r.const_get(level.to_s.upcase)
24
+ end
25
+
26
+ log
27
+ end
28
+
29
+ def log
30
+ @log ||= Loggable.logger_for(self.class.name)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,102 @@
1
+ require 'net/http'
2
+ require 'tmpdir'
3
+ require 'fileutils'
4
+
5
+ module ZendeskTools
6
+ class RecoverSuspended < Command
7
+ include Loggable
8
+
9
+ RECOVER_CAUSES = [
10
+ "End-user only allowed to update their own tickets"
11
+ ]
12
+
13
+ def initialize(*args)
14
+ super
15
+ @tmpdir = Dir.mktmpdir
16
+ end
17
+
18
+ def run
19
+ @client.suspended_tickets.each do |suspended_ticket|
20
+ if should_recover?(suspended_ticket)
21
+ log.info "Recovering: #{suspended_ticket.subject}"
22
+ # Logic for recovering the tickets
23
+ # Need to add logic for:
24
+ # * Grab ticket_id
25
+ ticket_id = suspended_ticket.ticket_id
26
+
27
+ # * Grab author_id
28
+ author_id = suspended_ticket.author.id
29
+
30
+ # * Grab content
31
+ content = suspended_ticket.content
32
+
33
+ # * Create new comment with correct author and content
34
+ ticket = @client.tickets.find(:id => ticket_id)
35
+ ticket.comment = ZendeskAPI::Ticket::Comment.new(@client, :value => content, :author_id => author_id)
36
+
37
+ # * Check for attachments and logic around that
38
+
39
+ suspended_ticket.attachments.each do |attachment|
40
+ url = attachment.fetch('content_url')
41
+ name = attachment.fetch('file_name')
42
+ path = File.join(@tmpdir, name)
43
+
44
+ log.info "downloading #{url}"
45
+
46
+ File.open(path, 'wb') { |file| download(url, file) }
47
+ ticket.comment.uploads << path
48
+ end
49
+
50
+ # * Save comment and upload it to zendesk
51
+
52
+ log.info "uploading"
53
+ ticket.save
54
+
55
+ # * delete/destroy the recovered ticket
56
+ suspended_ticket.destroy
57
+ log.info "cleaning up"
58
+ FileUtils.rm_rf @tmpdir
59
+ else
60
+ log.info "Not recovering: #{suspended_ticket.subject}"
61
+ end
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def download(url, destination)
68
+ uri = URI.parse(url)
69
+
70
+ resp = Net::HTTP.get_response(uri) do |response|
71
+ total = response.content_length
72
+ progress = 0
73
+ segment_count = 0
74
+
75
+ response.read_body do |segment|
76
+ progress += segment.length
77
+ segment_count += 1
78
+
79
+ if segment_count % 15 == 0
80
+ percent = (progress.to_f / total.to_f) * 100
81
+ print "\rDownloading #{url}: #{percent.to_i}% (#{progress} / #{total})"
82
+ $stdout.flush
83
+ segment_count = 0
84
+ end
85
+
86
+ destination.write(segment)
87
+ end
88
+ end
89
+
90
+ unless resp.kind_of?(Net::HTTPSuccess)
91
+ raise "ERROR:#{resp.code} for #{url}"
92
+ end
93
+ end
94
+
95
+ def should_recover?(suspended_ticket)
96
+ cause = suspended_ticket.cause
97
+ subject = suspended_ticket.subject
98
+
99
+ RECOVER_CAUSES.any? { |recover_cause| cause.include?(recover_cause) }
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,27 @@
1
+ # encoding: UTF-8
2
+
3
+ module ZendeskTools
4
+ class UploadFilesToTicket < Command
5
+
6
+ def run
7
+ ticket_id = @args.shift or raise ArgumentError, "sorry, jeg trenger en ticket id"
8
+ files = @args
9
+
10
+ raise ArgumentError, "trenger noen filer å laste opp" if files.empty?
11
+
12
+ ticket = @client.tickets.find(:id => ticket_id)
13
+ ticket or raise "fant ingen ticket med id #{ticket_id.inspect}"
14
+
15
+ ticket.comment = ZendeskAPI::Ticket::Comment.new(@client, :value => "Vedlegg fra #{ZendeskTools.config['username']}")
16
+
17
+ files.each do |e|
18
+ ticket.comment.uploads << e
19
+ end
20
+
21
+ print "Laster opp #{files.join ', '}..."
22
+ ticket.save
23
+ puts "ferdig."
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,3 @@
1
+ module ZendeskTools
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'zendesk-tools/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "zendesk-tools"
8
+ gem.version = ZendeskTools::VERSION
9
+ gem.authors = ["Jari Bakken", "Eivind Throndsen"]
10
+ gem.email = ["jari@finn.no", "eivind.throndsen@finn.no"]
11
+ gem.description = %q{Tools for FINNs ZenDesk}
12
+ gem.summary = %q{Tools for FINNs ZenDesk}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "zendesk_api", "~> 1.3.0"
21
+ gem.add_dependency "json"
22
+ gem.add_dependency "rake"
23
+ gem.add_dependency "geminabox"
24
+ gem.add_dependency "log4r"
25
+ gem.add_development_dependency "pry"
26
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zendesk-tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Jari Bakken
8
+ - Eivind Throndsen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-06-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: zendesk_api
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: 1.3.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: 1.3.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: json
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: geminabox
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: log4r
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: pry
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ description: Tools for FINNs ZenDesk
99
+ email:
100
+ - jari@finn.no
101
+ - eivind.throndsen@finn.no
102
+ executables:
103
+ - zendesk-tools
104
+ extensions: []
105
+ extra_rdoc_files: []
106
+ files:
107
+ - .gitattributes
108
+ - .gitignore
109
+ - Gemfile
110
+ - LICENSE.txt
111
+ - README.md
112
+ - Rakefile
113
+ - bin/zendesk-tools
114
+ - lib/zendesk-tools.rb
115
+ - lib/zendesk-tools/clean_suspended.rb
116
+ - lib/zendesk-tools/command.rb
117
+ - lib/zendesk-tools/loggable.rb
118
+ - lib/zendesk-tools/recover_suspended.rb
119
+ - lib/zendesk-tools/upload_files_to_ticket.rb
120
+ - lib/zendesk-tools/version.rb
121
+ - zendesk-tools.gemspec
122
+ homepage: ''
123
+ licenses: []
124
+ metadata: {}
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.0.14
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Tools for FINNs ZenDesk
145
+ test_files: []