##// END OF EJS Templates
Updates rdm-mailhandler.rb help....
Jean-Philippe Lang -
r14306:54952a2b2518
parent child
Show More
@@ -1,183 +1,196
1 1 #!/usr/bin/env ruby
2 2 # Redmine - project management software
3 3 # Copyright (C) 2006-2015 Jean-Philippe Lang
4 4 #
5 5 # This program is free software; you can redistribute it and/or
6 6 # modify it under the terms of the GNU General Public License
7 7 # as published by the Free Software Foundation; either version 2
8 8 # of the License, or (at your option) any later version.
9 9 #
10 10 # This program is distributed in the hope that it will be useful,
11 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 # GNU General Public License for more details.
14 14 #
15 15 # You should have received a copy of the GNU General Public License
16 16 # along with this program; if not, write to the Free Software
17 17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 18
19 19 require 'net/http'
20 20 require 'net/https'
21 21 require 'uri'
22 22 require 'optparse'
23 23
24 24 module Net
25 25 class HTTPS < HTTP
26 26 def self.post_form(url, params, headers, options={})
27 27 request = Post.new(url.path)
28 28 request.form_data = params
29 29 request.initialize_http_header(headers)
30 30 request.basic_auth url.user, url.password if url.user
31 31 http = new(url.host, url.port)
32 32 http.use_ssl = (url.scheme == 'https')
33 33 if options[:certificate_bundle]
34 34 http.ca_file = options[:certificate_bundle]
35 35 end
36 36 if options[:no_check_certificate]
37 37 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
38 38 end
39 39 http.start {|h| h.request(request) }
40 40 end
41 41 end
42 42 end
43 43
44 44 class RedmineMailHandler
45 45 VERSION = '0.2.3'
46 46
47 47 attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :default_group, :no_permission_check,
48 48 :url, :key, :no_check_certificate, :certificate_bundle, :no_account_notice, :no_notification
49 49
50 50 def initialize
51 51 self.issue_attributes = {}
52 52
53 53 optparse = OptionParser.new do |opts|
54 54 opts.banner = "Usage: rdm-mailhandler.rb [options] --url=<Redmine URL> --key=<API key>"
55 55 opts.separator("")
56 56 opts.separator("Reads an email from standard input and forwards it to a Redmine server through a HTTP request.")
57 57 opts.separator("")
58 58 opts.separator("Required arguments:")
59 59 opts.on("-u", "--url URL", "URL of the Redmine server") {|v| self.url = v}
60 60 opts.on("-k", "--key KEY", "Redmine API key") {|v| self.key = v}
61 61 opts.separator("")
62 62 opts.separator("General options:")
63 opts.on("--no-permission-check", "disable permission checking when receiving",
64 "the email") {self.no_permission_check = '1'}
65 63 opts.on("--key-file FILE", "full path to a file that contains your Redmine",
66 64 "API key (use this option instead of --key if",
67 65 "you don't want the key to appear in the command",
68 66 "line)") {|v| read_key_from_file(v)}
69 67 opts.on("--no-check-certificate", "do not check server certificate") {self.no_check_certificate = true}
70 68 opts.on("--certificate-bundle FILE", "certificate bundle to use") {|v| self.certificate_bundle = v}
71 69 opts.on("-h", "--help", "show this help") {puts opts; exit 1}
72 70 opts.on("-v", "--verbose", "show extra information") {self.verbose = true}
73 71 opts.on("-V", "--version", "show version information and exit") {puts VERSION; exit}
74 72 opts.separator("")
75 opts.separator("User creation options:")
73 opts.separator("User and permissions options:")
76 74 opts.on("--unknown-user ACTION", "how to handle emails from an unknown user",
77 75 "ACTION can be one of the following values:",
78 76 "* ignore: email is ignored (default)",
79 77 "* accept: accept as anonymous user",
80 78 "* create: create a user account") {|v| self.unknown_user = v}
79 opts.on("--no-permission-check", "disable permission checking when receiving",
80 "the email") {self.no_permission_check = '1'}
81 81 opts.on("--default-group GROUP", "add created user to GROUP (none by default)",
82 82 "GROUP can be a comma separated list of groups") { |v| self.default_group = v}
83 83 opts.on("--no-account-notice", "don't send account information to the newly",
84 84 "created user") { |v| self.no_account_notice = '1'}
85 85 opts.on("--no-notification", "disable email notifications for the created",
86 86 "user") { |v| self.no_notification = '1'}
87 87 opts.separator("")
88 88 opts.separator("Issue attributes control options:")
89 89 opts.on("-p", "--project PROJECT", "identifier of the target project") {|v| self.issue_attributes['project'] = v}
90 90 opts.on("-s", "--status STATUS", "name of the target status") {|v| self.issue_attributes['status'] = v}
91 91 opts.on("-t", "--tracker TRACKER", "name of the target tracker") {|v| self.issue_attributes['tracker'] = v}
92 92 opts.on( "--category CATEGORY", "name of the target category") {|v| self.issue_attributes['category'] = v}
93 93 opts.on( "--priority PRIORITY", "name of the target priority") {|v| self.issue_attributes['priority'] = v}
94 94 opts.on( "--private", "create new issues as private") {|v| self.issue_attributes['is_private'] = '1'}
95 95 opts.on("-o", "--allow-override ATTRS", "allow email content to override attributes",
96 96 "specified by previous options",
97 97 "ATTRS is a comma separated list of attributes") {|v| self.allow_override = v}
98 98 opts.separator("")
99 opts.separator("Overrides:")
100 opts.separator(" ATTRS is a comma separated list of attributes among:")
101 opts.separator(" * project, tracker, status, priority, category, assigned_to, fixed_version,")
102 opts.separator(" start_date, due_date, estimated_hours, done_ratio")
103 opts.separator(" * custom fields names with underscores instead of spaces (case insensitive)")
104 opts.separator("")
105 opts.separator(" Example: --allow_override=project,priority,my_custom_field")
106 opts.separator("")
107 opts.separator(" If the --project option is not set, project is overridable by default for")
108 opts.separator(" emails that create new issues.")
109 opts.separator("")
110 opts.separator(" You can use --allow_override=all to allow all attributes to be overridable.")
111 opts.separator("")
99 112 opts.separator("Examples:")
100 opts.separator("No project specified, emails MUST contain the 'Project' keyword:")
113 opts.separator(" No project specified, emails MUST contain the 'Project' keyword:")
101 114 opts.separator(" rdm-mailhandler.rb --url http://redmine.domain.foo --key secret")
102 115 opts.separator("")
103 opts.separator("Fixed project and default tracker specified, but emails can override")
104 opts.separator("both tracker and priority attributes using keywords:")
116 opts.separator(" Fixed project and default tracker specified, but emails can override")
117 opts.separator(" both tracker and priority attributes using keywords:")
105 118 opts.separator(" rdm-mailhandler.rb --url https://domain.foo/redmine --key secret \\")
106 119 opts.separator(" --project foo \\")
107 120 opts.separator(" --tracker bug \\")
108 121 opts.separator(" --allow-override tracker,priority")
109 122
110 123 opts.summary_width = 27
111 124 end
112 125 optparse.parse!
113 126
114 127 unless url && key
115 128 puts "Some arguments are missing. Use `rdm-mailhandler.rb --help` for getting help."
116 129 exit 1
117 130 end
118 131 end
119 132
120 133 def submit(email)
121 134 uri = url.gsub(%r{/*$}, '') + '/mail_handler'
122 135
123 136 headers = { 'User-Agent' => "Redmine mail handler/#{VERSION}" }
124 137
125 138 data = { 'key' => key, 'email' => email,
126 139 'allow_override' => allow_override,
127 140 'unknown_user' => unknown_user,
128 141 'default_group' => default_group,
129 142 'no_account_notice' => no_account_notice,
130 143 'no_notification' => no_notification,
131 144 'no_permission_check' => no_permission_check}
132 145 issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value }
133 146
134 147 debug "Posting to #{uri}..."
135 148 begin
136 149 response = Net::HTTPS.post_form(URI.parse(uri), data, headers, :no_check_certificate => no_check_certificate, :certificate_bundle => certificate_bundle)
137 150 rescue SystemCallError, IOError => e # connection refused, etc.
138 151 warn "An error occured while contacting your Redmine server: #{e.message}"
139 152 return 75 # temporary failure
140 153 end
141 154 debug "Response received: #{response.code}"
142 155
143 156 case response.code.to_i
144 157 when 403
145 158 warn "Request was denied by your Redmine server. " +
146 159 "Make sure that 'WS for incoming emails' is enabled in application settings and that you provided the correct API key."
147 160 return 77
148 161 when 422
149 162 warn "Request was denied by your Redmine server. " +
150 163 "Possible reasons: email is sent from an invalid email address or is missing some information."
151 164 return 77
152 165 when 400..499
153 166 warn "Request was denied by your Redmine server (#{response.code})."
154 167 return 77
155 168 when 500..599
156 169 warn "Failed to contact your Redmine server (#{response.code})."
157 170 return 75
158 171 when 201
159 172 debug "Proccessed successfully"
160 173 return 0
161 174 else
162 175 return 1
163 176 end
164 177 end
165 178
166 179 private
167 180
168 181 def debug(msg)
169 182 puts msg if verbose
170 183 end
171 184
172 185 def read_key_from_file(filename)
173 186 begin
174 187 self.key = File.read(filename).strip
175 188 rescue Exception => e
176 189 $stderr.puts "Unable to read the key from #{filename}:\n#{e.message}"
177 190 exit 1
178 191 end
179 192 end
180 193 end
181 194
182 195 handler = RedmineMailHandler.new
183 196 exit(handler.submit(STDIN.read))
General Comments 0
You need to be logged in to leave comments. Login now