Project

General

Profile

Feature #3453 » redmine-0.8-stable-r2815-accept_incoming_emails_from_unknown_users.patch

Stanislav German-Evtushenko, 2009-07-13 16:01

View differences:

test/unit/mail_handler_test.rb (working copy)
1
# redMine - project management software
2
# Copyright (C) 2006-2007  Jean-Philippe Lang
1
# Redmine - project management software
2
# Copyright (C) 2006-2009  Jean-Philippe Lang
3 3
#
4 4
# This program is free software; you can redistribute it and/or
5 5
# modify it under the terms of the GNU General Public License
......
127 127
    assert_equal 1, issue.watchers.size
128 128
  end
129 129
  
130
  def test_add_issue_by_unknown_user
131
    assert_no_difference 'User.count' do
132
      assert_equal false, submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'})
133
    end
134
  end
135
  
136
  def test_add_issue_by_anonymous_user
137
    Role.anonymous.add_permission!(:add_issues)
138
    assert_no_difference 'User.count' do
139
      issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'accept')
140
      assert issue.is_a?(Issue)
141
      assert issue.author.anonymous?
142
    end
143
  end
144
  
145
  def test_add_issue_by_created_user
146
    Setting.default_language = 'en'
147
    assert_difference 'User.count' do
148
      issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'create')
149
      assert issue.is_a?(Issue)
150
      assert issue.author.active?
151
      assert_equal 'john.doe@somenet.foo', issue.author.mail
152
      assert_equal 'John', issue.author.firstname
153
      assert_equal 'Doe', issue.author.lastname
154
    
155
      # account information
156
      email = ActionMailer::Base.deliveries.first
157
      assert_not_nil email
158
      assert email.subject.include?('account activation')
159
      login = email.body.match(/\* Login: (.*)$/)[1]
160
      password = email.body.match(/\* Password: (.*)$/)[1]
161
      assert_equal issue.author, User.try_to_login(login, password)
162
    end
163
  end
164
  
130 165
  def test_add_issue_without_from_header
131 166
    Role.anonymous.add_permission!(:add_issues)
132 167
    assert_equal false, submit_email('ticket_without_from_header.eml')
app/models/mail_handler.rb (working copy)
38 38
  end
39 39
  
40 40
  # Processes incoming emails
41
  # Returns the created object (eg. an issue, a message) or false
41 42
  def receive(email)
42 43
    @email = email
43
    @user = User.active.find(:first, :conditions => ["LOWER(mail) = ?", email.from.to_a.first.to_s.strip.downcase])
44
    unless @user
45
      # Unknown user => the email is ignored
46
      # TODO: ability to create the user's account
47
      logger.info "MailHandler: email submitted by unknown user [#{email.from.first}]" if logger && logger.info
44
    @user = User.find_by_mail(email.from.to_a.first.to_s.strip)
45
    if @user && !@user.active?
46
      logger.info  "MailHandler: ignoring email from non-active user [#{@user.login}]" if logger && logger.info
48 47
      return false
49 48
    end
49
    if @user.nil?
50
      # Email was submitted by an unknown user
51
      case @@handler_options[:unknown_user]
52
      when 'accept'
53
        @user = User.anonymous
54
      when 'create'
55
        @user = MailHandler.create_user_from_email(email)
56
        if @user
57
          logger.info "MailHandler: [#{@user.login}] account created" if logger && logger.info
58
          Mailer.deliver_account_information(@user, @user.password)
59
        else
60
          logger.error "MailHandler: could not create account for [#{email.from.first}]" if logger && logger.error
61
          return false
62
        end
63
      else
64
        # Default behaviour, emails from unknown users are ignored
65
        logger.info  "MailHandler: ignoring email from unknown user [#{email.from.first}]" if logger && logger.info
66
        return false
67
      end
68
    end
50 69
    User.current = @user
51 70
    dispatch
52 71
  end
......
197 216
    @plain_text_body.strip!
198 217
    @plain_text_body
199 218
  end
219
  
220
  # Creates a user account for the +email+ sender
221
  def self.create_user_from_email(email)
222
    addr = email.from_addrs.to_a.first
223
    if addr && !addr.spec.blank?
224
      user = User.new
225
      user.mail = addr.spec
226
      
227
      names = addr.name.blank? ? addr.spec.gsub(/@.*$/, '').split('.') : addr.name.split
228
      user.firstname = names.shift
229
      user.lastname = names.join(' ')
230
      user.lastname = '-' if user.lastname.blank?
