##// END OF EJS Templates
Updates rdm-mailhandler.rb help....
Jean-Philippe Lang -
r14307:1079089e7549
parent child
Show More
@@ -1,196 +1,200
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 63 opts.on("--key-file FILE", "full path to a file that contains your Redmine",
64 64 "API key (use this option instead of --key if",
65 65 "you don't want the key to appear in the command",
66 66 "line)") {|v| read_key_from_file(v)}
67 67 opts.on("--no-check-certificate", "do not check server certificate") {self.no_check_certificate = true}
68 68 opts.on("--certificate-bundle FILE", "certificate bundle to use") {|v| self.certificate_bundle = v}
69 69 opts.on("-h", "--help", "show this help") {puts opts; exit 1}
70 70 opts.on("-v", "--verbose", "show extra information") {self.verbose = true}
71 71 opts.on("-V", "--version", "show version information and exit") {puts VERSION; exit}
72 72 opts.separator("")
73 73 opts.separator("User and permissions options:")
74 74 opts.on("--unknown-user ACTION", "how to handle emails from an unknown user",
75 75 "ACTION can be one of the following values:",
76 76 "* ignore: email is ignored (default)",
77 77 "* accept: accept as anonymous user",
78 78 "* create: create a user account") {|v| self.unknown_user = v}
79 79 opts.on("--no-permission-check", "disable permission checking when receiving",
80 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 opts.on("-o", "--allow-override ATTRS", "allow email content to override attributes",
96 "specified by previous options",
97 "ATTRS is a comma separated list of attributes") {|v| self.allow_override = v}
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("")
112 opts.separator("Examples:")
113 opts.separator(" No project specified, emails MUST contain the 'Project' keyword:")
114 opts.separator(" rdm-mailhandler.rb --url http://redmine.domain.foo --key secret")
115 opts.separator("")
116 opts.separator(" Fixed project and default tracker specified, but emails can override")
117 opts.separator(" both tracker and priority attributes using keywords:")
118 opts.separator(" rdm-mailhandler.rb --url https://domain.foo/redmine --key secret \\")
119 opts.separator(" --project foo \\")
120 opts.separator(" --tracker bug \\")
121 opts.separator(" --allow-override tracker,priority")
95 opts.on("-o", "--allow-override ATTRS", "allow email content to set attributes values",
96 "ATTRS is a comma separated list of attributes",
97 "or 'all' to allow all attributes to be",
98 "overridable (see below for details)") {|v| self.allow_override = v}
99
100 opts.separator <<-END_DESC
101
102 Overrides:
103 ATTRS is a comma separated list of attributes among:
104 * project, tracker, status, priority, category, assigned_to, fixed_version,
105 start_date, due_date, estimated_hours, done_ratio
106 * custom fields names with underscores instead of spaces (case insensitive)
107
108 Example: --allow_override=project,priority,my_custom_field
109
110 If the --project option is not set, project is overridable by default for
111 emails that create new issues.
112
113 You can use --allow_override=all to allow all attributes to be overridable.
114
115 Examples:
116 No project specified, emails MUST contain the 'Project' keyword:
117 rdm-mailhandler.rb --url http://redmine.domain.foo --key secret
118
119 Fixed project and default tracker specified, but emails can override
120 both tracker and priority attributes using keywords:
121 rdm-mailhandler.rb --url https://domain.foo/redmine --key secret \\
122 --project foo \\
123 --tracker bug \\
124 --allow-override tracker,priority
125 END_DESC
122 126
123 127 opts.summary_width = 27
124 128 end
125 129 optparse.parse!
126 130
127 131 unless url && key
128 132 puts "Some arguments are missing. Use `rdm-mailhandler.rb --help` for getting help."
129 133 exit 1
130 134 end
131 135 end
132 136
133 137 def submit(email)
134 138 uri = url.gsub(%r{/*$}, '') + '/mail_handler'
135 139
136 140 headers = { 'User-Agent' => "Redmine mail handler/#{VERSION}" }
137 141
138 142 data = { 'key' => key, 'email' => email,
139 143 'allow_override' => allow_override,
140 144 'unknown_user' => unknown_user,
141 145 'default_group' => default_group,
142 146 'no_account_notice' => no_account_notice,
143 147 'no_notification' => no_notification,
144 148 'no_permission_check' => no_permission_check}
145 149 issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value }
146 150
147 151 debug "Posting to #{uri}..."
148 152 begin
149 153 response = Net::HTTPS.post_form(URI.parse(uri), data, headers, :no_check_certificate => no_check_certificate, :certificate_bundle => certificate_bundle)
150 154 rescue SystemCallError, IOError => e # connection refused, etc.
151 155 warn "An error occured while contacting your Redmine server: #{e.message}"
152 156 return 75 # temporary failure
153 157 end
154 158 debug "Response received: #{response.code}"
155 159
156 160 case response.code.to_i
157 161 when 403
158 162 warn "Request was denied by your Redmine server. " +
159 163 "Make sure that 'WS for incoming emails' is enabled in application settings and that you provided the correct API key."
160 164 return 77
161 165 when 422
162 166 warn "Request was denied by your Redmine server. " +
163 167 "Possible reasons: email is sent from an invalid email address or is missing some information."
164 168 return 77
165 169 when 400..499
166 170 warn "Request was denied by your Redmine server (#{response.code})."
167 171 return 77
168 172 when 500..599
169 173 warn "Failed to contact your Redmine server (#{response.code})."
170 174 return 75
171 175 when 201
172 176 debug "Proccessed successfully"
173 177 return 0
174 178 else
175 179 return 1
176 180 end
177 181 end
178 182
179 183 private
180 184
181 185 def debug(msg)
182 186 puts msg if verbose
183 187 end
184 188
185 189 def read_key_from_file(filename)
186 190 begin
187 191 self.key = File.read(filename).strip
188 192 rescue Exception => e
189 193 $stderr.puts "Unable to read the key from #{filename}:\n#{e.message}"
190 194 exit 1
191 195 end
192 196 end
193 197 end
194 198
195 199 handler = RedmineMailHandler.new
196 200 exit(handler.submit(STDIN.read))
General Comments 0
You need to be logged in to leave comments. Login now