From 2e15e00aceba955f37489066f22aafa197f55b6e Mon Sep 17 00:00:00 2001 From: Vincent Vanwaelscappel Date: Fri, 21 May 2021 08:32:50 +0200 Subject: [PATCH 1/1] wip #4472 @0.25 --- .gitignore | 8 + .idea/.gitignore | 8 + .idea/deployment.xml | 343 +++++++++++++ .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/redmine-slack.iml | 9 + .idea/vcs.xml | 6 + .rubocop.yml | 116 +++++ .slim-lint.yml | 3 + .travis.yml | 39 ++ Gemfile | 8 + README.md | 88 ++++ .../redmine_slack_settings_controller.rb | 46 ++ app/controllers/slash_commands_controller.rb | 47 ++ app/helpers/redmine_slack_projects_helper.rb | 17 + app/helpers/slash_commands_helper.rb | 13 + app/models/redmine_slack_notification.rb | 45 ++ app/models/redmine_slack_setting.rb | 16 + app/models/slack.rb | 464 ++++++++++++++++++ .../_issues_silent_updates.html.erb | 4 + .../_journal_silent_updates.html.erb | 3 + .../_redmine_slack_select.html.slim | 7 + .../_redmine_slack_text.html.slim | 9 + .../redmine_slack_settings/_show.html.slim | 57 +++ .../_redmine_slack_settings.html.slim | 80 +++ config/locales/en.yml | 45 ++ config/locales/fr.yml | 45 ++ config/routes.rb | 9 + ...622172451_create_redmine_slack_settings.rb | 23 + ...5645_migrate_redmine_messenger_settings.rb | 31 ++ .../20200702092644_add_color_settings.rb | 8 + ...0847_create_redmine_slack_notifications.rb | 12 + .../20200727112644_add_update_threshold.rb | 6 + .../20200818072644_add_replies_threshold.rb | 6 + docs/images/signing-secret.png | Bin 0 -> 68932 bytes docs/images/slack-token.png | Bin 0 -> 48938 bytes docs/images/slash-command.png | Bin 0 -> 77522 bytes init.rb | 39 ++ lib/redmine_slack.rb | 39 ++ lib/redmine_slack/diffy.rb | 168 +++++++ lib/redmine_slack/helpers.rb | 21 + lib/redmine_slack/hooks.rb | 61 +++ lib/redmine_slack/patches/issue_patch.rb | 214 ++++++++ .../patches/issues_controller_patch.rb | 29 ++ lib/redmine_slack/patches/journals_patch.rb | 19 + .../patches/wiki_content_patch.rb | 161 ++++++ test/integration/routing_test.rb | 11 + test/support/database-postgresql-travis.yml | 8 + test/test_helper.rb | 39 ++ test/unit/i18n_test.rb | 39 ++ test/unit/issue_test.rb | 32 ++ test/unit/project_test.rb | 40 ++ 52 files changed, 2555 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.gitignore create mode 100644 .idea/deployment.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/redmine-slack.iml create mode 100644 .idea/vcs.xml create mode 100644 .rubocop.yml create mode 100644 .slim-lint.yml create mode 100644 .travis.yml create mode 100644 Gemfile create mode 100644 README.md create mode 100644 app/controllers/redmine_slack_settings_controller.rb create mode 100644 app/controllers/slash_commands_controller.rb create mode 100644 app/helpers/redmine_slack_projects_helper.rb create mode 100644 app/helpers/slash_commands_helper.rb create mode 100644 app/models/redmine_slack_notification.rb create mode 100644 app/models/redmine_slack_setting.rb create mode 100644 app/models/slack.rb create mode 100644 app/views/redmine_slack/_issues_silent_updates.html.erb create mode 100644 app/views/redmine_slack/_journal_silent_updates.html.erb create mode 100644 app/views/redmine_slack_settings/_redmine_slack_select.html.slim create mode 100644 app/views/redmine_slack_settings/_redmine_slack_text.html.slim create mode 100644 app/views/redmine_slack_settings/_show.html.slim create mode 100644 app/views/settings/_redmine_slack_settings.html.slim create mode 100644 config/locales/en.yml create mode 100644 config/locales/fr.yml create mode 100644 config/routes.rb create mode 100644 db/migrate/20200622172451_create_redmine_slack_settings.rb create mode 100644 db/migrate/20200623165645_migrate_redmine_messenger_settings.rb create mode 100644 db/migrate/20200702092644_add_color_settings.rb create mode 100644 db/migrate/20200723160847_create_redmine_slack_notifications.rb create mode 100644 db/migrate/20200727112644_add_update_threshold.rb create mode 100644 db/migrate/20200818072644_add_replies_threshold.rb create mode 100644 docs/images/signing-secret.png create mode 100644 docs/images/slack-token.png create mode 100644 docs/images/slash-command.png create mode 100644 init.rb create mode 100644 lib/redmine_slack.rb create mode 100644 lib/redmine_slack/diffy.rb create mode 100644 lib/redmine_slack/helpers.rb create mode 100644 lib/redmine_slack/hooks.rb create mode 100644 lib/redmine_slack/patches/issue_patch.rb create mode 100644 lib/redmine_slack/patches/issues_controller_patch.rb create mode 100644 lib/redmine_slack/patches/journals_patch.rb create mode 100644 lib/redmine_slack/patches/wiki_content_patch.rb create mode 100644 test/integration/routing_test.rb create mode 100644 test/support/database-postgresql-travis.yml create mode 100644 test/test_helper.rb create mode 100644 test/unit/i18n_test.rb create mode 100644 test/unit/issue_test.rb create mode 100644 test/unit/project_test.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d572e62 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +coverage/ +.buildpath +.project +.settings/ +docs/_build +docs/_static +docs/_templates diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000..4d7d1a3 --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0a76216 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8e13544 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/redmine-slack.iml b/.idea/redmine-slack.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/redmine-slack.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..f8928f6 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,116 @@ +AllCops: + TargetRubyVersion: 2.6 + TargetRailsVersion: 5.2 + + Exclude: + - '**/vendor/**/*' + - '**/tmp/**/*' + - '**/bin/**/*' + - '**/plugins/**/*' + - '**/extra/**/*' + - '**/lib/generators/**/templates/*' + - '**/lib/tasks/**/*' + - '**/files/**/*' + - 'db/schema.rb' + +# Enable extensions + +require: + - rubocop-performance + - rubocop-rails + +# Rules for Redmine + +Lint/SendWithMixinArgument: + Enabled: false + +Style/SymbolArray: + Enabled: false + +Rails/ApplicationRecord: + Enabled: false + +Rails/CreateTableWithTimestamps: + Enabled: false + +Rails/FilePath: + Enabled: false + +Style/IfUnlessModifier: + Enabled: false + +Style/ExpandPathArguments: + Enabled: false + +Style/ClassVars: + Enabled: false + +Bundler/OrderedGems: + Enabled: false + +Rails/ReversibleMigration: + Enabled: false + +Layout/EmptyLineBetweenDefs: + AllowAdjacentOneLineDefs: true + +Layout/SpaceBeforeBlockBraces: + # "space" is used more than "no_space". + # But "no_space" is more natural in one liner. + # str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/") + Enabled: false + +# You can see results by "rubocop --only Layout/SpaceInsideBlockBraces" +Layout/SpaceInsideBlockBraces: + EnforcedStyle: no_space + SpaceBeforeBlockParameters: false + +# You can see results by "rubocop --only Layout/SpaceInsideHashLiteralBraces" +Layout/SpaceInsideHashLiteralBraces: + EnforcedStyle: no_space + +Layout/TrailingWhitespace: + AllowInHeredoc: true + +Lint/SuppressedException: + AllowComments: true + +Metrics: + Enabled: false + +Naming/AccessorMethodName: + Enabled: false + +Naming/BinaryOperatorParameterName: + Enabled: false + +Naming/PredicateName: + Enabled: false + +Rails/HelperInstanceVariable: + Enabled: false + +Style/FormatStringToken: + Enabled: false + +Style/FrozenStringLiteralComment: + Enabled: true + EnforcedStyle: always + Exclude: + - 'db/**/*.rb' + - 'Gemfile' + - 'Rakefile' + - 'config.ru' + - 'config/additional_environment.rb' + +Style/HashSyntax: + Enabled: true + EnforcedStyle: no_mixed_keys + +Style/IdenticalConditionalBranches: + Exclude: + - 'config/initializers/10-patches.rb' + - 'lib/redmine/wiki_formatting/textile/redcloth3.rb' + +Style/TrailingCommaInArrayLiteral: + Enabled: false diff --git a/.slim-lint.yml b/.slim-lint.yml new file mode 100644 index 0000000..e770df4 --- /dev/null +++ b/.slim-lint.yml @@ -0,0 +1,3 @@ +linters: + LineLength: + max: 140 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..d58d9f5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,39 @@ +language: ruby + +rvm: + - 2.4.5 + - 2.5.3 + - 2.6.6 + +env: + - REDMINE_VER=4.0-stable DB=postgresql + +sudo: true + +addons: + postgresql: "9.6" + +before_install: + - export PLUGIN_NAME=redmine_slack + - export REDMINE_GIT_REPO=git://github.com/redmine/redmine.git + - export REDMINE_PATH=$HOME/redmine + - export BUNDLE_GEMFILE=$REDMINE_PATH/Gemfile + - git clone $REDMINE_GIT_REPO $REDMINE_PATH + - cd $REDMINE_PATH + - if [[ "$REDMINE_VER" != "master" ]]; then git checkout -b $REDMINE_VER origin/$REDMINE_VER; fi + - ln -s $TRAVIS_BUILD_DIR $REDMINE_PATH/plugins/$PLUGIN_NAME + - cp $TRAVIS_BUILD_DIR/test/support/database-$DB-travis.yml $REDMINE_PATH/config/database.yml + +before_script: + - psql -c 'create database travis_ci_test;' -U postgres + - bundle exec rake db:migrate + - bundle exec rake redmine:plugins:migrate + +script: + - export SKIP_COVERAGE=1 + - if [[ "$REDMINE_VER" == "master" ]]; then bundle exec rake redmine:plugins:test:units NAME=$PLUGIN_NAME; fi + - if [[ "$REDMINE_VER" == "master" ]]; then bundle exec rake redmine:plugins:test:functionals NAME=$PLUGIN_NAME; fi + - if [[ "$REDMINE_VER" == "master" ]]; then bundle exec rake redmine:plugins:test:integration NAME=$PLUGIN_NAME; fi + - if [[ "$REDMINE_VER" != "master" ]]; then bundle exec rake redmine:plugins:test NAME=$PLUGIN_NAME RUBYOPT="-W0"; fi + - cd plugins/$PLUGIN_NAME + - bundle exec rubocop -c .rubocop.yml diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..1c52dc6 --- /dev/null +++ b/Gemfile @@ -0,0 +1,8 @@ +gem 'slim-rails' +gem 'validate_url' + +group :test do + gem 'rubocop', '~> 0.76.0', require: false + gem 'rubocop-performance', '~> 1.5.0', require: false + gem 'rubocop-rails', '~> 2.3.0', require: false +end diff --git a/README.md b/README.md new file mode 100644 index 0000000..768c49d --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +Redmine Slack +============= + +This plugin allows to send notifications from your Redmine installation to Slack. + +It's heavily inspired by [Redmine Messenger](https://github.com/AlphaNodes/redmine_messenger/) but supporting only Slack. This way, we can take advantage of a lot of rich features included on Slack. + +# Configuration + +There's a global config and a per-project config to override global values. In this configuration you can set some parameters for the integration. + + +To configure this plugin you need to get Slack Token and Slack Signing Secret. + +## Slack Signing Secret + +You get this on Basic Information tab for your app. + +![Screenshot of Signing Secret Section in Slack App config](./docs/images/signing-secret.png) + +## Slack Token + +You get this on "OAuth & Permissions" tab for your app. + +![Screenshot of Slack Token Section in Slack App config](./docs/images/slack-token.png) + +## Existing configuration parameters + +This is a list of current configuration parameters (both in global and per project): + +- Slack Token: Configure Slack token +- Slack Signing Secret: Configure Slack Signing Secret to validate requests coming from Slack +- Slack Channel: Channel to send notifications. +- Slack Verify SSL: Configure whether SSL should be validated (Leave on. This will probably be deleted in a future version) +- Auto Mentions: Configure whether to use mentions automatically in Slack. +- Default Mentions: Mentions to include by default in Slack notifications. +- Post Updates: Post issues updates to Slack. +- New Include Description: Include description in new issue. +- Updated include description: Include description in updated issue. +- Text Trim Size: Character amount used to trim notifications to Slack. +- Supress Empty Messages: Avoid sending messages without text description to Slack. +- Post Private issues: Configure whether new private issues should be posted to Slack. +- Post private notes: Configure whether updates to private issues should be posted to Slack. +- Post wiki: Configure whether new Wiki pages should be posted to Slack. +- Post wiki updates: Configure whether updates to wiki pages should be posted to Slack. + +## Configuring a new channel + +To configure a new channel, you could do one of these options: + +1) In Project -> Settings -> Redmine Slack, add channel and click save +2) In Slack channel, invoke slash command like this: `/redmine-connect project-slug` + +In order to use as described in number 2), you need to create a Slack Slash command and provide it with the following url: `/slack/slash/connect` + +This is an example on how to configure the Slash Command: + + +![Screenshot of Slack Slash Command Configuration in Slack App config](./docs/images/slash-command.png) + +## Posting Slack replies to Redmine + +This plugin is able to post the threaded replies for a notification back to Redmine. In order to do so, you need to configure a cron job like this: + +``` +0 * * * * cd /home/redmine/redmine && ./bin/rails runner Slack.post_slack_responses -e production >> log/cron_rake.log 2>&1 +``` + +You should also configure "Get Slack replies threshold" parameter in the global plugin settings to the same amount of seconds between each cron run (e.g. if cron runs once per hour, time replies threshold should be 3600). + +In order to make this work, the bot needs to be added to the channels so that it can read the messages. + +# Features + +This plugin sends Slack notifications when you update issues or wiki entries. + +# Permissions required in Slack + +The following scopes are required in order to work properly with Slack: + +- chat:write +- chat:write.public +- commands +- channels:history +- channels:read +- files:read +- user:read +- user:read.email diff --git a/app/controllers/redmine_slack_settings_controller.rb b/app/controllers/redmine_slack_settings_controller.rb new file mode 100644 index 0000000..f96ce51 --- /dev/null +++ b/app/controllers/redmine_slack_settings_controller.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# Redmine Slack Settings Controller. +class RedmineSlackSettingsController < ApplicationController + before_action :find_project_by_project_id + before_action :authorize + + def update + setting = RedmineSlackSetting.find_or_create(@project.id) + if setting.update(allowed_params) + flash[:notice] = l(:notice_successful_update) + redirect_to settings_project_path(@project, tab: 'redmine_slack') + else + flash[:error] = setting.errors.full_messages.flatten.join("\n") + respond_to do |format| + format.html {redirect_back_or_default(settings_project_path(@project, tab: 'redmine_slack'))} + format.api {render_validation_errors(setting)} + end + end + end + + private + + def allowed_params + params.require(:setting).permit :redmine_slack_token, + :redmine_slack_signing_secret, + :redmine_slack_channel, + :redmine_slack_verify_ssl, + :auto_mentions, + :default_mentions, + :post_updates, + :new_include_description, + :updated_include_description, + :text_trim_size, + :supress_empty_messages, + :post_private_issues, + :post_private_notes, + :post_wiki, + :post_wiki_updates, + :color_create_notifications, + :color_update_notifications, + :replies_threshold, + :color_close_notifications, + :update_notification_threshold + end +end diff --git a/app/controllers/slash_commands_controller.rb b/app/controllers/slash_commands_controller.rb new file mode 100644 index 0000000..540337d --- /dev/null +++ b/app/controllers/slash_commands_controller.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +# Slack commands controller. +class SlashCommandsController < ApplicationController + include SlashCommandsHelper + skip_before_action :verify_authenticity_token + + def channel_connect + signing_secret = RedmineSlack.settings[:redmine_slack_signing_secret] + data = [] + if valid_request?(request.headers, request.raw_post, signing_secret) + channel_name = params[:channel_name] + project_slug = params[:text] + data = [] + project = Project.where(['identifier = ?', project_slug]).first + unless project + # Try by id. + project = Project.where(['id = ?', project_slug]).first + unless project + data = "Project #{project_slug} not found" + end + end + if project + slack_setting = RedmineSlackSetting.find_or_create(project.id) + if slack_setting.redmine_slack_channel + previous_channel_name = slack_setting.redmine_slack_channel + if previous_channel_name != channel_name + slack_setting.redmine_slack_channel = channel_name + slack_setting.save! + data = "Project channel updated. It was previously set to #{previous_channel_name}." + else + data = "Nothing to do. Project was already set to channel #{channel_name}." + end + else + slack_setting.redmine_slack_channel = channel_name + slack_setting.save! + data = "Project channel set to #{channel_name}." + end + end + else + data = 'Invalid Request' + end + respond_to do |format| + format.html {render json: data, status: :ok, layout: nil} + end + end +end diff --git a/app/helpers/redmine_slack_projects_helper.rb b/app/helpers/redmine_slack_projects_helper.rb new file mode 100644 index 0000000..3a678ac --- /dev/null +++ b/app/helpers/redmine_slack_projects_helper.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# Project helpers module. +module RedmineSlackProjectsHelper + def project_settings_tabs + tabs = super + + if User.current.allowed_to?(:manage_redmine_slack, @project) + tabs << {name: 'redmine_slack', + action: :show, + partial: 'redmine_slack_settings/show', + label: :label_redmine_slack} + end + + tabs + end +end diff --git a/app/helpers/slash_commands_helper.rb b/app/helpers/slash_commands_helper.rb new file mode 100644 index 0000000..25389a1 --- /dev/null +++ b/app/helpers/slash_commands_helper.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Slack commands controller helper. +module SlashCommandsHelper + def valid_request?(headers, body, signing_secret) + timestamp = headers['X-Slack-Request-Timestamp'] + signature = headers['X-Slack-Signature'] + string_to_validate = "v0:#{timestamp}:#{body}" + digest = OpenSSL::Digest.new('sha256') + signed = OpenSSL::HMAC.hexdigest(digest, signing_secret, string_to_validate) + signature == "v0=#{signed}" + end +end diff --git a/app/models/redmine_slack_notification.rb b/app/models/redmine_slack_notification.rb new file mode 100644 index 0000000..0fc1659 --- /dev/null +++ b/app/models/redmine_slack_notification.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +# Slack notification model class. +class RedmineSlackNotification < ActiveRecord::Base + def self.find_or_create(entity, entity_id) + notification = RedmineSlackNotification.find_by(entity: entity, entity_id: entity_id) + unless notification + notification = RedmineSlackNotification.new + notification.entity = entity + notification.entity_id = entity_id + notification.timestamp = Time.now.to_i + end + + notification + end + + def self.find_or_create_within_timeframe(entity, entity_id, seconds) + current_timestamp = Time.now.to_i + timestamp = current_timestamp - seconds.to_i + notification = RedmineSlackNotification.find_by( + 'entity = ? AND entity_id = ? AND timestamp >= ?', + entity, + entity_id, + timestamp + ) + unless notification + notification = RedmineSlackNotification.new + notification.entity = entity + notification.entity_id = entity_id + notification.timestamp = current_timestamp + end + notification + end + + def self.find_notification_by_type_within_timeframe(entity, seconds) + current_timestamp = Time.now.to_i + timestamp = current_timestamp - seconds.to_i + notifications = RedmineSlackNotification.where( + 'entity = ? AND timestamp >= ?', + entity, + timestamp + ) + notifications + end +end diff --git a/app/models/redmine_slack_setting.rb b/app/models/redmine_slack_setting.rb new file mode 100644 index 0000000..cbd0055 --- /dev/null +++ b/app/models/redmine_slack_setting.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +# Slack settings model class. +class RedmineSlackSetting < ActiveRecord::Base + belongs_to :project + + def self.find_or_create(p_id) + setting = RedmineSlackSetting.find_by(project_id: p_id) + unless setting + setting = RedmineSlackSetting.new + setting.project_id = p_id + end + + setting + end +end diff --git a/app/models/slack.rb b/app/models/slack.rb new file mode 100644 index 0000000..f744147 --- /dev/null +++ b/app/models/slack.rb @@ -0,0 +1,464 @@ +# frozen_string_literal: true + +require 'net/http' +require 'json' + +# Slack class. +class Slack + include Redmine::I18n + + def self.markup_format(text) + text + end + + def self.trim(original_msg, project) + msg = original_msg + trim_size = Slack.textfield_for_project(project, :text_trim_size).to_i + + if trim_size.positive? + loop do + msg = msg[0..trim_size] + break unless /^.* (http[A-Za-z\.\d\/\:]*)$/.match(msg) + break if msg == original_msg + # Restore original message and try again. + msg = original_msg + trim_size += 1 + end + end + msg + end + + def self.default_url_options + {only_path: true, script_name: Redmine::Utils.relative_url_root} + end + + def self.speak(msg, channels, options, notification = nil) + url = 'https://slack.com/api/chat.postMessage' + token = RedmineSlack.settings[:redmine_slack_token] + + return if url.blank? + return if channels.blank? + return if token.blank? + + params = { + text: msg, + link_names: 1 + } + + params[:attachments] = [options[:attachment]] if options[:attachment]&.any? + + channels.each do |channel| + uri = URI(url) + params[:channel] = channel + http_options = {use_ssl: uri.scheme == 'https'} + http_options[:verify_mode] = OpenSSL::SSL::VERIFY_NONE unless RedmineSlack.setting?(:redmine_slack_verify_ssl) + + begin + req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json') + req['Authorization'] = "Bearer #{token}" + req.body = params.to_json + Net::HTTP.start(uri.hostname, uri.port, http_options) do |http| + response = http.request(req) + body = response.body + body_json = JSON.parse(body) + notification.slack_message_id = body_json['ts'] + notification.slack_channel_id = body_json['channel'] + notification.save + Rails.logger.warn(response) unless [Net::HTTPSuccess, Net::HTTPRedirection, Net::HTTPOK].include? response + end + rescue StandardError => e + Rails.logger.warn("cannot connect to #{url}") + Rails.logger.warn(e) + end + end + end + + def self.update_message(msg, channel, options, notification = nil) + url = 'https://slack.com/api/chat.update' + token = RedmineSlack.settings[:redmine_slack_token] + + return if url.blank? + return if channel.blank? + return if token.blank? + + params = { + ts: notification.slack_message_id, + text: msg, + link_names: 1 + } + + params[:attachments] = [options[:attachment]] if options[:attachment]&.any? + + uri = URI(url) + params[:channel] = channel + http_options = {use_ssl: uri.scheme == 'https'} + http_options[:verify_mode] = OpenSSL::SSL::VERIFY_NONE unless RedmineSlack.setting?(:redmine_slack_verify_ssl) + begin + req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json') + req['Authorization'] = "Bearer #{token}" + req.body = params.to_json + Net::HTTP.start(uri.hostname, uri.port, http_options) do |http| + response = http.request(req) + notification.timestamp = Time.now.to_i + notification.save + Rails.logger.warn(response) unless [Net::HTTPSuccess, Net::HTTPRedirection, Net::HTTPOK].include? response + end + rescue StandardError => e + Rails.logger.warn("cannot connect to #{url}") + Rails.logger.warn(e) + end + end + + def self.object_url(obj) + if Setting.host_name.to_s =~ %r{\A(https?\://)?(.+?)(\:(\d+))?(/.+)?\z}i + host = Regexp.last_match(2) + port = Regexp.last_match(4) + prefix = Regexp.last_match(5) + Rails.application.routes.url_for( + obj.event_url( + host: host, + protocol: Setting.protocol, + port: port, + script_name: prefix + ) + ) + else + Rails.application.routes.url_for( + obj.event_url( + host: Setting.host_name, + protocol: Setting.protocol, + script_name: '' + ) + ) + end + end + + def self.textfield_for_project(proj, config) + return if proj.blank? + + # project based + pm = RedmineSlackSetting.find_by(project_id: proj.id) + return pm.send(config) if !pm.nil? && pm.send(config).present? + + default_textfield(proj, config) + end + + def self.default_textfield(proj, config) + # parent project based + parent_field = textfield_for_project(proj.parent, config) + return parent_field if parent_field.present? + return RedmineSlack.settings[config] if RedmineSlack.settings[config].present? + + '' + end + + def self.channels_for_project(proj) + return [] if proj.blank? + + # project based + pm = RedmineSlackSetting.find_by(project_id: proj.id) + if !pm.nil? && pm.redmine_slack_channel.present? + return [] if pm.redmine_slack_channel == '-' + + return pm.redmine_slack_channel.split(',').map!(&:strip).uniq + end + default_project_channels(proj) + end + + def self.default_project_channels(proj) + # parent project based + parent_channel = channels_for_project(proj.parent) + return parent_channel if parent_channel.present? + # system based + if RedmineSlack.settings[:redmine_slack_channel].present? && + RedmineSlack.settings[:redmine_slack_channel] != '-' + return RedmineSlack.settings[:redmine_slack_channel].split(',').map!(&:strip).uniq + end + + [] + end + + def self.setting_for_project(proj, config) + return false if proj.blank? + + @setting_found = 0 + # project based + pm = RedmineSlackSetting.find_by(project_id: proj.id) + unless pm.nil? || pm.send(config).zero? + @setting_found = 1 + return false if pm.send(config) == 1 + return true if pm.send(config) == 2 + # 0 = use system based settings + end + default_project_setting(proj, config) + end + + def self.default_project_setting(proj, config) + if proj.present? && proj.parent.present? + parent_setting = setting_for_project(proj.parent, config) + return parent_setting if @setting_found == 1 + end + # system based + return true if RedmineSlack.settings[config].present? && RedmineSlack.setting?(config) + + false + end + + def self.detail_to_field(detail, project) + field_format = nil + key = nil + escape = true + + if detail.property == 'cf' + key = begin + CustomField.find(detail.prop_key).name + rescue StandardError + nil + end + title = key + field_format = begin + CustomField.find(detail.prop_key).field_format + rescue StandardError + nil + end + elsif detail.property == 'attachment' + key = 'attachment' + title = I18n.t :label_attachment + else + key = detail.prop_key.to_s.sub('_id', '') + title = if key == 'parent' + I18n.t "field_#{key}_issue" + else + I18n.t "field_#{key}" + end + end + + short = true + value = detail.value.to_s + + case key + when 'description' + short = false + value = Slack.trim(value, project) + when 'title', 'subject' + short = false + when 'tracker' + tracker = Tracker.find(detail.value) + value = tracker.to_s if tracker.present? + when 'project' + project = Project.find(detail.value) + value = project.to_s if project.present? + when 'status' + status = IssueStatus.find(detail.value) + value = status.to_s if status.present? + when 'priority' + priority = IssuePriority.find(detail.value) + value = priority.to_s if priority.present? + when 'category' + category = detail.value ? IssueCategory.find(detail.value) : '' + value = category.to_s if category.present? + when 'assigned_to' + user = detail.value ? User.find(detail.value) : '' + value = user.to_s if user.present? + when 'fixed_version' + fixed_version = detail.value ? Version.find(detail.value) : '' + value = fixed_version.to_s if fixed_version.present? + when 'attachment' + attachment = Attachment.find(detail.prop_key) + value = "<#{Slack.object_url attachment}|#{ERB::Util.html_escape(attachment.filename)}>" if attachment.present? + escape = false + when 'parent' + issue = detail.value ? Issue.find(detail.value) : '' + value = "<#{Slack.object_url issue}|#{ERB::Util.html_escape(issue)}>" if issue.present? + escape = false + end + + if detail.property == 'cf' && field_format == 'version' + version = Version.find(detail.value) + value = version.to_s if version.present? + end + + value = if value.present? + if escape + ERB::Util.html_escape(value) + else + value + end + else + '-' + end + + result = {title: title, value: value} + result[:short] = true if short + result + end + + def self.mentions(project, text) + names = [] + Slack.textfield_for_project(project, :default_mentions) + .split(',').each {|m| names.push m.strip} + names += extract_usernames(text) unless text.nil? + names.present? ? ' To: ' + names.uniq.join(', ') : nil + end + + def self.extract_usernames(text) + text = '' if text.nil? + # slack usernames may only contain lowercase letters, numbers, + # dashes, dots and underscores and must start with a letter or number. + text.scan(/@[a-z0-9][a-z0-9_\-.]*/).uniq + end + + def self.get_recent_notifications + notifications = [] + # Get notifications sent in last 24 hours. + notifications += RedmineSlackNotification.find_notification_by_type_within_timeframe('issue', 86_400) + notifications += RedmineSlackNotification.find_notification_by_type_within_timeframe('issue-note', 86_400) + notifications + end + + def self.get_notification_replies(notification) + url = 'https://slack.com/api/conversations.replies' + token = RedmineSlack.settings[:redmine_slack_token] + + return if token.blank? + + params = { + ts: notification.slack_message_id, + channel: notification.slack_channel_id + } + + uri = URI(url) + uri.query = URI.encode_www_form(params) + begin + req = Net::HTTP::Get.new(uri, 'Content-Type' => 'application/json') + req['Authorization'] = "Bearer #{token}" + http_options = {use_ssl: uri.scheme == 'https'} + http_options[:verify_mode] = OpenSSL::SSL::VERIFY_NONE unless RedmineSlack.setting?(:redmine_slack_verify_ssl) + Net::HTTP.start(uri.hostname, uri.port, http_options) do |http| + response = http.request(req) + body = response.body + body_json = JSON.parse(body) + body_json['messages'] || [] + end + rescue StandardError => e + Rails.logger.warn("cannot connect to #{url}") + Rails.logger.warn(e) + end + end + + def self.get_user_email(slack_user_id) + url = 'https://slack.com/api/users.info' + token = RedmineSlack.settings[:redmine_slack_token] + + return if token.blank? + + params = { + user: slack_user_id + } + + uri = URI(url) + uri.query = URI.encode_www_form(params) + begin + req = Net::HTTP::Get.new(uri, 'Content-Type' => 'application/json') + req['Authorization'] = "Bearer #{token}" + http_options = {use_ssl: uri.scheme == 'https'} + http_options[:verify_mode] = OpenSSL::SSL::VERIFY_NONE unless RedmineSlack.setting?(:redmine_slack_verify_ssl) + Net::HTTP.start(uri.hostname, uri.port, http_options) do |http| + response = http.request(req) + body = response.body + body_json = JSON.parse(body) + if body_json['user']['profile'].key?('email') + body_json['user']['profile']['email'] + end + end + rescue StandardError => e + Rails.logger.warn("cannot connect to #{url}") + Rails.logger.warn(e) + end + end + + def self.get_user_id(email) + return 2 if email.nil? + + email_address = EmailAddress.find_by address: email + return 2 if email_address.nil? + + email_address.user_id + end + + def self.post_reply_to_redmine(message, issue_id) + email = get_user_email(message['user']) + author_id = get_user_id(email) + journal = Journal.new + journal.journalized_type = 'Issue' + journal.journalized = Issue.find(issue_id) + journal.user_id = author_id + journal.notes = message['text'] + + if message.key? 'files' + message['files'].each do |file| + url = file['url_private'] + file_content = get_attachment(url) + attachments = [] + author = User.find(author_id) + next if file_content.nil? + + attachment = Attachment.new(:file => file_content) + attachment.container_id = issue_id + attachment.container_type = 'Issue' + attachment.author = author + attachment.filename = file['title'] + attachment.content_type = file['mimetype'] + attachment.save + journal.journalize_attachment(attachment, :added) + attachments << attachment + end + end + + journal.save + journal.journalized.save + journal + end + + def self.get_attachment(url) + token = RedmineSlack.settings[:redmine_slack_token] + + return if token.blank? + + uri = URI(url) + begin + req = Net::HTTP::Get.new(uri) + req['Authorization'] = "Bearer #{token}" + http_options = {use_ssl: uri.scheme == 'https'} + http_options[:verify_mode] = OpenSSL::SSL::VERIFY_NONE unless RedmineSlack.setting?(:redmine_slack_verify_ssl) + Net::HTTP.start(uri.hostname, uri.port, http_options) do |http| + response = http.request(req) + response.body + end + rescue StandardError => e + Rails.logger.warn("cannot connect to #{url}") + Rails.logger.warn(e) + end + end + + def self.post_slack_responses + notifications = get_recent_notifications + notifications.each do |notification| + issue_id = notification.entity_id + issue = Issue.find(issue_id) + project = Project.find(issue.project_id) + seconds = Slack.textfield_for_project(project, :replies_threshold).to_i || 0 + replies = get_notification_replies(notification) + replies.each do |reply| + next unless reply.key?('thread_ts') && reply['thread_ts'] != reply['ts'] + + current_timestamp = Time.now.to_i + timestamp = current_timestamp - seconds + # Only act for replies within allowed "seconds". + next if reply['ts'].to_i < timestamp + + post_reply_to_redmine(reply, issue_id) + end + end + end +end diff --git a/app/views/redmine_slack/_issues_silent_updates.html.erb b/app/views/redmine_slack/_issues_silent_updates.html.erb new file mode 100644 index 0000000..016d43c --- /dev/null +++ b/app/views/redmine_slack/_issues_silent_updates.html.erb @@ -0,0 +1,4 @@ +

