├── README.md ├── app └── views │ ├── projects │ └── _redmine_hipchat.html.erb │ └── settings │ └── _redmine_hipchat.html.erb ├── config └── locales │ └── en.yml ├── db └── migrate │ └── 20120917111848_add_hip_chat_token_and_room_id_to_project.rb ├── init.rb └── lib ├── hipchat_hooks.rb ├── hipchat_view_hooks.rb └── project_patch.rb /README.md: -------------------------------------------------------------------------------- 1 | HipChat Plugin for Redmine 2 | ========================== 3 | 4 | This plugin sends messages to your HipChat room when issues are created or updated. 5 | 6 | Setup 7 | ----- 8 | 9 | 1. Install this plugin following the standard Redmine [plugin installation guide](http://www.redmine.org/wiki/redmine/Plugins). 10 | 1. In Redmine, go to the Plugin page in the Adminstration area. 11 | 1. Select 'Configure' next to the HipChat plugin and enter the required details. 12 | -------------------------------------------------------------------------------- /app/views/projects/_redmine_hipchat.html.erb: -------------------------------------------------------------------------------- 1 |

2 | <%= form.text_field :hipchat_auth_token %> 3 | A token from your API tokens page. Leave empty to use <%= link_to 'global settings', plugin_settings_path(:redmine_hipchat) %>. 4 |

5 | 6 |

7 | <%= form.text_field :hipchat_room_name %> 8 | Target room's ID or name. Leave empty to use <%= link_to 'global settings', plugin_settings_path(:redmine_hipchat) %>. 9 |

10 | 11 |

12 | <%= form.check_box :hipchat_notify %> 13 | Notify room members? Will trigger sound/popup based on user preferences. 14 |

15 | -------------------------------------------------------------------------------- /app/views/settings/_redmine_hipchat.html.erb: -------------------------------------------------------------------------------- 1 |

2 | <%= content_tag(:label, l(:hipchat_settings_label_auth_token)) %> 3 | <%= text_field_tag 'settings[auth_token]', @settings[:auth_token] %> 4 | A token from your API tokens page. 5 |

6 | 7 |

8 | <%= content_tag(:label, l(:hipchat_settings_label_room_id)) %> 9 | <%= text_field_tag 'settings[room_id]', @settings[:room_id] %> 10 | Target room's ID or name. 11 |

12 | 13 |

14 | <%= content_tag(:label, l(:hipchat_settings_label_notify)) %> 15 | <%= check_box_tag 'settings[notify]', 1, @settings[:notify] %> 16 | Notify room members? Will trigger sound/popup based on user preferences. 17 |

18 | 19 |

20 | <%= content_tag(:label, l(:hipchat_settings_label_projects)) %> 21 | <%= select_tag 'settings[projects][]', project_tree_options_for_select(Project.active, :selected => Project.where(:id => @settings[:projects])), :multiple => true, :size => Project.active.size %> 22 |

23 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | hipchat_settings_header: HipChat Plugin Configuration 3 | hipchat_settings_label_room_id: Room ID 4 | hipchat_settings_label_auth_token: Room token 5 | hipchat_settings_label_notify: Notify 6 | hipchat_settings_label_projects: Projects 7 | field_hipchat_auth_token: HipChat Room token 8 | field_hipchat_room_name: HipChat Room ID 9 | field_hipchat_notify: HipChat notify 10 | -------------------------------------------------------------------------------- /db/migrate/20120917111848_add_hip_chat_token_and_room_id_to_project.rb: -------------------------------------------------------------------------------- 1 | class AddHipChatTokenAndRoomIdToProject < ActiveRecord::Migration 2 | def change 3 | add_column :projects, :hipchat_auth_token, :string, :default => "", :null => false 4 | add_column :projects, :hipchat_room_name, :string, :default => "", :null => false 5 | add_column :projects, :hipchat_notify, :boolean, :default => false, :null => false 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /init.rb: -------------------------------------------------------------------------------- 1 | Redmine::Plugin.register :redmine_hipchat do 2 | name 'HipChat' 3 | author 'HipChat, Inc.' 4 | description 'Sends notifications to a HipChat room.' 5 | version '2.0.0' 6 | url 'https://github.com/hipchat/redmine_hipchat' 7 | author_url 'https://www.hipchat.com/' 8 | 9 | Rails.configuration.to_prepare do 10 | require_dependency 'hipchat_hooks' 11 | require_dependency 'hipchat_view_hooks' 12 | require_dependency 'project_patch' 13 | Project.send(:include, RedmineHipchat::Patches::ProjectPatch) 14 | end 15 | 16 | settings :partial => 'settings/redmine_hipchat', 17 | :default => { 18 | :room_id => "", 19 | :auth_token => "", 20 | } 21 | end 22 | -------------------------------------------------------------------------------- /lib/hipchat_hooks.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | class NotificationHook < Redmine::Hook::Listener 4 | 5 | def controller_issues_new_after_save(context = {}) 6 | issue = context[:issue] 7 | project = issue.project 8 | return true if !hipchat_configured?(project) 9 | 10 | author = CGI::escapeHTML(User.current.name) 11 | tracker = CGI::escapeHTML(issue.tracker.name.downcase) 12 | subject = CGI::escapeHTML(issue.subject) 13 | url = get_url(issue) 14 | text = "#{author} reported #{project.name} #{tracker} ##{issue.id}: #{subject}" 15 | 16 | data = {} 17 | data[:text] = text 18 | data[:token] = hipchat_auth_token(project) 19 | data[:room] = hipchat_room_name(project) 20 | data[:notify] = hipchat_notify(project) 21 | 22 | send_message(data) 23 | end 24 | 25 | def controller_issues_edit_after_save(context = {}) 26 | issue = context[:issue] 27 | project = issue.project 28 | return true if !hipchat_configured?(project) 29 | 30 | author = CGI::escapeHTML(User.current.name) 31 | tracker = CGI::escapeHTML(issue.tracker.name.downcase) 32 | subject = CGI::escapeHTML(issue.subject) 33 | comment = CGI::escapeHTML(context[:journal].notes) 34 | url = get_url(issue) 35 | text = "#{author} updated #{project.name} #{tracker} ##{issue.id}: #{subject}" 36 | text += ": #{truncate(comment)}" unless comment.blank? 37 | 38 | data = {} 39 | data[:text] = text 40 | data[:token] = hipchat_auth_token(project) 41 | data[:room] = hipchat_room_name(project) 42 | data[:notify] = hipchat_notify(project) 43 | 44 | send_message(data) 45 | end 46 | 47 | def controller_wiki_edit_after_save(context = {}) 48 | page = context[:page] 49 | project = page.wiki.project 50 | return true if !hipchat_configured?(project) 51 | 52 | author = CGI::escapeHTML(User.current.name) 53 | wiki = CGI::escapeHTML(page.pretty_title) 54 | project_name = CGI::escapeHTML(project.name) 55 | url = get_url(page) 56 | text = "#{author} edited #{project_name} wiki page #{wiki}" 57 | 58 | data = {} 59 | data[:text] = text 60 | data[:token] = hipchat_auth_token(project) 61 | data[:room] = hipchat_room_name(project) 62 | data[:notify] = hipchat_notify(project) 63 | 64 | send_message(data) 65 | end 66 | 67 | private 68 | 69 | def hipchat_configured?(project) 70 | if !project.hipchat_auth_token.empty? && !project.hipchat_room_name.empty? 71 | return true 72 | elsif Setting.plugin_redmine_hipchat[:projects] && 73 | Setting.plugin_redmine_hipchat[:projects].include?(project.id.to_s) && 74 | Setting.plugin_redmine_hipchat[:auth_token] && 75 | Setting.plugin_redmine_hipchat[:room_id] 76 | return true 77 | else 78 | Rails.logger.info "Not sending HipChat message - missing config" 79 | end 80 | false 81 | end 82 | 83 | def hipchat_auth_token(project) 84 | return project.hipchat_auth_token if !project.hipchat_auth_token.empty? 85 | return Setting.plugin_redmine_hipchat[:auth_token] 86 | end 87 | 88 | def hipchat_room_name(project) 89 | return project.hipchat_room_name if !project.hipchat_room_name.empty? 90 | return Setting.plugin_redmine_hipchat[:room_id] 91 | end 92 | 93 | def hipchat_notify(project) 94 | return project.hipchat_notify if !project.hipchat_auth_token.empty? && !project.hipchat_room_name.empty? 95 | Setting.plugin_redmine_hipchat[:notify] 96 | end 97 | 98 | def get_url(object) 99 | case object 100 | when Issue then "#{Setting[:protocol]}://#{Setting[:host_name]}/issues/#{object.id}" 101 | when WikiPage then "#{Setting[:protocol]}://#{Setting[:host_name]}/projects/#{object.wiki.project.identifier}/wiki/#{object.title}" 102 | else 103 | Rails.logger.info "Asked redmine_hipchat for the url of an unsupported object #{object.inspect}" 104 | end 105 | end 106 | 107 | def send_message(data) 108 | Rails.logger.info "Sending message to HipChat: #{data[:text]}" 109 | req = Net::HTTP::Post.new("/v1/rooms/message") 110 | req.set_form_data({ 111 | :auth_token => data[:token], 112 | :room_id => data[:room], 113 | :notify => data[:notify] ? 1 : 0, 114 | :from => 'Redmine', 115 | :message => data[:text] 116 | }) 117 | req["Content-Type"] = 'application/x-www-form-urlencoded' 118 | 119 | http = Net::HTTP.new("api.hipchat.com", 443) 120 | http.use_ssl = true 121 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE 122 | begin 123 | http.start do |connection| 124 | connection.request(req) 125 | end 126 | rescue Net::HTTPBadResponse => e 127 | Rails.logger.error "Error hitting HipChat API: #{e}" 128 | end 129 | end 130 | 131 | def truncate(text, length = 20, end_string = '…') 132 | return unless text 133 | words = text.split() 134 | words[0..(length-1)].join(' ') + (words.length > length ? end_string : '') 135 | end 136 | end 137 | -------------------------------------------------------------------------------- /lib/hipchat_view_hooks.rb: -------------------------------------------------------------------------------- 1 | class NotificationViewHook < Redmine::Hook::ViewListener 2 | render_on(:view_projects_form, :partial => 'projects/redmine_hipchat', :layout => false) 3 | end 4 | -------------------------------------------------------------------------------- /lib/project_patch.rb: -------------------------------------------------------------------------------- 1 | module RedmineHipchat 2 | module Patches 3 | module ProjectPatch 4 | def self.included(base) 5 | base.class_eval do 6 | safe_attributes 'hipchat_auth_token', 'hipchat_room_name', 'hipchat_notify' 7 | end 8 | end 9 | end 10 | end 11 | end 12 | --------------------------------------------------------------------------------