Project

General

Profile

Feature #3003 » create_users_from_emails_patch.patch

Marius Hächler, 2009-04-24 15:11

View differences:

app/controllers/settings_controller.rb (working copy)
40 40
    @options[:user_format] = User::USER_FORMATS.keys.collect {|f| [User.current.name(f), f.to_s] }
41 41
    @deliveries = ActionMailer::Base.perform_deliveries
42 42

  
43
    @users = User.active.find(:all, :order => :login)
44
    @roles = Role.find(:all, :order => :name)
45

  
43 46
    @guessed_host_and_path = request.host_with_port.dup
44 47
    @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank?
45 48
  end
app/models/mail_handler.rb (working copy)
41 41
  def receive(email)
42 42
    @email = email
43 43
    @user = User.active.find_by_mail(email.from.to_a.first.to_s.strip)
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
48
      return false
44
    unless @user # create user
45
      if Setting.mail_handler_create_users_from_incoming_mails.to_i != 0 # creates a user and assigns him to a project
46
        @user = create_user(email)
47
        return false unless @user
48
        return false unless create_role(@user)
49
      elsif Setting.mail_handler_assign_unknown_addresses_to_user.to_i != 0 # use default users, needs :add_issue right on project
50
        unless @user = User.find_by_id(Setting.mail_handler_assign_unknown_addresses_to_user.to_i)
51
          logger.info "MailHandler: could not find User with id [#{Setting.mail_handler_assign_unknown_addresses_to_user.to_i}] to assign sender #{email.from.first}" if logger && loggger.info
52
          return false
53
        end
54
      else
55
        # unknown user and no values specified to handle unknown mails
56
        logger.info "MailHandler: email submitted by unknown user [#{email.from.first}] (change Settings in incoming E-Mail tab for default behaviour)" if logger && logger.info
57
        return false
58
      end
49 59
    end
50 60
    User.current = @user
51 61
    dispatch
52 62
  end
53
  
63

  
64

  
65
  protected
66
  def target_project
67
    # TODO: other ways to specify project:
68
    # * parse the email To field
69
    # * specific project (eg. Setting.mail_handler_target_project)
70
    target = Project.find_by_identifier(get_keyword(:project))
71
    raise MissingInformation.new('Unable to determine target project') if target.nil?
72
    target
73
  end
74

  
75
  # creates a user from email address and sets the status depending on the configured actions
76
  def create_user(email)
77
    new_user = User.new
78
    new_user.mail = email.from.first.to_s
79
    new_user.admin = false
80
    email_user_name = email.from.first.to_s.split('@').first
81
    new_user.login = if !User.find_by_login(email_user_name) # set login to the email address without domain or if it exists to the full email
82
      email_user_name
83
    else
84
      email.from.first.to_s
85
    end
86
    new_user.status = User::STATUS_REGISTERED
87
    new_user.firstname = email_user_name.split('.').first
88
    new_user.lastname = email_user_name.split('.').last
89
    password = Token.generate_token_value(8)
90
    new_user.password = password
91
    new_user.password_confirmation = password
92

  
93
    case Setting.mail_handler_create_users_from_incoming_mails
94
    when '1' || '2'
95
      token = Token.new(:user => new_user, :action => "register")
96
      Mailer.deliver_register(token) if new_user.save and token.save
97
      Mailer.deliver_account_information(new_user, password)
98
    when '3'
99
      new_user.status = User::STATUS_ACTIVE
100
      new_user.last_login_on = Time.now
101
      if new_user.save
102
        Mailer.deliver_account_information(new_user, password, :notice_account_register_done)
103
      else
104
        logger.info "could not create user #{new_user}" if logger and logger.info
105
        return false
106
      end
107
    else
108
      Mailer.deliver_account_activation_request(new_user)
109
      Mailer.deliver_account_information(new_user, password, :notice_account_pending)
110
    end
111
    return new_user
112
  end
113

  
114
  # creates a member on the target_project for the given user with the configured role
115
  def create_role(user)
116
    # Roles need right for add_issue
117
    if Setting.mail_handler_role_to_add_users_to_project.to_i != 0
118
      if Role.find_by_id(Setting.mail_handler_role_to_add_users_to_project.to_i)