231
      
232
      user.login = user.mail
233
      user.password = ActiveSupport::SecureRandom.hex(5)
234
      user.language = Setting.default_language
235
      user.save ? user : nil
236
    end
237
  end
200 238
end
extra/mail_handler/rdm-mailhandler.rb (working copy)
15 15
#   -k, --key                      Redmine API key
16 16
#   
17 17
# General options:
18
#       --unknown-user=ACTION      how to handle emails from an unknown user
19
#                                  ACTION can be one of the following values:
20
#                                  ignore: email is ignored (default)
21
#                                  accept: accept as anonymous user
22
#                                  create: create a user account
18 23
#   -h, --help                     show this help
19 24
#   -v, --verbose                  show extra information
20 25
#   -V, --version                  show version information and exit
......
64 69
class RedmineMailHandler
65 70
  VERSION = '0.1'
66 71
  
67
  attr_accessor :verbose, :issue_attributes, :allow_override, :url, :key
72
  attr_accessor :verbose, :issue_attributes, :allow_override, :uknown_user, :url, :key
68 73

  
69 74
  def initialize
70 75
    self.issue_attributes = {}
......
80 85
      [ '--tracker',        '-t', GetoptLong::REQUIRED_ARGUMENT],
81 86
      [ '--category',             GetoptLong::REQUIRED_ARGUMENT],
82 87
      [ '--priority',             GetoptLong::REQUIRED_ARGUMENT],
83
      [ '--allow-override', '-o', GetoptLong::REQUIRED_ARGUMENT]
88
      [ '--allow-override', '-o', GetoptLong::REQUIRED_ARGUMENT],
89
      [ '--unknown-user',         GetoptLong::REQUIRED_ARGUMENT]
84 90
    )
85 91

  
86 92
    opts.each do |opt, arg|
......
99 105
        self.issue_attributes[opt.gsub(%r{^\-\-}, '')] = arg.dup
100 106
      when '--allow-override'
101 107
        self.allow_override = arg.dup
108
      when '--unknown-user'
109
        self.unknown_user = arg.dup
102 110
      end
103 111
    end
104 112
    
......
108 116
  def submit(email)
109 117
    uri = url.gsub(%r{/*$}, '') + '/mail_handler'
110 118
    
111
    data = { 'key' => key, 'email' => email, 'allow_override' => allow_override }
119
    data = { 'key' => key, 'email' => email, 
120
                           'allow_override' => allow_override,
121
                           'unknown_user' => unknown_user }
112 122
    issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value }
113 123
             
114 124
    debug "Posting to #{uri}..."
lib/tasks/email.rake (working copy)
21 21
    desc <<-END_DESC
22 22
Read an email from standard input.
23 23

  
24
General options:
25
  unknown_user=ACTION      how to handle emails from an unknown user
26
                           ACTION can be one of the following values:
27
                           ignore: email is ignored (default)
28
                           accept: accept as anonymous user
29
                           create: create a user account
30
  
24 31
Issue attributes control options:
25 32
  project=PROJECT          identifier of the target project
26 33
  status=STATUS            name of the target status
......
47 54
      options = { :issue => {} }
48 55
      %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] }
49 56
      options[:allow_override] = ENV['allow_override'] if ENV['allow_override']
57
      options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user']
50 58
      
51 59
      MailHandler.receive(STDIN.read, options)
52 60
    end
......
54 62
    desc <<-END_DESC
55 63
Read emails from an IMAP server.
56 64

  
65
General options:
66
  unknown_user=ACTION      how to handle emails from an unknown user
67
                           ACTION can be one of the following values:
68
                           ignore: email is ignored (default)
69
                           accept: accept as anonymous user
70
                           create: create a user account
71
  
57 72
Available IMAP options:
58 73
  host=HOST                IMAP server host (default: 127.0.0.1)
59 74
  port=PORT                IMAP server port (default: 143)
......
61 76
  username=USERNAME        IMAP account
62 77
  password=PASSWORD        IMAP password
63 78
  folder=FOLDER            IMAP folder to read (default: INBOX)
64

  
79
  
65 80
Issue attributes control options:
66 81
  project=PROJECT          identifier of the target project
67 82
  status=STATUS            name of the target status
......
107 122
      options = { :issue => {} }
108 123
      %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] }
109 124
      options[:allow_override] = ENV['allow_override'] if ENV['allow_override']
125
      options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user']
110 126

  
111 127
      Redmine::IMAP.check(imap_options, options)
112 128
    end
(1-1/2)