Project

General

Profile

Patch #1616 » feature_277_mailing_list_forum_integration.diff

Joshua Hoover, 2008-07-10 02:37

View differences:

test/unit/mail_handler_test.rb (working copy)
26 26
                   :trackers,
27 27
                   :projects_trackers,
28 28
                   :enumerations,
29
                   :issue_categories
29
                   :issue_categories,
30
                   :boards
30 31
  
31 32
  FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
32 33
  
......
97 98
    assert_equal Issue.find(2), journal.journalized
98 99
    assert_equal 'This is reply', journal.notes
99 100
  end
101
  
102
  def test_add_forum_message
103
    # This email subject contains: [eCookbook - Discussion] A new message on a forum
104
    message = submit_email('message_on_given_project.eml')
105
    assert message.is_a?(Message)
106
    assert !message.new_record?
107
    message.reload
108
    assert_equal 'A new message on a forum', message.subject
109
    assert_equal User.find_by_login('jsmith'), message.author
110
    assert_equal Board.find(2), message.board
111
    assert message.content.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
112
  end
113
  
114
  def test_add_forum_message_reply
115
    # This email subject contains: Re: [eCookbook - Help] First post
116
    message = submit_email('message_reply.eml')
117
    assert message.is_a?(Message)
118
    assert !message.new_record?
119
    message.reload
120
    assert_equal 'Re: First post', message.subject
121
    assert_equal User.find_by_login('jsmith'), message.author
122
    assert_equal Board.find(1), message.board
123
    assert_equal Message.find(1).id, message.parent_id
124
    assert message.content.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
125
  end
126
  
127
  def test_reject_invalid_message_project
128
    # This email subject contains: [Bad Project Name - Discussion]
129
    message = submit_email('message_invalid_project.eml')
130
    assert !message
131
  end
132
  
133
  def test_reject_invalid_message_board
134
    # This email subject contains: [eCookbook - Invalid Board Name]
135
    message = submit_email('message_invalid_board.eml')
136
    assert !message
137
  end
138
  
139
  def test_reject_invalid_user_email
140
    # This email is from: not_a_valid_user_email@somenet.foo
141
    message = submit_email('message_invalid_user_email.eml')
142
    assert !message
143
  end
100 144

  
145
  def test_reject_unsupported_email
146
    # This email is from a valid user but has no content for an issue or message
147
    message = submit_email('unsupported_email.eml')
148
    assert !message
149
  end
150
  
101 151
  private
102 152
  
103 153
  def submit_email(filename, options={})
app/models/mail_handler.rb (working copy)
51 51
  private