119
        member = Member.new(
120
          :user_id => user.id,
121
          :project_id => self.target_project.id,
122
          :role_id => Setting.mail_handler_role_to_add_users_to_project.to_i
123
        )
124
        unless member.save
125
          logger.info "could not create Role for user #{user.login} and project #{self.target_project.name}" if logger and logger.info
126
          return false
127
        end
128
      else
129
        logger.info "could not assing #{user} to #{self.target_project.name}, missing Role id: #{Setting.mail_handler_role_to_add_users_to_project}" if logger and logger.info
130
        return false
131
      end
132
    end
133
    return true
134
  end
135

  
54 136
  private
55 137

  
56 138
  MESSAGE_ID_RE = %r{^<redmine\.([a-z0-9_]+)\-(\d+)\.\d+@}
......
94 176
    priority = (get_keyword(:priority) && Enumeration.find_by_opt_and_name('IPRI', get_keyword(:priority)))
95 177
    status =  (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
96 178

  
97
    # check permission
179
    # check permissions
98 180
    raise UnauthorizedAction unless user.allowed_to?(:add_issues, project)
99 181
    issue = Issue.new(:author => user, :project => project, :tracker => tracker, :category => category, :priority => priority)
100 182
    # check workflow
......
118 200
    issue
119 201
  end
120 202
  
121
  def target_project
122
    # TODO: other ways to specify project:
123
    # * parse the email To field
124
    # * specific project (eg. Setting.mail_handler_target_project)
125
    target = Project.find_by_identifier(get_keyword(:project))
126
    raise MissingInformation.new('Unable to determine target project') if target.nil?
127
    target
128
  end
129
  
130 203
  # Adds a note to an existing issue
131 204
  def receive_issue_reply(issue_id)
132 205
    status =  (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
......
164 237
      message = message.root
165 238
      if user.allowed_to?(:add_messages, message.project) && !message.locked?
166 239
        reply = Message.new(:subject => email.subject.gsub(%r{^.*msg\d+\]}, '').strip,
167
                            :content => plain_text_body)
240
          :content => plain_text_body)
168 241
        reply.author = user
169 242
        reply.board = message.board
170 243
        message.children << reply
......
180 253
    if email.has_attachments?
181 254
      email.attachments.each do |attachment|
182 255
        Attachment.create(:container => obj,
183
                          :file => attachment,
184
                          :author => user,
185
                          :content_type => attachment.content_type)
256
          :file => attachment,
257
          :author => user,
258
          :content_type => attachment.content_type)
186 259
      end
187 260
    end
188 261
  end
app/models/mailer.rb (working copy)
158 158
  # Example:
159 159
  #   account_information(user, password) => tmail object
160 160
  #   Mailer.deliver_account_information(user, password) => sends account information to the user
161
  def account_information(user, password)
161
  def account_information(user, password, information = '')
162 162
    set_language_if_valid user.language
163 163
    recipients user.mail
164 164
    subject l(:mail_subject_register, Setting.app_title)
165 165
    body :user => user,
166 166
         :password => password,
167
         :information => information,
167 168
         :login_url => url_for(:controller => 'account', :action => 'login')
168 169
  end
169 170

  
app/models/token.rb (working copy)
35 35
  end
36 36
  
37 37
private
38
  def self.generate_token_value
38
  def self.generate_token_value(length = 40)
39 39
    chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
40 40
    token_value = ''
41
    40.times { |i| token_value << chars[rand(chars.size-1)] }
41
    length.times { |i| token_value << chars[rand(chars.size-1)] }
42 42
    token_value
43 43
  end
44 44
end
app/views/mailer/account_information.text.html.rhtml (working copy)
1 1
<% if @user.auth_source %>
2
<p><%= l(:mail_body_account_information_external, @user.auth_source.name) %></p>
2
  <p><%= l(:mail_body_account_information_external, @user.auth_source.name) %></p>
3 3
<% else %>
4
<p><%= l(:mail_body_account_information) %>:</p>
5
<ul>
4
  <p><%= l(:mail_body_account_information) %>:</p>
5
  <ul>
6 6
    <li><%= l(:field_login) %>: <%= @user.login %></li>