+ + +

\ No newline at end of file diff --git a/app/views/redmine_slack/_journal_silent_updates.html.erb b/app/views/redmine_slack/_journal_silent_updates.html.erb new file mode 100644 index 0000000..6ebfacd --- /dev/null +++ b/app/views/redmine_slack/_journal_silent_updates.html.erb @@ -0,0 +1,3 @@ +
+ + \ No newline at end of file diff --git a/app/views/redmine_slack_settings/_redmine_slack_select.html.slim b/app/views/redmine_slack_settings/_redmine_slack_select.html.slim new file mode 100644 index 0000000..e5c5461 --- /dev/null +++ b/app/views/redmine_slack_settings/_redmine_slack_select.html.slim @@ -0,0 +1,7 @@ +p + = f.select mf, project_redmine_slack_options(@redmine_slack_setting.send(mf)), label: l("label_settings_#{mf}") + ' + em.info[style="display: inline;"] + = l(:label_default) + ' : + = project_setting_redmine_slack_default_value(mf) diff --git a/app/views/redmine_slack_settings/_redmine_slack_text.html.slim b/app/views/redmine_slack_settings/_redmine_slack_text.html.slim new file mode 100644 index 0000000..1b290f4 --- /dev/null +++ b/app/views/redmine_slack_settings/_redmine_slack_text.html.slim @@ -0,0 +1,9 @@ +p + = f.text_field mf, size: size, label: l("label_settings_#{mf}") + em.info + = l(:label_redmine_slack_project_text_field_info) + | ( + = l(:label_default) + ' : + = Slack.default_textfield(@project, mf) + | ) diff --git a/app/views/redmine_slack_settings/_show.html.slim b/app/views/redmine_slack_settings/_show.html.slim new file mode 100644 index 0000000..67a9af9 --- /dev/null +++ b/app/views/redmine_slack_settings/_show.html.slim @@ -0,0 +1,57 @@ +.box.tabular.redmine_slack_settings + - @redmine_slack_setting = RedmineSlackSetting.find_or_create(@project.id) + = labelled_form_for :setting, + @redmine_slack_setting, + url: project_redmine_slack_setting_path(project_id: @project), + method: :put, + class: 'tabular' do |f| + = error_messages_for 'redmine_slack_setting' + .box + .info = t(:redmine_slack_settings_project_intro) + br + p + = f.text_field :redmine_slack_token, size: 60, label: l(:label_settings_redmine_slack_token) + em.info + = l(:label_redmine_slack_project_text_field_info) + | ( + = l(:label_redmine_slack_default_not_visible) + | ) + p + = f.text_field :redmine_slack_signing_secret, size: 60, label: l(:label_settings_redmine_slack_signing_secret) + em.info + = l(:label_redmine_slack_project_text_field_info) + | ( + = l(:label_redmine_slack_default_not_visible) + | ) + = render partial: 'redmine_slack_settings/redmine_slack_text', locals: { f: f, mf: :redmine_slack_channel, size: 30 } + = render partial: 'redmine_slack_settings/redmine_slack_select', locals: { f: f, mf: :redmine_slack_verify_ssl } + + p + = render partial: 'redmine_slack_settings/redmine_slack_text', locals: { f: f, mf: :color_create_notifications, size: 30 } + = render partial: 'redmine_slack_settings/redmine_slack_text', locals: { f: f, mf: :color_update_notifications, size: 30 } + = render partial: 'redmine_slack_settings/redmine_slack_text', locals: { f: f, mf: :color_close_notifications, size: 30 } + = render partial: 'redmine_slack_settings/redmine_slack_text', locals: { f: f, mf: :update_notification_threshold, size: 30 } + = render partial: 'redmine_slack_settings/redmine_slack_text', locals: { f: f, mf: :replies_threshold, size: 30 } + + br + h3 = l(:label_issue_plural) + .info = t(:redmine_slack_issue_intro) + br + = render partial: 'redmine_slack_settings/redmine_slack_select', locals: { f: f, mf: :auto_mentions } + = render partial: 'redmine_slack_settings/redmine_slack_select', locals: { f: f, mf: :post_updates } + = render partial: 'redmine_slack_settings/redmine_slack_select', locals: { f: f, mf: :new_include_description } + = render partial: 'redmine_slack_settings/redmine_slack_select', locals: { f: f, mf: :updated_include_description } + = render partial: 'redmine_slack_settings/redmine_slack_text', locals: { f: f, mf: :text_trim_size, size: 30 } + = render partial: 'redmine_slack_settings/redmine_slack_select', locals: { f: f, mf: :supress_empty_messages } + = render partial: 'redmine_slack_settings/redmine_slack_select', locals: { f: f, mf: :post_private_issues } + = render partial: 'redmine_slack_settings/redmine_slack_select', locals: { f: f, mf: :post_private_notes } + + br + h3 = l(:label_wiki) + .info = t(:redmine_slack_wiki_intro) + br + = render partial: 'redmine_slack_settings/redmine_slack_select', locals: { f: f, mf: :post_wiki } + = render partial: 'redmine_slack_settings/redmine_slack_select', locals: { f: f, mf: :post_wiki_updates } + br + + = submit_tag l(:button_save) diff --git a/app/views/settings/_redmine_slack_settings.html.slim b/app/views/settings/_redmine_slack_settings.html.slim new file mode 100644 index 0000000..58c6ed6 --- /dev/null +++ b/app/views/settings/_redmine_slack_settings.html.slim @@ -0,0 +1,80 @@ +- @settings = ActionController::Parameters.new(@settings) unless Rails.version >= '5.2' + +.info = t(:redmine_slack_settings_intro) +br +p + = content_tag(:label, l(:label_settings_redmine_slack_token)) + = text_field_tag('settings[redmine_slack_token]', @settings[:redmine_slack_token], size: 60, placeholder: '') + em.info = t(:redmine_slack_token_info_html) +p + = content_tag(:label, l(:label_settings_redmine_slack_signing_secret)) + = text_field_tag('settings[redmine_slack_signing_secret]', @settings[:redmine_slack_signing_secret], size: 60, placeholder: '') + em.info = t(:redmine_slack_signing_secret_info_html) +p + = content_tag(:label, l(:label_settings_redmine_slack_channel)) + = text_field_tag('settings[redmine_slack_channel]', @settings[:redmine_slack_channel], size: 30, placeholder: 'redmine') + em.info = t(:redmine_slack_channel_info_html) +p + = content_tag(:label, l(:label_settings_redmine_slack_verify_ssl)) + = check_box_tag 'settings[redmine_slack_verify_ssl]', 1, @settings[:redmine_slack_verify_ssl].to_i == 1 + em.info = t(:redmine_slack_verify_ssl_info_html) +p + = content_tag(:label, l(:label_settings_color_create_notifications)) + = text_field_tag('settings[color_create_notifications]', @settings[:color_create_notifications], size: 30) +p + = content_tag(:label, l(:label_settings_color_update_notifications)) + = text_field_tag('settings[color_update_notifications]', @settings[:color_update_notifications], size: 30) +p + = content_tag(:label, l(:label_settings_color_close_notifications)) + = text_field_tag('settings[color_close_notifications]', @settings[:color_close_notifications], size: 30) +p + = content_tag(:label, l(:label_settings_update_notification_threshold)) + = text_field_tag('settings[update_notification_threshold]', @settings[:update_notification_threshold], size: 30) +p + = content_tag(:label, l(:label_settings_replies_threshold)) + = text_field_tag('settings[replies_threshold]', @settings[:replies_threshold], size: 30) + +br +h3 = l(:label_issue_plural) +.info = t(:redmine_slack_issue_intro) +br +p + = content_tag(:label, l(:label_settings_auto_mentions)) + = check_box_tag 'settings[auto_mentions]', 1, @settings[:auto_mentions].to_i == 1 +p + = content_tag(:label, l(:label_settings_default_mentions)) + = text_field_tag('settings[default_mentions]', @settings[:default_mentions], size: 30) + em.info = t(:default_mentionsl_info) +p + = content_tag(:label, l(:label_settings_post_updates)) + = check_box_tag 'settings[post_updates]', 1, @settings[:post_updates].to_i == 1 +p + = content_tag(:label, l(:label_settings_new_include_description)) + = check_box_tag 'settings[new_include_description]', 1, @settings[:new_include_description].to_i == 1 +p + = content_tag(:label, l(:label_settings_updated_include_description)) + = check_box_tag 'settings[updated_include_description]', 1, @settings[:updated_include_description].to_i == 1 +p + = content_tag(:label, l(:label_settings_text_trim_size)) + = text_field_tag('settings[text_trim_size]', @settings[:text_trim_size], size: 30) +p + = content_tag(:label, l(:label_settings_supress_empty_messages)) + = check_box_tag 'settings[supress_empty_messages]', 1, @settings[:supress_empty_messages].to_i == 1 +p + = content_tag(:label, l(:label_settings_post_private_issues)) + = check_box_tag 'settings[post_private_issues]', 1, @settings[:post_private_issues].to_i == 1 +p + = content_tag(:label, l(:label_settings_post_private_notes)) + = check_box_tag 'settings[post_private_notes]', 1, @settings[:post_private_notes].to_i == 1 + +br +h3 = l(:label_wiki) +.info = t(:redmine_slack_wiki_intro) +br +p + = content_tag(:label, l(:label_settings_post_wiki)) + = check_box_tag 'settings[post_wiki]', 1, @settings[:post_wiki].to_i == 1 +p + = content_tag(:label, l(:label_settings_post_wiki_updates)) + = check_box_tag 'settings[post_wiki_updates]', 1, @settings[:post_wiki_updates].to_i == 1 + diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..10fe520 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,45 @@ +# English strings +en: + default_mentionsl_info: Default people to notify, comma separated (e.g. @all, @here) + error_redmine_slack_invalid_url: is not a valid URL + label_redmine_slack_default_not_visible: Default setting is not visible for security reasons + label_redmine_slack_issue_created: "[%{project_url}] Issue %{url} created by *%{user}*" + label_redmine_slack_issue_updated: "[%{project_url}] Issue %{url} updated by *%{user}*" + label_redmine_slack_project_text_field_info: Leave it blank for system default. + label_redmine_slack_setting: Redmine Slack Settings + label_redmine_slack_settings_default: System default + label_redmine_slack_settings_disabled: Disabled + label_redmine_slack_settings_enabled: Enabled + label_redmine_slack_wiki_created: "[%{project_url}] Wiki %{url} created by *%{user}*" + label_redmine_slack_wiki_updated: "[%{project_url}] Wiki %{url} updated by *%{user}*" + label_redmine_slack: Redmine Slack + label_settings_auto_mentions: Convert names to mentions? + label_settings_default_mentions: Default people for mentions + label_settings_redmine_slack_channel: Redmine Slack Channel + label_settings_redmine_slack_token: Redmine Slack Token + label_settings_redmine_slack_signing_secret: Redmine Slack Signing Secret + label_settings_redmine_slack_verify_ssl: Verify SSL + label_settings_new_include_description: New issue description? + label_settings_post_private_issues: Private issue updates? + label_settings_post_private_notes: Private notes updates? + label_settings_post_updates: Issue updates? + label_settings_post_wiki_updates: Wiki updates? + label_settings_post_wiki: Post Wiki added? + label_settings_updated_include_description: Description in update issue? + label_settings_text_trim_size: Text trim size? + label_settings_supress_empty_messages: Supress empty messages? + redmine_slack_channel_info_html: 'Here you have to specify the channel, which should be used. You can define multible channels, seperated by comma' + redmine_slack_contacts_intro: Activate the changes for Issues that should be sent to the pre-defined Redmine Slack channel. + redmine_slack_issue_intro: Activate the changes for Issues that should be sent to the pre-defined Redmine Slack channel. + redmine_slack_settings_intro: "Configure global settings here. This settings can be overriden per project." + redmine_slack_settings_project_intro: "Override global settings for this specific project." + redmine_slack_token_info_html: 'Generate a token from your Slack app' + redmine_slack_signing_secret_info_html: 'Paste the verification token from your Slack app' + redmine_slack_verify_ssl_info_html: 'If your Redmine Slack service uses an invalid or self-signed SSL certificate, disable it.' + redmine_slack_wiki_intro: Activate the changes for Wikis that should be sent to the pre-defined Redmine Slack channel. + permission_manage_redmine_slack: Manage Redmine Slack + label_settings_color_create_notifications: Hex color for create notifications + label_settings_color_update_notifications: Hex color for update notifications + label_settings_color_close_notifications: Hex color for close notifications + label_settings_update_notification_threshold: Update notifications threshold + label_settings_replies_threshold: Get Slack replies threshold diff --git a/config/locales/fr.yml b/config/locales/fr.yml new file mode 100644 index 0000000..d6150e4 --- /dev/null +++ b/config/locales/fr.yml @@ -0,0 +1,45 @@ +# French strings +fr: + default_mentionsl_info: Default people to notify, comma separated (e.g. @all, @here) + error_redmine_slack_invalid_url: is not a valid URL + label_redmine_slack_default_not_visible: Default setting is not visible for security reasons + label_redmine_slack_issue_created: "[%{project_url}] Issue %{url} created by *%{user}*" + label_redmine_slack_issue_updated: "[%{project_url}] Issue %{url} updated by *%{user}*" + label_redmine_slack_project_text_field_info: Leave it blank for system default. + label_redmine_slack_setting: Paramètres de Redmine Slack + label_redmine_slack_settings_default: System default + label_redmine_slack_settings_disabled: Disabled + label_redmine_slack_settings_enabled: Enabled + label_redmine_slack_wiki_created: "[%{project_url}] Wiki %{url} created by *%{user}*" + label_redmine_slack_wiki_updated: "[%{project_url}] Wiki %{url} updated by *%{user}*" + label_redmine_slack: Redmine Slack + label_settings_auto_mentions: Convert names to mentions? + label_settings_default_mentions: Default people for mentions + label_settings_redmine_slack_channel: Redmine Slack Channel + label_settings_redmine_slack_token: Redmine Slack Token + label_settings_redmine_slack_signing_secret: Redmine Slack Signing Secret + label_settings_redmine_slack_verify_ssl: Verify SSL + label_settings_new_include_description: New issue description? + label_settings_post_private_issues: Private issue updates? + label_settings_post_private_notes: Private notes updates? + label_settings_post_updates: Issue updates? + label_settings_post_wiki_updates: Wiki updates? + label_settings_post_wiki: Post Wiki added? + label_settings_updated_include_description: Description in update issue? + label_settings_text_trim_size: Text trim size? + label_settings_supress_empty_messages: Supress empty messages? + redmine_slack_channel_info_html: 'Here you have to specify the channel, which should be used. You can define multible channels, seperated by comma' + redmine_slack_contacts_intro: Activate the changes for Issues that should be sent to the pre-defined Redmine Slack channel. + redmine_slack_issue_intro: Activate the changes for Issues that should be sent to the pre-defined Redmine Slack channel. + redmine_slack_settings_intro: "Configure global settings here. This settings can be overriden per project." + redmine_slack_settings_project_intro: "Override global settings for this specific project." + redmine_slack_token_info_html: 'Generate a token from your Slack app' + redmine_slack_signing_secret_info_html: 'Paste the verification token from your Slack app' + redmine_slack_verify_ssl_info_html: 'If your Redmine Slack service uses an invalid or self-signed SSL certificate, disable it.' + redmine_slack_wiki_intro: Activate the changes for Wikis that should be sent to the pre-defined Redmine Slack channel. + permission_manage_redmine_slack: Manage Redmine Slack + label_settings_color_create_notifications: Hex color for create notifications + label_settings_color_update_notifications: Hex color for update notifications + label_settings_color_close_notifications: Hex color for close notifications + label_settings_update_notification_threshold: Update notifications threshold + label_settings_replies_threshold: Get Slack replies threshold diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..6d5db32 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +# Plugin's routes +# See: http://guides.rubyonrails.org/routing.html +resources :projects, only: [] do + resource :redmine_slack_setting, only: %i[show update] +end + +post 'slack/slash/connect', :to => 'slash_commands#channel_connect' diff --git a/db/migrate/20200622172451_create_redmine_slack_settings.rb b/db/migrate/20200622172451_create_redmine_slack_settings.rb new file mode 100644 index 0000000..f21a804 --- /dev/null +++ b/db/migrate/20200622172451_create_redmine_slack_settings.rb @@ -0,0 +1,23 @@ +# Initial migration. +class CreateRedmineSlackSettings < ActiveRecord::Migration[5.2] + def change + create_table :redmine_slack_settings do |t| + t.references :project, null: false, index: true + t.string :redmine_slack_token + t.string :redmine_slack_signing_secret + t.string :redmine_slack_channel + t.integer :redmine_slack_verify_ssl, default: 0, null: false + t.integer :auto_mentions, default: 0, null: false + t.string :default_mentions, default: nil + t.integer :post_updates, default: 0, null: false + t.integer :new_include_description, default: 0, null: false + t.integer :updated_include_description, default: 0, null: false + t.integer :post_private_issues, default: 0, null: false + t.integer :post_private_notes, default: 0, null: false + t.integer :post_wiki, default: 0, null: false + t.integer :post_wiki_updates, default: 0, null: false + t.integer :text_trim_size, default: nil + t.integer :supress_empty_messages, default: 0, null: false + end + end +end diff --git a/db/migrate/20200623165645_migrate_redmine_messenger_settings.rb b/db/migrate/20200623165645_migrate_redmine_messenger_settings.rb new file mode 100644 index 0000000..fefc3f2 --- /dev/null +++ b/db/migrate/20200623165645_migrate_redmine_messenger_settings.rb @@ -0,0 +1,31 @@ +# Initial migration. +class MigrateRedmineMessengerSettings < ActiveRecord::Migration[5.2] + def change + return unless Redmine::Plugin.installed?('redmine_messenger') + + MessengerSetting.where('messenger_url IS NOT NULL').each do |setting| + next if RedmineSlackSetting.where('project_id = :p_id', p_id: setting.project_id).exists? + + new_setting = RedmineSlackSetting.find_or_create(setting.project_id) + new_setting.redmine_slack_channel = setting.messenger_channel + new_setting.redmine_slack_verify_ssl = setting.messenger_verify_ssl + new_setting.auto_mentions = setting.auto_mentions + new_setting.default_mentions = setting.default_mentions + new_setting.post_updates = setting.post_updates + new_setting.new_include_description = setting.new_include_description + new_setting.updated_include_description = setting.updated_include_description + new_setting.post_private_issues = setting.post_private_issues + new_setting.post_private_notes = setting.post_private_notes + new_setting.post_wiki = setting.post_wiki + new_setting.post_wiki_updates = setting.post_wiki_updates + + if ActiveRecord::Base.connection.column_exists?(:messenger_settings, :text_trim_size) + new_setting.text_trim_size = setting.text_trim_size + end + if ActiveRecord::Base.connection.column_exists?(:messenger_settings, :supress_empty_messages) + new_setting.supress_empty_messages = setting.supress_empty_messages + end + new_setting.save! + end + end +end diff --git a/db/migrate/20200702092644_add_color_settings.rb b/db/migrate/20200702092644_add_color_settings.rb new file mode 100644 index 0000000..d4a22af --- /dev/null +++ b/db/migrate/20200702092644_add_color_settings.rb @@ -0,0 +1,8 @@ +# Add color settings. +class AddColorSettings < ActiveRecord::Migration[5.2] + def change + add_column :redmine_slack_settings, :color_create_notifications, :string, default: nil + add_column :redmine_slack_settings, :color_update_notifications, :string, default: nil + add_column :redmine_slack_settings, :color_close_notifications, :string, default: nil + end +end diff --git a/db/migrate/20200723160847_create_redmine_slack_notifications.rb b/db/migrate/20200723160847_create_redmine_slack_notifications.rb new file mode 100644 index 0000000..24a82e5 --- /dev/null +++ b/db/migrate/20200723160847_create_redmine_slack_notifications.rb @@ -0,0 +1,12 @@ +# Create Redmine Slack notifications table. +class CreateRedmineSlackNotifications < ActiveRecord::Migration[5.2] + def change + create_table :redmine_slack_notifications do |t| + t.integer :timestamp + t.string :entity + t.integer :entity_id + t.string :slack_channel_id + t.string :slack_message_id + end + end +end diff --git a/db/migrate/20200727112644_add_update_threshold.rb b/db/migrate/20200727112644_add_update_threshold.rb new file mode 100644 index 0000000..96e79f1 --- /dev/null +++ b/db/migrate/20200727112644_add_update_threshold.rb @@ -0,0 +1,6 @@ +# Add update threshold. +class AddUpdateThreshold < ActiveRecord::Migration[5.2] + def change + add_column :redmine_slack_settings, :update_notification_threshold, :integer, default: nil + end +end diff --git a/db/migrate/20200818072644_add_replies_threshold.rb b/db/migrate/20200818072644_add_replies_threshold.rb new file mode 100644 index 0000000..949bbd6 --- /dev/null +++ b/db/migrate/20200818072644_add_replies_threshold.rb @@ -0,0 +1,6 @@ +# Add replies threshold. +class AddRepliesThreshold < ActiveRecord::Migration[5.2] + def change + add_column :redmine_slack_settings, :replies_threshold, :integer, default: nil + end +end diff --git a/docs/images/signing-secret.png b/docs/images/signing-secret.png new file mode 100644 index 0000000000000000000000000000000000000000..ff859ec905632e379852a66216930157e28186b7 GIT binary patch literal 68932 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%0A~)@yRMKnaq9NJk#IMCrc6Te3q+ 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 JzDwwO|3B__;nM&B literal 0 HcmV?d00001 diff --git a/docs/images/slack-token.png b/docs/images/slack-token.png new file mode 100644 index 0000000000000000000000000000000000000000..561aa87e091a590f920e95d5ecac329a7f5b3184 GIT binary patch literal 48938 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 W^vtOrClU_)k$I}{q(H*J?|%X7d=d!& literal 0 HcmV?d00001 diff --git a/docs/images/slash-command.png b/docs/images/slash-command.png new file mode 100644 index 0000000000000000000000000000000000000000..a9481afd46462e03dfca4ccfd1c2854cd1859daa GIT binary patch literal 77522 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⪚x8klsYtXWu=btM<%86X2^vR}- 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 '5.2' + # convert Rails 4 data + new_settings = ActiveSupport::HashWithIndifferentAccess.new(Setting[:plugin_redmine_slack]) + Setting.plugin_redmine_slack = new_settings + new_settings + else + ActionController::Parameters.new(Setting[:plugin_redmine_slack]) + end + else + # Rails 5 uses ActiveSupport::HashWithIndifferentAccess + Setting[:plugin_redmine_slack] + end + end + + def self.setting?(value) + return true if settings[value].to_i == 1 + + false + end + end + + # Patches + Issue.include RedmineSlack::Patches::IssuePatch + WikiContent.include RedmineSlack::Patches::WikiContentPatch + ProjectsController.send :helper, RedmineSlackProjectsHelper + + # Global helpers + ActionView::Base.include RedmineSlack::Helpers + + # Hooks + require_dependency 'redmine_slack/hooks' +end diff --git a/lib/redmine_slack/diffy.rb b/lib/redmine_slack/diffy.rb new file mode 100644 index 0000000..4e380f4 --- /dev/null +++ b/lib/redmine_slack/diffy.rb @@ -0,0 +1,168 @@ +# frozen_string_literal: true + +require 'open3' +require 'tempfile' + +# Redmine Slack module. +module RedmineSlack + # Adapted from https://github.com/samg/diffy/blob/master/lib/diffy/diff.rb + class Diffy + ORIGINAL_DEFAULT_OPTIONS = { + :diff => '-U10000', + :source => 'strings', + :include_diff_info => false, + :include_plus_and_minus_in_html => false, + :context => nil, + :allow_empty_diff => true + }.freeze + + class << self + attr_writer :default_format + def default_format + @default_format ||= :text + end + + # default options passed to new Diff objects + attr_writer :default_options + def default_options + @default_options ||= ORIGINAL_DEFAULT_OPTIONS.dup + end + end + include Enumerable + attr_reader :string1, :string2, :options + + # supported options + # +:diff+:: A cli options string passed to diff + # +:source+:: Either _strings_ or _files_. Determines whether string1 + # and string2 should be interpreted as strings or file paths. + # +:include_diff_info+:: Include diff header info + # +:include_plus_and_minus_in_html+:: Show the +, -, ' ' at the + # beginning of lines in html output. + def initialize(string1, string2, options = {}) + @options = self.class.default_options.merge(options) + unless %w[strings files].include?(@options[:source]) + raise( + ArgumentError, + "Invalid :source option #{@options[:source].inspect}. Supported options are 'strings' and 'files'." + ) + end + + @string1 = string1 + @string2 = string2 + end + + def diff + @diff ||= begin + @paths = case options[:source] + when 'strings' + [tempfile(string1), tempfile(string2)] + when 'files' + [string1, string2] + end + + diff = Open3.popen3(diff_bin, *(diff_options + @paths)) {|_i, o, _e| o.read} + diff.force_encoding('ASCII-8BIT') if diff.respond_to?(:valid_encoding?) && !diff.valid_encoding? + if diff =~ /\A\s*\Z/ && !options[:allow_empty_diff] + diff = case options[:source] + when 'strings' then string1 + when 'files' then File.read(string1) + end.gsub(/^/, ' ') + end + diff + end + ensure + # unlink the tempfiles explicitly now that the diff is generated + if defined? @tempfiles # to avoid Ruby warnings about undefined ins var. + Array(@tempfiles).each do |t| + # check that the path is not nil and file still exists. + # REE seems to be very agressive with when it magically removes + # tempfiles + t.unlink if t.path && File.exist?(t.path) + rescue StandardError => e + warn "#{e.class}: #{e}" + warn e.backtrace.join("\n") + end + end + end + + def each + lines = case @options[:include_diff_info] + when false + # this "primes" the diff and sets up the paths we'll reference below. + diff + + # caching this regexp improves the performance of the loop by a + # considerable amount. + regexp = /^(--- "?#{@paths[0]}"?|\+\+\+ "?#{@paths[1]}"?|@@|\\\\)/ + + diff.split("\n").reject{|x| x =~ regexp}.map {|line| line + "\n"} + + when true + diff.split("\n").map {|line| line + "\n"} + end + + if block_given? + lines.each{|line| yield line} + else + lines.to_enum + end + end + + def each_chunk + old_state = nil + chunks = each_with_object([]) do |line, cc| + state = line.each_char.first + if state == old_state + cc.last << line + else + cc.push line.dup + end + old_state = state + end + + if block_given? + chunks.each{|chunk| yield chunk} + else + chunks.to_enum + end + end + + def tempfile(string) + t = Tempfile.new('diffy', :encoding => 'ascii-8bit') + # ensure tempfiles aren't unlinked when GC runs by maintaining a + # reference to them. + @tempfiles ||= [] + @tempfiles.push(t) + t.print(string) + t.flush + t.close + t.path + end + + private + + @@bin = nil + def diff_bin + return @@bin if @@bin + + if (@@bin = ENV['DIFFY_DIFF']) + # system() trick from Minitest + raise "Can't execute diff program '#{@@bin}'" unless system(@@bin, __FILE__, __FILE__) + + return @@bin + end + + diffs = %w[diff ldiff] + @@bin = diffs.find {|name| system(name, __FILE__, __FILE__)} + + raise "Can't find a diff executable in PATH #{ENV['PATH']}" if @@bin.nil? + + @@bin + end + + # options pass to diff program + def diff_options + Array(options[:context] ? "-U #{options[:context]}" : options[:diff]) + end + end +end diff --git a/lib/redmine_slack/helpers.rb b/lib/redmine_slack/helpers.rb new file mode 100644 index 0000000..de3a391 --- /dev/null +++ b/lib/redmine_slack/helpers.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# Redmine slack module. +module RedmineSlack + # Helpers module. + module Helpers + def project_redmine_slack_options(active) + options_for_select({l(:label_redmine_slack_settings_default) => '0', + l(:label_redmine_slack_settings_disabled) => '1', + l(:label_redmine_slack_settings_enabled) => '2'}, active) + end + + def project_setting_redmine_slack_default_value(value) + if Slack.default_project_setting(@project, value) + l(:label_redmine_slack_settings_enabled) + else + l(:label_redmine_slack_settings_disabled) + end + end + end +end diff --git a/lib/redmine_slack/hooks.rb b/lib/redmine_slack/hooks.rb new file mode 100644 index 0000000..fee7f58 --- /dev/null +++ b/lib/redmine_slack/hooks.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +# Redmine Slack module. +module RedmineSlack + # Add some listeners. + class RedmineSlackListener < Redmine::Hook::Listener + def model_changeset_scan_commit_for_issue_ids_pre_issue_update(context = {}) + issue = context[:issue] + journal = issue.current_journal + changeset = context[:changeset] + + channels = Slack.channels_for_project issue.project + + return unless channels.present? && issue.changes.any? && Slack.setting_for_project(issue.project, :post_updates) + return if issue.is_private? && !Slack.setting_for_project(issue.project, :post_private_issues) + + msg = "[#{ERB::Util.html_escape(issue.project)}] \ + #{ERB::Util.html_escape(journal.user.to_s)} \ + updated <#{Slack.object_url issue}|#{ERB::Util.html_escape(issue)}>" + + repository = changeset.repository + + if Setting.host_name.to_s =~ %r{/\A(https?\:\/\/)?(.+?)(\:(\d+))?(\/.+)?\z/i} + host = Regexp.last_match(2) + port = Regexp.last_match(4) + prefix = Regexp.last_match(5) + revision_url = Rails.application.routes.url_for( + controller: 'repositories', + action: 'revision', + id: repository.project, + repository_id: repository.identifier_param, + rev: changeset.revision, + host: host, + protocol: Setting.protocol, + port: port, + script_name: prefix + ) + else + revision_url = Rails.application.routes.url_for( + controller: 'repositories', + action: 'revision', + id: repository.project, + repository_id: repository.identifier_param, + rev: changeset.revision, + host: Setting.host_name, + protocol: Setting.protocol + ) + end + + attachment = {} + attachment[:text] = ll( + Setting.default_language, + :text_status_changed_by_changeset, + "<#{revision_url}|#{ERB::Util.html_escape(changeset.comments)}>" + ) + attachment[:fields] = journal.details.map {|d| Slack.detail_to_field d} + + Slack.speak(msg, channels, attachment: attachment, project: repository.project) + end + end +end diff --git a/lib/redmine_slack/patches/issue_patch.rb b/lib/redmine_slack/patches/issue_patch.rb new file mode 100644 index 0000000..d31b7aa --- /dev/null +++ b/lib/redmine_slack/patches/issue_patch.rb @@ -0,0 +1,214 @@ +# frozen_string_literal: true + +# Redmine Slack module to add patches. +module RedmineSlack + # Patches module. + module Patches + # Issue Patches. + module IssuePatch + def self.included(base) + base.send(:include, InstanceMethods) + base.class_eval do + after_create :send_redmine_slack_create + after_commit :send_redmine_slack_update, :on => :update + end + end + + # Instance Methods. + module InstanceMethods + def send_redmine_slack_create + channels = Slack.channels_for_project project + + return if channels.blank? + return if is_private? && !Slack.setting_for_project(project, :post_private_issues) + return if RequestStore.store[:redmine_slack_silent].nil? + + set_language_if_valid Setting.default_language + + attachment = {} + if description.present? && Slack.setting_for_project(project, :new_include_description) + attachment[:text] = Slack.markup_format(Slack.trim(description, project)) + end + attachment[:fields] = [{title: I18n.t(:field_status), + value: ERB::Util.html_escape(status.to_s), + short: true}, + {title: I18n.t(:field_priority), + value: ERB::Util.html_escape(priority.to_s), + short: true}] + if assigned_to.present? + attachment[:fields] << {title: I18n.t(:field_assigned_to), + value: ERB::Util.html_escape(assigned_to.to_s), + short: true} + end + + return unless attachment.any? && attachment.key?(:text) + + attachment[:color] = Slack.textfield_for_project(project, :color_create_notifications) + + notification = RedmineSlackNotification.find_or_create_within_timeframe( + 'issue', + id, + Slack.textfield_for_project(project, :update_notification_threshold) + ) + + Slack.speak( + l( + :label_redmine_slack_issue_created, + project_url: "<#{Slack.object_url project}|#{ERB::Util.html_escape(project)}>", + url: send_redmine_slack_mention_url(project, description), + user: author + ), + channels, + {attachment: attachment, project: project}, + notification + ) + end + + def send_redmine_slack_update + return if current_journal.nil? + return if RequestStore.store[:redmine_slack_silent].nil? + + channels = Slack.channels_for_project project + + return unless channels.present? && Slack.setting_for_project(project, :post_updates) + return if is_private? && !Slack.setting_for_project(project, :post_private_issues) + return if current_journal.private_notes? && !Slack.setting_for_project(project, :post_private_notes) + + set_language_if_valid Setting.default_language + + attachment = {} + text_diff = {} + + notification_type = 'issue' + + if current_journal.notes.present? && Slack.setting_for_project(project, :updated_include_description) + attachment[:text] = Slack.markup_format(Slack.trim(current_journal.notes, project)) + notification_type = 'issue-note' + end + + current_journal.details.each do |detail| + unless detail && + detail.prop_key == 'description' && + detail.value.present? && + detail.old_value.present? && + Slack.setting_for_project(project, :updated_include_description) + next + end + + diff = Diffy.new(detail.old_value, detail.value, :context => 1) + diff_elements = [] + diff.each_with_index do |item, _index| + item_stripped = item.strip.delete("\r").gsub("\r\n", '') + if item_stripped.length + if item[0] == '-' + diff_elements << "~#{item_stripped[1..-1]}~" if item_stripped[1..-1].length > 1 + elsif item[0] == '+' + diff_elements << "_#{item_stripped[1..-1]}_" if item_stripped[1..-1].length > 1 + else + diff_elements << item_stripped unless item_stripped.include? 'No newline at end of file' + end + end + end + text_diff = { + title: 'Description Differences', + value: Slack.trim(diff_elements.to_a.join("\r\n"), project), + short: false + } + # Finally, delete description from details to avoid including it as a field. + current_journal.details.delete(detail) + end + + fields = current_journal.details.map {|d| Slack.detail_to_field d, project} + if status_id != status_id_was + fields << {title: I18n.t(:field_status), + value: ERB::Util.html_escape(status.to_s), + short: true} + end + if priority_id != priority_id_was + fields << {title: I18n.t(:field_priority), + value: ERB::Util.html_escape(priority.to_s), + short: true} + end + if assigned_to.present? + fields << {title: I18n.t(:field_assigned_to), + value: ERB::Util.html_escape(assigned_to.to_s), + short: true} + end + + fields << text_diff if text_diff.any? + + attachment[:fields] = fields if fields.any? + + send_message = true + if Slack.setting_for_project(project, :supress_empty_messages) + send_message = false unless (attachment.any? && attachment.key?(:text)) || !text_diff.empty? + end + + return unless send_message + + attachment[:color] = Slack.textfield_for_project(project, :color_update_notifications) + + if closed? + attachment[:color] = Slack.textfield_for_project(project, :color_close_notifications) + end + + notification = RedmineSlackNotification.find_or_create_within_timeframe( + notification_type, + id, + Slack.textfield_for_project(project, :update_notification_threshold) + ) + if notification_type == 'issue' && !notification.slack_message_id.nil? + Slack.update_message( + l( + :label_redmine_slack_issue_updated, + project_url: "<#{Slack.object_url project}|#{ERB::Util.html_escape(project)}>", + url: send_redmine_slack_mention_url(project, current_journal.notes), + user: current_journal.user + ), + notification.slack_channel_id, + {attachment: attachment, project: project}, + notification + ) + else + Slack.speak( + l( + :label_redmine_slack_issue_updated, + project_url: "<#{Slack.object_url project}|#{ERB::Util.html_escape(project)}>", + url: send_redmine_slack_mention_url(project, current_journal.notes), + user: current_journal.user + ), + channels, + {attachment: attachment, project: project}, + notification + ) + end + end + + private + + def send_redmine_slack_mention_url(project, text) + mention_to = '' + if Slack.setting_for_project(project, :auto_mentions) || + Slack.textfield_for_project(project, :default_mentions).present? + mention_to = Slack.mentions(project, text) + end + "<#{Slack.object_url(self)}|#{self}>#{mention_to}" + end + end + end + + # Issues hook. + class IssuesHook < Redmine::Hook::ViewListener + # Add journal with edit issue + def view_issues_form_details_bottom(context = {}) + return unless context[:issue].id.nil? + + context[:controller].send( + :render_to_string, + partial: 'redmine_slack/issues_silent_updates', + locals: {} + ) + end + end + end +end diff --git a/lib/redmine_slack/patches/issues_controller_patch.rb b/lib/redmine_slack/patches/issues_controller_patch.rb new file mode 100644 index 0000000..4af1939 --- /dev/null +++ b/lib/redmine_slack/patches/issues_controller_patch.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +# Redmine Slack module to add patches. +module RedmineSlack + # Patches module. + module Patches + # Issue Patches. + module IssuesControllerPatch + def self.included(base) + base.send(:include, InstanceMethods) + base.class_eval do + before_action :handle_silent_update, :only => [:create, :update] + end + end + + # Instance Methods. + module InstanceMethods + def handle_silent_update + RequestStore.store[:redmine_slack_silent] = + params[:redmine_issue_slack_silent] || params[:redmine_journal_slack_silent] + end + end + end + end +end + +# Add module to Welcome Controller +IssuesController.send(:include, RedmineSlack::Patches::IssuesControllerPatch) +IssuesController.prepend RedmineSlack::Patches::IssuesControllerPatch diff --git a/lib/redmine_slack/patches/journals_patch.rb b/lib/redmine_slack/patches/journals_patch.rb new file mode 100644 index 0000000..6aee3d3 --- /dev/null +++ b/lib/redmine_slack/patches/journals_patch.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# To change this template, choose Tools | Templates +# and open the template in the editor. +module RedmineSlack + module Patches + # Journals hook. + class JournalsHook < Redmine::Hook::ViewListener + # Add journal with edit issue + def view_issues_edit_notes_bottom(context = {}) + context[:controller].send( + :render_to_string, + partial: 'redmine_slack/journal_silent_updates', + locals: {} + ) + end + end + end +end diff --git a/lib/redmine_slack/patches/wiki_content_patch.rb b/lib/redmine_slack/patches/wiki_content_patch.rb new file mode 100644 index 0000000..e11cbbc --- /dev/null +++ b/lib/redmine_slack/patches/wiki_content_patch.rb @@ -0,0 +1,161 @@ +# frozen_string_literal: true + +# Redmine Slack module to add patches. +module RedmineSlack + # Patches module. + module Patches + # Patches for wiki content. + module WikiContentPatch + def self.included(base) + base.send(:include, InstanceMethods) + base.class_eval do + after_create :send_redmine_slack_create + after_commit :send_redmine_slack_update, :on => :update + end + end + + # Instance methods. + module InstanceMethods + def send_redmine_slack_create + return unless Slack.setting_for_project(project, :post_wiki) + + set_language_if_valid Setting.default_language + + channels = Slack.channels_for_project project + + return if channels.blank? + + attachment = {} + attachment[:fields] = [] + attachment[:fields] << { + title: 'Content', + value: Slack.trim(text, project), + short: false + } + + attachment[:color] = Slack.textfield_for_project(project, :color_create_notifications) + + notification = RedmineSlackNotification.find_or_create_within_timeframe( + 'wiki-content', + id, + Slack.textfield_for_project(project, :update_notification_threshold) + ) + + Slack.speak( + l( + :label_redmine_slack_wiki_created, + project_url: "<#{Slack.object_url project}|#{ERB::Util.html_escape(project)}>", + url: "<#{Rails.application.routes.url_for( + :controller => 'wiki', + :action => 'show', + :project_id => project, + :id => page.title, + :host => Setting.host_name + )}|#{page.title}>", + user: User.current + ), + channels, + {project: project, attachment: attachment}, + notification + ) + end + + def send_redmine_slack_update + return unless Slack.setting_for_project(project, :post_wiki_updates) + + set_language_if_valid Setting.default_language + + channels = Slack.channels_for_project project + + return if channels.blank? + + attachment = nil + if comments.present? + attachment = {} + attachment[:text] = Slack.markup_format(comments.to_s) + end + + version_to = version + + content_to = versions.find_by(version: version_to) + content_from = content_to.try(:previous) + if content_to && content_from + diff = Diffy.new(content_from.data, content_to.data, :context => 1) + diff_elements = [] + diff.each_with_index do |item, _index| + item_stripped = item.strip.delete("\r").gsub("\r\n", '') + if item_stripped.length + if item[0] == '-' + diff_elements << "~#{item_stripped[1..-1]}~" if item_stripped[1..-1].length > 1 + elsif item[0] == '+' + diff_elements << "_#{item_stripped[1..-1]}_" if item_stripped[1..-1].length > 1 + else + diff_elements << item_stripped unless item_stripped.include? 'No newline at end of file' + end + end + end + attachment = {} if attachment.nil? + attachment[:fields] = [] + attachment[:fields] << { + title: 'Content Differences', + value: diff_elements.to_a.join("\r\n"), + short: false + } + end + + send_message = true + if Slack.setting_for_project(project, :supress_empty_messages) + send_message = false unless attachment.any? && (attachment.key?(:text) || attachment.key?(:fields)) + end + + return unless send_message + + attachment[:color] = Slack.textfield_for_project(project, :color_update_notifications) + + notification = RedmineSlackNotification.find_or_create_within_timeframe( + 'wiki-content', + id, + Slack.textfield_for_project(project, :update_notification_threshold) + ) + if !notification.slack_message_id.nil? + Slack.update_message( + l( + :label_redmine_slack_wiki_updated, + project_url: "<#{Slack.object_url project}|#{ERB::Util.html_escape(project)}>", + url: "<#{Rails.application.routes.url_for( + :controller => 'wiki', + :action => 'show', + :project_id => project, + :id => page.title, + :host => Setting.host_name + )}|#{page.title}>", + user: User.current + ), + notification.slack_channel_id, + {project: project, attachment: attachment}, + notification + ) + else + Slack.speak( + l( + :label_redmine_slack_wiki_updated, + project_url: "<#{Slack.object_url project}|#{ERB::Util.html_escape(project)}>", + url: "<#{Rails.application.routes.url_for( + :controller => 'wiki', + :action => 'show', + :project_id => project, + :id => page.title, + :host => Setting.host_name + )}|#{page.title}>", + user: User.current + ), + channels, + {project: project, attachment: attachment}, + notification + ) + end + end + end + end + end +end diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb new file mode 100644 index 0000000..8e657fa --- /dev/null +++ b/test/integration/routing_test.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require File.expand_path('../../test_helper', __FILE__) + +# Test Routing class. +class RoutingTest < Redmine::RoutingTest + test 'routing redmine_slack' do + should_route 'GET /projects/1/settings/redmine_slack' => 'projects#settings', :id => '1', :tab => 'redmine_slack' + should_route 'PUT /projects/1/redmine_slack_setting' => 'redmine_slack_settings#update', :project_id => '1' + end +end diff --git a/test/support/database-postgresql-travis.yml b/test/support/database-postgresql-travis.yml new file mode 100644 index 0000000..a118b62 --- /dev/null +++ b/test/support/database-postgresql-travis.yml @@ -0,0 +1,8 @@ +test: + adapter: postgresql + encoding: unicode + pool: 5 + database: travis_ci_test + user: postgres + + diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..d3d98c1 --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +$VERBOSE = nil + +unless ENV['SKIP_COVERAGE'] + require 'simplecov' + require 'simplecov-rcov' + + SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ + SimpleCov::Formatter::HTMLFormatter, + SimpleCov::Formatter::RcovFormatter + ] + + SimpleCov.start :rails do + add_filter 'init.rb' + root File.expand_path(File.dirname(__FILE__) + '/..') + end +end + +require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper') + +# Redmine slack test helper module. +module RedmineSlack + # Test case class. + class TestCase + include ActionDispatch::TestProcess + + def self.prepare + Role.where(id: [1, 2]).each do |r| + r.permissions << :view_issues + r.save + end + + Project.where(id: [1, 2]).each do |project| + EnabledModule.create(project: project, name: 'issue_tracking') + end + end + end +end diff --git a/test/unit/i18n_test.rb b/test/unit/i18n_test.rb new file mode 100644 index 0000000..fdd0ec5 --- /dev/null +++ b/test/unit/i18n_test.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +require File.expand_path('../../test_helper', __FILE__) + +# Test internationalization. +class I18nTest < ActiveSupport::TestCase + include Redmine::I18n + + def setup + User.current = nil + end + + def teardown + set_language_if_valid 'en' + end + + def test_valid_languages + assert valid_languages.is_a?(Array) + assert valid_languages.first.is_a?(Symbol) + end + + def test_locales_validness + lang_files_count = Dir[Rails.root.join('plugins', + 'redmine_slack', + 'config', + 'locales', + '*.yml')].size + assert_equal lang_files_count, 2 + valid_languages.each do |lang| + assert set_language_if_valid(lang) + end + # check if parse error exists + ::I18n.locale = 'fr' + assert_equal 'Paramètres de Redmine Slack', l(:label_redmine_slack_setting) + ::I18n.locale = 'en' + assert_equal 'Redmine Slack Settings', l(:label_redmine_slack_setting) + set_language_if_valid('en') + end +end diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb new file mode 100644 index 0000000..ba38085 --- /dev/null +++ b/test/unit/issue_test.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require File.expand_path('../../test_helper', __FILE__) + +# Issues basic test. +class IssueTest < ActiveSupport::TestCase + fixtures :projects, :users, :members, :member_roles, :roles, + :trackers, :projects_trackers, + :enabled_modules, + :issue_statuses, :issue_categories, :workflows, + :enumerations, + :issues, :journals, :journal_details, + :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values, + :time_entries + + include Redmine::I18n + + def setup + set_language_if_valid 'en' + end + + def teardown + User.current = nil + end + + def test_create + issue = Issue.new(project_id: 1, tracker_id: 1, author_id: 3, subject: 'test_create') + assert issue.save + assert_equal issue.tracker.default_status, issue.status + assert issue.description.nil? + end +end diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb new file mode 100644 index 0000000..691014e --- /dev/null +++ b/test/unit/project_test.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require File.expand_path('../../test_helper', __FILE__) + +# Projects basic test. +class ProjectTest < ActiveSupport::TestCase + fixtures :projects, :trackers, :issue_statuses, :issues, + :journals, :journal_details, + :enumerations, :users, :issue_categories, + :projects_trackers, + :custom_fields, + :custom_fields_projects, + :custom_fields_trackers, + :custom_values, + :roles, + :member_roles, + :members, + :enabled_modules, + :versions, + :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, + :groups_users, + :time_entries, + :news, :comments, + :documents, + :workflows + + def setup + User.current = User.find(1) + end + + def test_create_project + Project.delete_all + Project.create!(name: 'Project Messenger', identifier: 'project-messenger') + assert_equal 1, Project.count + end + + def test_load_project + Project.find(1) + end +end -- 2.39.5