52 52

  
53 53
  ISSUE_REPLY_SUBJECT_RE = %r{\[[^\]]+#(\d+)\]}
54
  FORUM_MESSAGE_SUBJECT = %r{(\[.*)(#.*\])}
55
  FORUM_MESSAGE_SUBJECT_RE = %r{re: }i
56
  FORUM_MESSAGE_SUBJECT_SPLIT = %r{(\[)(.*)( - )(.*)(\])}
54 57
  
55 58
  def dispatch
56 59
    if m = email.subject.match(ISSUE_REPLY_SUBJECT_RE)
57 60
      receive_issue_update(m[1].to_i)
61
    elsif !email.subject.match(FORUM_MESSAGE_SUBJECT) && email.subject.match(/\[/)
62
      if email.subject.match(FORUM_MESSAGE_SUBJECT_RE)
63
        receive_forum_message_reply
64
      else
65
        receive_forum_message
66
      end
58 67
    else
59 68
      receive_issue
60 69
    end
......
89 98
    issue
90 99
  end
91 100
  
101
  # Creates a new forum message
102
  def receive_forum_message
103
    project = target_project
104
    board = target_board
105
    # check permission
106
    raise UnauthorizedAction unless user.allowed_to?(:edit_messages, project)
107
    message = Message.new(:author => user, :board => board)
108
    message.subject = email.subject.split(FORUM_MESSAGE_SUBJECT_SPLIT)[6].strip
109
    message.content = email.plain_text_body.chomp
110
    message.save!
111
    logger.info "MailHandler: message ##{message.id} - #{message.subject} created by #{user}" if logger && logger.info
112
    #Mailer.deliver_message_posted(message) if Setting.notified_events.include?('message_posted')
113
    message
114
  end
115
   
116
  # Creates a reply to an existing forum message
117
  def receive_forum_message_reply
118
    project = target_project
119
    board = target_board
120
    # check permission
121
    raise UnauthorizedAction unless user.allowed_to?(:edit_messages, project)
122
    message = Message.new(:author => user, :board => board)
123
    subject = email.subject.split(FORUM_MESSAGE_SUBJECT_SPLIT)[6].gsub(FORUM_MESSAGE_SUBJECT_RE, "").strip
124
    message.parent_id = Message.find(:first, 
125
                                     :conditions => [ "board_id = ? AND subject = ?",
126
                                     board, subject ],
127
                                     :order => "created_on DESC").id
128
    message.subject = "Re: " + subject
129
    message.content = email.plain_text_body.chomp
130
    message.save!
131
    logger.info "MailHandler: message ##{message.id} - #{message.subject} created by #{user} in reply to message ##{message.parent_id}" if logger && logger.info
132
    #Mailer.deliver_message_posted(message) if Setting.notified_events.include?('message_posted')
133
    message
134
  end
135
  
92 136
  def target_project
93 137
    # TODO: other ways to specify project:
94 138
    # * parse the email To field
95 139
    # * specific project (eg. Setting.mail_handler_target_project)
96
    target = Project.find_by_identifier(get_keyword(:project))
140
    unless target = Project.find_by_identifier(get_keyword(:project))
141
      target = Project.find_by_name(email.subject.split(FORUM_MESSAGE_SUBJECT_SPLIT)[2])
142
    end
97 143
    raise MissingInformation.new('Unable to determine target project') if target.nil?
98 144
    target
99 145
  end
100 146
  
147
  def target_board
148
    target = Board.find_by_name(email.subject.split(FORUM_MESSAGE_SUBJECT_SPLIT)[4].strip)
149
    raise MissingInformation.new('Unable to determine target board/forum') if target.nil?
150
    target
151
  end
152
  
101 153
  # Adds a note to an existing issue
102 154
  def receive_issue_update(issue_id)
103 155
    issue = Issue.find_by_id(issue_id)
app/models/mailer.rb (working copy)
99 99
  def message_posted(message, recipients)
100 100
    redmine_headers 'Project' => message.project.identifier,
101 101
                    'Topic-Id' => (message.parent_id || message.id)
102
    from Setting.forum_mail_from unless Setting.forum_mail_from.empty?
102 103
    recipients(recipients)
103 104
    subject "[#{message.board.project.name} - #{message.board.name}] #{message.subject}"
104 105
    body :message => message,
app/views/settings/_notifications.rhtml (working copy)
5 5
<p><label><%= l(:setting_mail_from) %></label>
6 6
<%= text_field_tag 'settings[mail_from]', Setting.mail_from, :size => 60 %></p>
7 7

  
8
<p><label><%= l(:setting_forum_mail_from) %></label>
9
<%= text_field_tag 'settings[forum_mail_from]', Setting.forum_mail_from, :size => 60 %></p>
10

  
8 11
<p><label><%= l(:setting_bcc_recipients) %></label>
9 12
<%= check_box_tag 'settings[bcc_recipients]', 1, Setting.bcc_recipients? %>
10 13
<%= hidden_field_tag 'settings[bcc_recipients]', 0 %></p>
lang/en.yml (working copy)
192 192
setting_attachment_max_size: Attachment max. size
193 193
setting_issues_export_limit: Issues export limit
194 194
setting_mail_from: Emission email address
195
setting_forum_mail_from: Forum emission email address
195 196
setting_bcc_recipients: Blind carbon copy recipients (bcc)
196 197
setting_host_name: Host name
197 198
setting_text_formatting: Text formatting
config/settings.yml (working copy)
44 44
  default: '25,50,100'
45 45
mail_from:
46 46
  default: redmine@somenet.foo
47
forum_mail_from:
48
  default: ""
47 49
bcc_recipients:
48 50
  default: 1
49 51
text_formatting:
(1-1/4)