7 7
    <li><%= l(:field_password) %>: <%= @password %></li>
8
</ul>
8
  </ul>
9 9
<% end %>
10 10

  
11
<% if @information -%>
12
  <p><%= l(@information) %></p>
13
<% end -%>
14

  
11 15
<p><%= l(:label_login) %>: <%= auto_link(@login_url) %></p>
app/views/mailer/account_information.text.plain.rhtml (working copy)
3 3
* <%= l(:field_login) %>: <%= @user.login %>
4 4
* <%= l(:field_password) %>: <%= @password %>
5 5
<% end %>
6
<% if @information -%>
7
  <%= l(@information) %>
8
<% end -%>
6 9
<%= l(:label_login) %>: <%= @login_url %>
app/views/settings/_mail_handler.rhtml (working copy)
1 1
<% form_tag({:action => 'edit', :tab => 'mail_handler'}) do %>
2 2

  
3
<div class="box tabular settings">
4
<p><label><%= l(:setting_mail_handler_api_enabled) %></label>
5
<%= check_box_tag 'settings[mail_handler_api_enabled]', 1, Setting.mail_handler_api_enabled?,
6
                  :onclick => "if (this.checked) { Form.Element.enable('settings_mail_handler_api_key'); } else { Form.Element.disable('settings_mail_handler_api_key'); }" %>
7
<%= hidden_field_tag 'settings[mail_handler_api_enabled]', 0 %></p>
3
  <div class="box tabular settings">
4
    <p><label><%= l(:setting_mail_handler_api_enabled) %></label>
5
      <%= check_box_tag 'settings[mail_handler_api_enabled]', 1, Setting.mail_handler_api_enabled?,
6
        :onclick => "if (this.checked) { Form.Element.enable('settings_mail_handler_api_key'); } else { Form.Element.disable('settings_mail_handler_api_key'); }" %>
7
      <%= hidden_field_tag 'settings[mail_handler_api_enabled]', 0 %></p>
8 8

  
9
<p><label><%= l(:setting_mail_handler_api_key) %></label>
10
<%= text_field_tag 'settings[mail_handler_api_key]', Setting.mail_handler_api_key, 
11
                                                     :size => 30,
12
                                                     :id => 'settings_mail_handler_api_key',
13
                                                     :disabled => !Setting.mail_handler_api_enabled? %>
14
<%= link_to_function l(:label_generate_key), "if ($('settings_mail_handler_api_key').disabled == false) { $('settings_mail_handler_api_key').value = randomKey(20) }" %></p>
15
</div>
9
    <p><label><%= l(:setting_mail_handler_api_key) %></label>
10
      <%= text_field_tag 'settings[mail_handler_api_key]', Setting.mail_handler_api_key,
11
        :size => 30,
12
        :id => 'settings_mail_handler_api_key',
13
        :disabled => !Setting.mail_handler_api_enabled? %>
14
      <%= link_to_function l(:label_generate_key), "if ($('settings_mail_handler_api_key').disabled == false) { $('settings_mail_handler_api_key').value = randomKey(20) }" %></p>
16 15

  
17
<%= submit_tag l(:button_save) %>
16
    <p>
17
      <label><%= l(:setting_mail_handler_create_users_from_incoming_mails) %></label>
18
      <%= select_tag 'settings[mail_handler_create_users_from_incoming_mails]',
19
        options_for_select( [[l(:label_disabled), "0"],
20
          [l(:label_registration_activation_by_email), "1"],
21
          [l(:label_registration_manual_activation), "2"],
22
          [l(:label_registration_automatic_activation), "3"]
23
        ], Setting.mail_handler_create_users_from_incoming_mails ),
24
        :onChange => "if (this.options[this.selectedIndex].value == \"0\") { Form.Element.enable('settings_mail_handler_assign_unknown_addresses_to_user'); } else { Form.Element.disable('settings_mail_handler_assign_unknown_addresses_to_user'); }"
25
    %>
26
    </p>
27

  
28
    <p>
29
      <label><%= l(:setting_mail_handler_role_to_add_users_to_project) %></label>
30
      <%= select(:settings, :mail_handler_role_to_add_users_to_project, @roles.collect {|p| [ p.name, p.id ] },
31
        { :include_blank => true, :selected => Setting.mail_handler_role_to_add_users_to_project.to_i }
32
      ) %>
33
    </p>
34

  
35
  
36
    <p>
37
      <label><%= l(:setting_mail_handler_assign_unknown_addresses_to_user) %></label>
38
      <%= select(:settings, :mail_handler_assign_unknown_addresses_to_user, @users.collect {|p| [ p.login, p.id ] },
39
        { :include_blank => true, :selected => Setting.mail_handler_assign_unknown_addresses_to_user.to_i },
40
        { :disabled => Setting.mail_handler_create_users_from_incoming_mails.to_i == 0}
41
      ) %>
42
    </p>
43

  
44
  </div>
45

  
46
  <%= submit_tag l(:button_save) %>
18 47
<% end %>
config/locales/de.yml (working copy)
304 304
  setting_enabled_scm: Aktivierte Versionskontrollsysteme
305 305
  setting_mail_handler_api_enabled: Abruf eingehender E-Mails aktivieren
306 306
  setting_mail_handler_api_key: API-Schlüssel
307
  setting_mail_handler_create_users_from_incoming_mails: Erstelle Benutzer aus eingehenden E-Mails
308
  setting_mail_handler_assign_unknown_addresses_to_user: Unbekannte Absender folgendem Benutzer zuordnen
309
  setting_mail_handler_role_to_add_users_to_project: Rolle für neue Benutzer
307 310
  setting_sequential_project_identifiers: Fortlaufende Projektkennungen generieren
308 311
  setting_gravatar_enabled: Gravatar Benutzerbilder benutzen
309 312
  setting_diff_max_lines_displayed: Maximale Anzahl anzuzeigender Diff-Zeilen
config/locales/en.yml (working copy)
279 279
  setting_enabled_scm: Enabled SCM
280 280
  setting_mail_handler_api_enabled: Enable WS for incoming emails
281 281
  setting_mail_handler_api_key: API key
282
  setting_mail_handler_create_users_from_incoming_mails: Create users from incoming E-Mails
283
  setting_mail_handler_assign_unknown_addresses_to_user: Assign Unknown addresses to the following User
284
  setting_mail_handler_role_to_add_users_to_project: Role for new Users
282 285
  setting_sequential_project_identifiers: Generate sequential project identifiers
283 286
  setting_gravatar_enabled: Use Gravatar user icons
284 287
  setting_diff_max_lines_displayed: Max number of diff lines displayed
config/settings.yml (working copy)
117 117
mail_handler_api_enabled:
118 118
  default: 0
119 119
mail_handler_api_key:
120
  default: 
120
  default:
121
mail_handler_create_users_from_incoming_mails:
122
  default: 0
123
mail_handler_assign_unknown_addresses_to_user:
124
  default: 0
125
mail_handler_role_to_add_users_to_project:
126
  default: 0
121 127
issue_list_default_columns:
122 128
  serialized: true
123 129
  default: 
test/unit/mail_handler_test.rb (working copy)
32 32
                   :custom_fields,
33 33
                   :custom_fields_trackers,
34 34
                   :boards,
35
                   :messages
35
                   :messages,
36
                   :settings
36 37
  
37 38
  FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
38 39
  
......
196 197
    assert_equal 'This is a html-only email.', issue.description
197 198
  end
198 199

  
200
  def test_should_create_new_user_and_assign_to_project
201
    issue = submit_email('ticket_with_new_user.eml')
202
    assert issue.is_a?(Issue)
203
    assert !issue.new_record?
204
    assert_equal issue.subject, 'New ticker from new user'
205
    assert_equal 'onlinestore', issue.project.name.downcase
206
    assert_equal 'jjins', issue.author.login
207
    assert_equal 'jjins@somenet.foo', issue.author.mail
208
    creator = User.find_by_login('jjins')
209
    assert_not_nil creator
210
    member = Member.find(:first, :conditions => {:project_id => issue.project.id, :user_id => creator.id})
211
    assert_not_nil member
212
    assert_equal 'Reporter', member.role.name
213
  end
214

  
199 215
  private
200 216
  
201 217
  def submit_email(filename, options={})
(3-3/4)