Added Messenger plugin.
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2023-02-27 22:36:26 +01:00
parent 054ddb0f4f
commit 18a64f6d16
59 changed files with 2502 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
env:
browser: true
jquery: true
extends: 'eslint:recommended'
rules:
indent:
- error
- 2
linebreak-style:
- error
- unix
quotes:
- error
- single
semi:
- error
- always

View File

@@ -0,0 +1,37 @@
name: Run Linters
on:
push:
pull_request:
schedule:
- cron: '30 5 * * *'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Gemfile
run: |
touch .enable_dev
sed -i "3isource 'https://rubygems.org'" Gemfile
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.1
bundler-cache: true
- name: Setup gems
run: |
bundle install --jobs 4 --retry 3
- name: Run RuboCop
run: |
bundle exec rubocop -S
- name: Run Slim-Lint
run: |
bundle exec slim-lint app/views
if: always()

View File

@@ -0,0 +1,121 @@
name: Tests
on:
push:
pull_request:
schedule:
- cron: '0 5 * * *'
jobs:
test:
name: ${{ matrix.redmine }} ${{ matrix.db }} ruby-${{ matrix.ruby }}
runs-on: ubuntu-latest
strategy:
matrix:
ruby: ['2.7', '3.0', '3.1', '3.2']
redmine: ['5.0-stable', 'master']
db: ['postgres', 'mysql']
exclude:
- ruby: '3.2'
redmine: '5.0-stable'
fail-fast: false
services:
postgres:
image: postgres:15
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: 'BestPasswordEver'
ports:
# will assign a random free host port
- 3306/tcp
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=3
steps:
- name: Verify MySQL connection from host
run: |
mysql --host 127.0.0.1 --port ${{ job.services.mysql.ports[3306] }} -uroot -pBestPasswordEver -e "SHOW DATABASES"
if: matrix.db == 'mysql'
- name: Checkout Redmine
uses: actions/checkout@v3
with:
repository: redmine/redmine
ref: ${{ matrix.redmine }}
path: redmine
- name: Checkout redmine_messenger
uses: actions/checkout@v3
with:
repository: AlphaNodes/redmine_messenger
path: redmine/plugins/redmine_messenger
- name: Update package archives
run: sudo apt-get update --yes --quiet
- name: Install package dependencies
run: >
sudo apt-get install --yes --quiet
build-essential
cmake
libicu-dev
libmysqlclient-dev
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Prepare Redmine source
working-directory: redmine
run: |
cp plugins/redmine_messenger/test/support/database-mysql.yml config/database.yml
cp plugins/redmine_messenger/test/support/configuration.yml config/configuration.yml
- name: Install Ruby dependencies
working-directory: redmine
run: |
bundle config set --local without 'development'
bundle install --jobs=4 --retry=3
- name: Run Redmine rake tasks
env:
RAILS_ENV: test
MYSQL_PORT: ${{ job.services.mysql.ports[3306] }}
working-directory: redmine
run: |
bundle exec rake generate_secret_token
bundle exec rake db:create db:migrate redmine:plugins:migrate
bundle exec rake db:test:prepare
- name: Run tests
env:
RAILS_ENV: test
MYSQL_PORT: ${{ job.services.mysql.ports[3306] }}
working-directory: redmine
run: bundle exec rake redmine:plugins:test NAME=redmine_messenger RUBYOPT="-W0"
- name: Run uninstall test
env:
RAILS_ENV: test
MYSQL_PORT: ${{ job.services.mysql.ports[3306] }}
working-directory: redmine
run: bundle exec rake redmine:plugins:migrate NAME=redmine_messenger VERSION=0

10
plugins/redmine_messenger/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
.DS_Store
coverage/
Gemfile.lock
.buildpath
.project
.settings/
docs/_build
docs/_static
docs/_templates
.enable_dev

View File

@@ -0,0 +1,106 @@
require:
- rubocop-performance
- rubocop-rails
- rubocop-minitest
AllCops:
TargetRubyVersion: 2.7
TargetRailsVersion: 6.1
NewCops: enable
Rails:
Enabled: true
Minitest/MultipleAssertions:
Max: 5
Enabled: true
Minitest/AssertPredicate:
Enabled: false
Metrics:
Enabled: false
Metrics/ParameterLists:
Enabled: true
CountKeywordArgs: false
Layout/LineLength:
Max: 140
Rails/ApplicationJob:
Enabled: false
Lint/AmbiguousOperatorPrecedence:
Enabled: false
Rails/ApplicationRecord:
Enabled: false
Rails/CreateTableWithTimestamps:
Enabled: false
Rails/HelperInstanceVariable:
Enabled: false
Rails/SkipsModelValidations:
Enabled: false
Performance/ChainArrayAllocation:
Enabled: true
Style/AutoResourceCleanup:
Enabled: true
Style/ExpandPathArguments:
Enabled: true
Exclude:
- test/**/*
Style/FrozenStringLiteralComment:
Enabled: true
Exclude:
- '/**/*.rsb'
Style/OptionHash:
Enabled: true
SuspiciousParamNames:
- options
- api_options
- opts
- args
- params
- parameters
- settings
Exclude:
- lib/redmine_messenger/patches/*.rb
# postgresql and mysql are supported
# autodetect does not work without database configuration
Rails/BulkChangeTable:
Enabled: true
Database: postgresql
Style/ReturnNil:
Enabled: true
Style/UnlessLogicalOperators:
Enabled: true
Style/MethodCallWithArgsParentheses:
Enabled: true
AllowParenthesesInMultilineCall: true
AllowParenthesesInChaining: true
EnforcedStyle: omit_parentheses
Style/Documentation:
Enabled: false
Style/HashTransformKeys:
Enabled: false
Style/HashTransformValues:
Enabled: false
Naming/VariableNumber:
Enabled: false

View File

@@ -0,0 +1,39 @@
linters:
LineLength:
max: 140
RuboCop:
ignored_cops:
- Layout/ArgumentAlignment
- Layout/ArrayAlignment
- Layout/BlockEndNewline
- Layout/EmptyLineAfterGuardClause
- Layout/HashAlignment
- Layout/IndentationConsistency
- Layout/IndentationWidth
- Layout/IndentFirstArgument
- Layout/IndentFirstArrayElement
- Layout/IndentFirstHashElement
- Layout/MultilineArrayBraceLayout
- Layout/MultilineAssignmentLayout
- Layout/MultilineBlockLayout
- Layout/MultilineHashBraceLayout
- Layout/MultilineMethodCallBraceLayout
- Layout/MultilineMethodCallIndentation
- Layout/MultilineMethodDefinitionBraceLayout
- Layout/MultilineOperationIndentation
- Layout/TrailingBlankLines
- Layout/TrailingEmptyLines
- Layout/TrailingWhitespace
- Lint/BlockAlignment
- Lint/EndAlignment
- Lint/Void
- Metrics/BlockLength
- Metrics/BlockNesting
- Layout/LineLength
- Naming/FileName
- Rails/OutputSafety
- Style/FrozenStringLiteralComment
- Style/IdenticalConditionalBranches
- Style/IfUnlessModifier
- Style/Next
- Style/WhileUntilModifier

View File

@@ -0,0 +1,6 @@
{
"extends": "stylelint-config-standard",
"rules": {
"string-quotes": "single"
}
}

View File

@@ -0,0 +1,144 @@
Changelog
=========
1.0.15
------
- Ruby 3.2 support
- Redmine 5.0 is required. Use git tag 1.0.14, if you use an older version.
1.0.14
------
- Fix i18n bug: switch back to used language after sending message
- Ruby 2.7 or higher is required. Maintained ruby versions are supported only, see <https://www.ruby-lang.org/en/downloads/>
- Redmine 4.2 is required. Use git tag 1.0.13, if you use an older version.
1.0.13
------
- Slack compatible url formating, see #100
1.0.12
------
- Fixed settings bug introducted with version 1.0.11
1.0.11
------
- Upcoming Redmine 5 support
- Ruby 3 support
- Ruby 2.6 or higher is required
- Use redmine_plugin_kit as plugin loader
1.0.10
------
- Web service is called asynchron which does not block performance while sending message
1.0.9
-----
- Redmine 4.1 is required. Use git tag 1.0.8, if you use an older version.
- Redmine 4.2 support
- Ruby 2.5 or higher is required
1.0.8
-----
- Drop testing with travis - we use github actions
- Add translation pt-BR - thanks to @lucianocosta
1.0.7
-----
- Added feature to send messages directly to users to be notified - thanks to @Ujifman
1.0.6
-----
- Redmine 4 is required. Use git tag 1.0.5, if you use an older version.
- Redmine 4.1 support
- Fix problems with changed fields, description and notes
- Fix problems with quotes #38
- Redundant status and priority in messages #56
- Show attachments for new issues
- Show indicator for private comment on issue
- Ruby 2.4 or higher is required
- Fix project name with &
1.0.5
-----
- ruby 2.4.x or newer is required
1.0.4
-----
- Frensh translation added - thanks to @ZerooCool
1.0.3
-----
- Redmine 4 support
1.0.2
-----
- Bug fixed with issue urls, if Redmine is in subdirectory
- slim is used as template engine
- add private contacts, db and passwords support (if plugins are installed)
- Discord support added to documentation
1.0.1
-----
- Japanese translation has been added - thanks @Yoto
- Default mentions has been added - thanks @xstasi
1.0.0
-----
- Redmine 3.4.x compatibility
- Commit message issue bug fix
- Some code cleanups
0.9.9
-----
- All global messenger settings can be overwritten project based
- Locale support added
- Wiki added supported for notification
- Contact added/updated supported for notification (if redmine_contacts is installed)
- Password added/updated supported for notification (if redmine_passwords is installed)
- DB entry added/updated supported for notification (if redmine_db is installed)
- SSL verify can be disabled
- Lots of refactoring and code cleanups
- Swith from httpclient to net/http
- Fork of redmine_rocketchat, redmine_slack and redmine_mattermost (base functions for all three messenger)
v0.6.1
------
unknown changes
v0.4
----
unknown changes
v0.3
----
unknown changes
v0.2
----
unknown changes
v0.1
----
unknown changes

View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
gem 'redmine_plugin_kit'
gem 'slim-rails'
group :development do
# this is only used for development.
# if you want to use it, do:
# - create .enable_dev file in messenger directory
# - remove rubocop entries from REDMINE/Gemfile
# - remove REDMINE/.rubocop* files
if File.file? File.expand_path './.enable_dev', __dir__
gem 'rubocop', require: false
gem 'rubocop-minitest', require: false
gem 'rubocop-performance', require: false
gem 'rubocop-rails', require: false
gem 'slim_lint', require: false
end
end

View File

@@ -0,0 +1,11 @@
Released under the MIT license.
Project redmine-slack is Copyright (c) 2014-2016 by Samuel Cormier-Iijima (https://github.com/sciyoshi/redmine-slack).
Fork project redmine_mattermost is Copyright (c) 2015-2016 by AltSol (https://github.com/altsol/redmine_mattermost).
Fork project redmine_rocketchat is Copyright (c) 2016-2017 by Phlegx (https://github.com/phlegx/redmine_rocketchat).
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,123 @@
Messenger plugin for Redmine
============================
This plugin posts updates to issues in your Redmine installation to [Slack](https://slack.com/), [Rocket.Chat](https://rocket.chat/), [Discord](https://discordapp.com/) or [Mattermost](https://about.mattermost.com/) channel.
[![Rate at redmine.org](https://img.shields.io/badge/rate%20at-redmine.org-blue.svg?style=fla)](https://www.redmine.org/plugins/redmine_messenger) [![Run Linters](https://github.com/AlphaNodes/redmine_messenger/workflows/Run%20Linters/badge.svg)](https://github.com/AlphaNodes/redmine_messenger/actions?query=workflow%3A%22Run+Linters%22) [![Tests](https://github.com/AlphaNodes/redmine_messenger/actions/workflows/tests.yml/badge.svg)](https://github.com/AlphaNodes/redmine_messenger/actions/workflows/tests.yml)
Features
--------
* Post information to messenger channel
* post issue updates
* post private issue updates
* display watchers
* convert username to mentions
* post wiki updates
* post db entry (if redmine_db is installed) updates
* post password (if redmine_passwords is installed) updates
* post contact (if redmine_contacts is installed) updates
* Post information directly to users to be notified (users names should be the same in Redmine and chat). Tested with Rocket.Chat
* overwrite messenger settings at project level
* parent project support (inherit messenger settings from parent project)
* multiple channel support (define one or more channels to deliver note)
Screenshot
----------
Rocket.Chat output:
![screenshot](https://raw.githubusercontent.com/alphanodes/redmine_messenger/master/assets/images/screenshot_rocketchat.png)
Redmine configuration:
![screenshot](https://raw.githubusercontent.com/alphanodes/redmine_messenger/master/assets/images/screenshot_redmine_settings.png)
* **Convert names to mentions:** Automatically converts Redmine mentions into Slack mentions so a user is notified through Slack when mentioned in a Redmine note. Depends on Redmine Mentions plugin.
* **Display watchers:** Issue watchers are included in notifications.
* **Post issue updates:** All newly created notes on an issue generate a notification (does not include private issues).
* **Description in new issue:** Include the text description of a new issue in the notification.
* **Description in update issue:** Include the text encompassed in a note upon updating the issue in the notification.
* **Post updates for private issue:** Same as *Post issue updates* but for private issues.
* **Post private notes:** Same as *Description in update issue* but for private issues.
* **Post wiki updates:** Generates a notification when a projects Wiki is updated.
Prepare your messenger service
------------------------------
### Slack
Go to Slack documentation [Incoming Webhooks](https://api.slack.com/incoming-webhooks) for more information to set up Incoming WebHook
### Mattermost
Go to Mattermost documentation [Incoming Webhooks](https://docs.mattermost.com/developer/webhooks-incoming.html) for more information to set up Incoming WebHook
### Discord
Go to Discord documentation [Intro to Webhooks ](https://support.discordapp.com/hc/en-us/articles/228383668) for more information to set up Incoming WebHook
You have to add /slack after your webhook url.
### Rocket.Chat
Go to Rocket.Chat documentation [Incoming WebHook Scripting](https://rocket.chat/docs/administrator-guides/integrations/) for more information to set up Incoming WebHook
Requirements
------------
* Redmine version >= 5.0
* Ruby version >= 2.7.0
### Older versions
* If you want to use it with Redmine 3.x, use git tag 1.0.5
* If you want to use it with Redmine 4.0, use git tag 1.0.7
* If you want to use it with Redmine 4.1, use git tag 1.0.13
* If you want to use it with Redmine 4.2, use git tag 1.0.14
Installation
------------
Install ``redmine_messenger`` plugin for `Redmine`
cd $REDMINE_ROOT
git clone https://github.com/AlphaNodes/redmine_messenger.git plugins/redmine_messenger
bundle update
bundle exec rake redmine:plugins:migrate RAILS_ENV=production
Make sure that the directory is named `redmine_messenger` (you cannot use another name for it)!
Restart Redmine (application server) and you should see the plugin show up in the Plugins page.
Under the configuration options, set the Messenger API URL to the URL for an
Incoming WebHook integration in your Messenger account and also set the Messenger
Channel to the channel's handle (be careful, this is not the channel's display name
visible to users, you can find each channel's handle by navigating inside the channel
and clicking the down-arrow and selecting view info).
Uninstall
---------
Uninstall ``redmine_messenger``
cd $REDMINE_ROOT
bundle exec rake redmine:plugins:migrate NAME=redmine_messenger VERSION=0 RAILS_ENV=production
rm -rf plugins/redmine_messenger
Restart Redmine (application server)
Credits
-------
The source code is forked from
* [redmine_rocketchat](https://github.com/phlegx/redmine_rocketchat)
* [redmine_mattermost](https://github.com/altsol/redmine_mattermost)
* [redmine-slack](https://github.com/sciyoshi/redmine-slack)
Special thanks to the original author and contributors for making this awesome hook for Redmine. This fork is just refactored to use Messenger-namespaced configuration options in order to use all hooks for Rocket.Chat, Mattermost AND Slack in a Redmine installation.

View File

@@ -0,0 +1,49 @@
# frozen_string_literal: true
class MessengerSettingsController < ApplicationController
before_action :find_project_by_project_id
before_action :authorize
def update
setting = MessengerSetting.find_or_create @project.id
if setting.update allowed_params
flash[:notice] = l :notice_successful_update
redirect_to settings_project_path(@project, tab: 'messenger')
else
flash[:error] = setting.errors.full_messages.flatten.join "\n"
respond_to do |format|
format.html { redirect_to settings_project_path(@project, tab: 'messenger') }
format.api { render_validation_errors setting }
end
end
end
private
def allowed_params
params.require(:setting).permit :messenger_url,
:messenger_icon,
:messenger_channel,
:messenger_username,
:messenger_verify_ssl,
:messenger_direct_users_messages,
:auto_mentions,
:default_mentions,
:display_watchers,
:post_updates,
:new_include_description,
:updated_include_description,
:post_private_issues,
:post_private_notes,
:post_wiki,
:post_wiki_updates,
:post_db,
:post_db_updates,
:post_private_db,
:post_contact,
:post_contact_updates,
:post_private_contacts,
:post_password,
:post_password_updates
end
end

View File

@@ -0,0 +1,16 @@
# frozen_string_literal: true
module MessengerProjectsHelper
def project_settings_tabs
tabs = super
if User.current.allowed_to? :manage_messenger, @project
tabs << { name: 'messenger',
action: :show,
partial: 'messenger_settings/show',
label: :label_messenger }
end
tabs
end
end

View File

@@ -0,0 +1,25 @@
# frozen_string_literal: true
require 'net/http'
require 'uri'
class MessengerDeliverJob < ActiveJob::Base
queue_as :default
def perform(url, params)
uri = URI url
http_options = { use_ssl: uri.scheme == 'https' }
http_options[:verify_mode] = OpenSSL::SSL::VERIFY_NONE unless RedmineMessenger.setting? :messenger_verify_ssl
begin
req = Net::HTTP::Post.new uri
req.set_form_data payload: params.to_json
Net::HTTP.start uri.hostname, uri.port, http_options do |http|
response = http.request req
Rails.logger.warn response.inspect 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

View File

@@ -0,0 +1,291 @@
# frozen_string_literal: true
class Messenger
include Redmine::I18n
class << self
def markup_format(text)
# TODO: output format should be markdown, but at the moment there is no
# solution without using pandoc (http://pandoc.org/), which requires
# packages on os level
#
# Redmine::WikiFormatting.html_parser.to_text(text)
text = text.to_s.dup
# @see https://api.slack.com/reference/surfaces/formatting#escaping
text.gsub! '&', '&amp;'
text.gsub! '<', '&lt;'
text.gsub! '>', '&gt;'
text
end
def default_url_options
{ only_path: true, script_name: Redmine::Utils.relative_url_root }
end
def speak(msg, channels, url, options)
url ||= RedmineMessenger.setting :messenger_url
return if url.blank? || channels.blank?
params = { text: msg, link_names: 1 }
username = textfield_for_project options[:project], :messenger_username
params[:username] = username if username.present?
params[:attachments] = options[:attachment]&.any? ? [options[:attachment]] : []
icon = textfield_for_project options[:project], :messenger_icon
if icon.present?
if icon.start_with? ':'
params[:icon_emoji] = icon
else
params[:icon_url] = icon
end
end
channels.each do |channel|
params[:channel] = channel
MessengerDeliverJob.perform_later url, params
end
end
def 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 url_for_project(proj)
return if proj.blank?
# project based
pm = proj.messenger_setting
return pm.messenger_url if !pm.nil? && pm.messenger_url.present?
# parent project based
parent_url = url_for_project proj.parent
return parent_url if parent_url.present?
# system based
return RedmineMessenger.setting :messenger_url if RedmineMessenger.setting(:messenger_url).present?
nil
end
def project_url_markdown(project)
"<#{object_url project}|#{project.name}>"
end
def url_markdown(obj, name)
"<#{object_url obj}|#{name}>"
end
def textfield_for_project(proj, config)
return if proj.blank?
# project based
pm = proj.messenger_setting
return pm.send config if !pm.nil? && pm.send(config).present?
default_textfield proj, config
end
def default_textfield(proj, config)
# parent project based
parent_field = textfield_for_project proj.parent, config
return parent_field if parent_field.present?
return RedmineMessenger.setting config if RedmineMessenger.setting(config).present?
''
end
def channels_for_project(proj)
return [] if proj.blank?
# project based
pm = proj.messenger_setting
if !pm.nil? && pm.messenger_channel.present?
return [] if pm.messenger_channel == '-'
return pm.messenger_channel.split(',').map!(&:strip).uniq
end
default_project_channels proj
end
def setting_for_project(proj, config)
return false if proj.blank?
@setting_found = 0
# project based
pm = proj.messenger_setting
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 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 RedmineMessenger.setting(config).present? && RedmineMessenger.setting?(config)
false
end
def attachment_text_from_journal(journal)
obj = journal.details.detect { |j| j.prop_key == 'description' && j.property == 'attr' }
text = obj.value if obj.present?
text.present? ? markup_format(text) : nil
end
def detail_to_field(detail, prj = nil)
field_format = nil
key = nil
escape = true
value = detail.value.to_s
if detail.property == 'cf'
key = CustomField.find(detail.prop_key)&.name
unless key.nil?
title = key
field_format = CustomField.find(detail.prop_key)&.field_format
value = IssuesController.helpers.format_value detail.value, detail.custom_field if detail.value.present?
end
elsif detail.property == 'attachment'
key = 'attachment'
title = I18n.t :label_attachment
value = detail.value.to_s
elsif detail.property == 'attr' &&
detail.prop_key == 'db_relation'
return { short: true } unless setting_for_project prj, :post_db
title = I18n.t :field_db_relation
if detail.value.present?
entry = DbEntry.visible.find_by id: detail.value
value = entry.present? ? entry.name : detail.value.to_s
end
elsif detail.property == 'attr' &&
detail.prop_key == 'password_relation'
return { short: true } unless setting_for_project prj, :post_password
title = I18n.t :field_password_relation
if detail.value.present?
entry = Password.visible.find_by id: detail.value
value = entry.present? ? entry.name : detail.value.to_s
end
else
key = detail.prop_key.to_s.sub '_id', ''
title = case key
when 'parent'
I18n.t "field_#{key}_issue"
when 'copied_from'
I18n.t "label_#{key}"
else
I18n.t "field_#{key}"
end
value = detail.value.to_s
end
short = true
case key
when 'title', 'subject'
short = false
when 'description'
return
when 'tracker'
value = object_field_value Tracker, detail.value
when 'estimated_hours'
value = format_hours(value.is_a?(String) ? (value.to_hours || value) : value)
when 'project'
value = object_field_value Project, detail.value
when 'status'
value = object_field_value IssueStatus, detail.value
when 'priority'
value = object_field_value IssuePriority, detail.value
when 'category'
value = object_field_value IssueCategory, detail.value
when 'assigned_to', 'author'
value = object_field_value Principal, detail.value
when 'fixed_version'
value = object_field_value Version, detail.value
when 'attachment'
attachment = Attachment.find_by id: detail.prop_key
value = if attachment.present?
escape = false
"<#{object_url attachment}|#{markup_format attachment.filename}>"
else
detail.prop_key.to_s
end
when 'parent', 'copied_from'
issue = Issue.find_by id: detail.value
value = if issue.present?
escape = false
"<#{object_url issue}|#{markup_format issue}>"
else
detail.value.to_s
end
end
value = object_field_value Version, detail.value if detail.property == 'cf' && field_format == 'version'
value = if value.present?
if escape
markup_format value
else
value
end
else
'-'
end
result = { title: title, value: value }
result[:short] = true if short
result
end
def mentions(project, text)
names = []
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
private
def object_field_value(klass, id)
obj = klass.find_by id: id
obj.nil? ? id.to_s : obj.to_s
end
def extract_usernames(text)
return [] if text.blank?
# messenger 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 default_project_channels(proj)
# parent project based
parent_channel = channels_for_project proj.parent
return parent_channel if parent_channel.present?
# system based
if RedmineMessenger.setting(:messenger_channel).present? &&
RedmineMessenger.setting(:messenger_channel) != '-'
return RedmineMessenger.setting(:messenger_channel).split(',').map!(&:strip).uniq
end
[]
end
end
end

View File

@@ -0,0 +1,18 @@
# frozen_string_literal: true
class MessengerSetting < ActiveRecord::Base
belongs_to :project
validates :messenger_url, format: { with: URI::DEFAULT_PARSER.make_regexp(%w[http https]), allow_blank: true }
def self.find_or_create(project_id)
setting = MessengerSetting.find_by project_id: project_id
unless setting
setting = MessengerSetting.new
setting.project_id = project_id
setting.save!
end
setting
end
end

View File

@@ -0,0 +1,7 @@
p
= f.select mf, project_messenger_options(@messenger_setting.send(mf)), label: l("label_settings_#{mf}")
'
em.info style="display: inline;"
= l :label_default
' :
= project_setting_messenger_default_value mf

View File

@@ -0,0 +1,9 @@
p
= f.text_field mf, size: size, label: l("label_settings_#{mf}")
em.info
= l :label_messenger_project_text_field_info
| (
= l :label_default
' :
= Messenger.default_textfield @project, mf
| )

View File

@@ -0,0 +1,77 @@
= error_messages_for 'messenger_setting'
- @messenger_setting = MessengerSetting.find_or_create @project.id
= labelled_form_for :setting,
@messenger_setting,
url: project_messenger_setting_path(project_id: @project),
method: :put do |f|
fieldset#messenger_settings.box.tabular
legend = l :label_messenger_outgoing_webhook
- if User.current.admin?
.contextual
= link_to l(:label_administration), plugin_settings_path(id: 'redmine_messenger'), class: 'icon icon-settings'
.info = t :messenger_settings_project_intro
br
p
= f.text_field :messenger_url, size: 60, label: :label_settings_messenger_url
em.info
= l :label_messenger_project_text_field_info
| (
= l :label_messenger_default_not_visible
| )
= render 'messenger_settings/messenger_text', f: f, mf: :messenger_icon, size: 60
= render 'messenger_settings/messenger_text', f: f, mf: :messenger_channel, size: 30
= render 'messenger_settings/messenger_text', f: f, mf: :messenger_username, size: 30
= render 'messenger_settings/messenger_select', f: f, mf: :messenger_verify_ssl
fieldset#messenger_settings.box.tabular
legend = l :label_issue_plural
.info = t :messenger_issue_intro
br
= render 'messenger_settings/messenger_select', f: f, mf: :auto_mentions
= render 'messenger_settings/messenger_text', f: f, mf: :default_mentions, size: 30
= render 'messenger_settings/messenger_select', f: f, mf: :display_watchers
= render 'messenger_settings/messenger_select', f: f, mf: :post_updates
= render 'messenger_settings/messenger_select', f: f, mf: :new_include_description
= render 'messenger_settings/messenger_select', f: f, mf: :updated_include_description
= render 'messenger_settings/messenger_select', f: f, mf: :post_private_issues
= render 'messenger_settings/messenger_select', f: f, mf: :post_private_notes
= render 'messenger_settings/messenger_select', f: f, mf: :messenger_direct_users_messages
fieldset#messenger_settings.box.tabular
legend = l :label_wiki
.info = t :messenger_wiki_intro
br
= render 'messenger_settings/messenger_select', f: f, mf: :post_wiki
= render 'messenger_settings/messenger_select', f: f, mf: :post_wiki_updates
- if RedmineMessenger::REDMINE_DB_SUPPORT && User.current.allowed_to?(:view_db_entries, @project)
fieldset#messenger_settings.box.tabular
legend = l :field_db_entries
.info = t :messenger_db_intro
br
= render 'messenger_settings/messenger_select', f: f, mf: :post_db
= render 'messenger_settings/messenger_select', f: f, mf: :post_db_updates
= render 'messenger_settings/messenger_select', f: f, mf: :post_private_db
- if RedmineMessenger::REDMINE_CONTACTS_SUPPORT && User.current.allowed_to?(:view_contacts, @project)
fieldset#messenger_settings.box.tabular
legend = l :label_contact_plural
.info = t :messenger_contacts_intro
br
= render 'messenger_settings/messenger_select', f: f, mf: :post_contact
= render 'messenger_settings/messenger_select', f: f, mf: :post_contact_updates
= render 'messenger_settings/messenger_select', f: f, mf: :post_private_contacts
- if Redmine::Plugin.installed?('redmine_passwords') && User.current.allowed_to?(:view_passwords, @project)
fieldset#messenger_settings.box.tabular
legend = l :label_password_plural
.info = t :messenger_passwords_intro
br
= render 'messenger_settings/messenger_select', f: f, mf: :post_password
= render 'messenger_settings/messenger_select', f: f, mf: :post_password_updates
= submit_tag l(:button_save)

View File

@@ -0,0 +1,111 @@
.info = t :messenger_settings_intro
br
fieldset#messenger_settings.box.tabular
legend = l :label_messenger_outgoing_webhook
p
label = l :label_settings_messenger_url
= text_field_tag 'settings[messenger_url]', @settings[:messenger_url], size: 60, placeholder: 'https://webhook.url'
em.info = t :messenger_url_info_html
p
label = l :label_settings_messenger_icon
= text_field_tag 'settings[messenger_icon]', @settings[:messenger_icon], size: 60
p
label = l :label_settings_messenger_channel
= text_field_tag 'settings[messenger_channel]', @settings[:messenger_channel], size: 30, placeholder: 'redmine'
em.info = t :messenger_channel_info_html
p
label = l :label_settings_messenger_username
= text_field_tag 'settings[messenger_username]', @settings[:messenger_username], size: 30
p
label = l :label_settings_messenger_verify_ssl
= check_box_tag 'settings[messenger_verify_ssl]', 1, @settings[:messenger_verify_ssl].to_i == 1
em.info = t :messenger_verify_ssl_info_html
fieldset#messenger_settings.box.tabular
legend = l :label_issue_plural
.info = t :messenger_issue_intro
br
p
label = l :label_settings_auto_mentions
= check_box_tag 'settings[auto_mentions]', 1, @settings[:auto_mentions].to_i == 1
p
label = l :label_settings_default_mentions
= text_field_tag 'settings[default_mentions]', @settings[:default_mentions], size: 30
em.info = t :default_mentionsl_info
p
label = l :label_settings_display_watchers
= check_box_tag 'settings[display_watchers]', 1, @settings[:display_watchers].to_i == 1
p
label = l :label_settings_post_updates
= check_box_tag 'settings[post_updates]', 1, @settings[:post_updates].to_i == 1
p
label = l :label_settings_new_include_description
= check_box_tag 'settings[new_include_description]', 1, @settings[:new_include_description].to_i == 1
p
label = l :label_settings_updated_include_description
= check_box_tag 'settings[updated_include_description]', 1, @settings[:updated_include_description].to_i == 1
p
label = l :label_settings_post_private_issues
= check_box_tag 'settings[post_private_issues]', 1, @settings[:post_private_issues].to_i == 1
p
label = l :label_settings_post_private_notes
= check_box_tag 'settings[post_private_notes]', 1, @settings[:post_private_notes].to_i == 1
p
label = l :label_settings_messenger_direct_users_messages
= check_box_tag 'settings[messenger_direct_users_messages]', 1, @settings[:messenger_direct_users_messages].to_i == 1
em.info = t :messenger_direct_users_messages_info_html
fieldset#messenger_settings.box.tabular
legend = l :label_wiki
.info = t :messenger_wiki_intro
br
p
label = l :label_settings_post_wiki
= check_box_tag 'settings[post_wiki]', 1, @settings[:post_wiki].to_i == 1
p
label = l :label_settings_post_wiki_updates
= check_box_tag 'settings[post_wiki_updates]', 1, @settings[:post_wiki_updates].to_i == 1
- if RedmineMessenger::REDMINE_DB_SUPPORT
fieldset#messenger_settings.box.tabular
legend = l :field_db_entries
.info = t :messenger_db_intro
br
p
label = l :label_settings_post_db
= check_box_tag 'settings[post_db]', 1, @settings[:post_db].to_i == 1
p
label = l :label_settings_post_db_updates
= check_box_tag 'settings[post_db_updates]', 1, @settings[:post_db_updates].to_i == 1
p
label = l :label_settings_post_private_db
= check_box_tag 'settings[post_private_db]', 1, @settings[:post_private_db].to_i == 1
- if RedmineMessenger::REDMINE_CONTACTS_SUPPORT
fieldset#messenger_settings.box.tabular
legend = l :label_contact_plural
.info = t :messenger_contacts_intro
br
p
label = l :label_settings_post_contact
= check_box_tag 'settings[post_contact]', 1, @settings[:post_contact].to_i == 1
p
label = l :label_settings_post_contact_updates
= check_box_tag 'settings[post_contact_updates]', 1, @settings[:post_contact_updates].to_i == 1
p
label = l :label_settings_post_private_contacts
= check_box_tag 'settings[post_private_contacts]', 1, @settings[:post_private_contacts].to_i == 1
- if Redmine::Plugin.installed? 'redmine_passwords'
fieldset#messenger_settings.box.tabular
legend = l :label_password_plural
.info = t :messenger_passwords_intro
br
p
label = l :label_settings_post_password
= check_box_tag 'settings[post_password]', 1, @settings[:post_password].to_i == 1
p
label = l :label_settings_post_password_updates
= check_box_tag 'settings[post_password_updates]', 1, @settings[:post_password_updates].to_i == 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -0,0 +1 @@
# eslint ignore file

View File

@@ -0,0 +1 @@
# stylelint ignore file

View File

@@ -0,0 +1,55 @@
# German strings
de:
default_mentionsl_info: Benutzer, die immer mit Mentions benachrichtet werden sollen. Mehrere Namen können mit Komma getrennt angegeben werden (z.B. @all, @here).
label_messenger_contact_created: "%{project_url} - Kontakt %{url} erstellt von *%{user}*"
label_messenger_contact_updated: "%{project_url} - Kontakt %{url} aktualisiert von *%{user}*"
label_messenger_db_entry_created: "%{project_url} - DB Eintrag %{url} erstellt von *%{user}*"
label_messenger_db_entry_updated: "%{project_url} - DB Eintrag %{url} aktualisiert von *%{user}*"
label_messenger_default_not_visible: Standardeinstellung wird aus Sicherheitsgründen nicht angezeigt
label_messenger_issue_created: "%{project_url} - Ticket %{url} erstellt von *%{user}*"
label_messenger_issue_updated: "%{project_url} - Ticket %{url} aktualisiert von *%{user}*"
label_messenger_outgoing_webhook: Ausgehender Webhook
label_messenger_password_created: "%{project_url} - Passwort %{url} erstellt von *%{user}*"
label_messenger_password_updated: "%{project_url} - Passwort %{url} aktualisiert von *%{user}*"
label_messenger_project_text_field_info: Leer lassen für Systemstandard.
label_messenger_setting: Messenger Einstellung
label_messenger_settings_default: Standardeinstellung
label_messenger_settings_disabled: Deaktiviert
label_messenger_settings_enabled: Aktiviert
label_messenger_wiki_created: "%{project_url} - Wiki %{url} erstellt von *%{user}*"
label_messenger_wiki_updated: "%{project_url} - Wiki %{url} aktualisiert von *%{user}*"
label_messenger: Messenger
label_settings_auto_mentions: Namen für Mentions konvertiert?
label_settings_default_mentions: Standardbenutzer für Mentions
label_settings_display_watchers: Beobachter?
label_settings_messenger_channel: Messenger Channel
label_settings_messenger_icon: Messenger Icon
label_settings_messenger_url: Messenger URL
label_settings_messenger_username: Messenger Benutzer
label_settings_messenger_verify_ssl: SSL verifiziert
label_settings_new_include_description: Neue Ticketeschreibung?
label_settings_post_contact_updates: Kontakt Updates?
label_settings_post_contact: Neue Kontakte?
label_settings_post_db_updates: DB Einträge Updates?
label_settings_post_db: Neue DB Einträge?
label_settings_post_password_updates: Passwort Updates?
label_settings_post_password: Neue Passwörter?
label_settings_post_private_contacts: Private Kontakte?
label_settings_post_private_db: Private DB Einträge?
label_settings_post_private_issues: Private Ticket Updates?
label_settings_post_private_notes: Private Notizen?
label_settings_post_updates: Ticket Updates?
label_settings_post_wiki_updates: Wiki Updates?
label_settings_post_wiki: Neue Wikis?
label_settings_updated_include_description: Ticket Beschreibungsupdates?
messenger_channel_info_html: 'Hier wird der Channel dem die Nachrichten gesendet werden sollen. Es können mehrere Channel angegeben werden, indem Sie mit Komma getrennt werden.'
messenger_contacts_intro: Legen Sie fest welche Einträge oder Änderungen für Kontakte im angegebenen Messenger Channel versendet werden.
messenger_db_intro: Legen Sie fest welche Einträge oder Änderungen für DB-Einträge im angegebenen Messenger Channel versendet werden.
messenger_issue_intro: Legen Sie fest welche Einträge oder Änderungen für Tickets im angegebenen Messenger Channel versendet werden.
messenger_passwords_intro: Legen Sie fest welche Einträge oder Änderungen für Passwörter im angegebenen Messenger Channel versendet werden.
messenger_settings_intro: Ist die Messenger URL im Adminbereich leer werden keine Nachrichten von Redmine an den Messenger verschickt. Egal welche Angaben sonst hier durchgeführt werden. Ist der globale Versand von Nachrichten für alle Projekte gewünscht, trägt man hier die URL ein. Für alle Projekte werden dann in den entsprechenden Channel Nachrichten versendet. Will man jedoch nur für bestimmte Projekte etwas schicken lässt man die URL hier leer. Die entsprechenden Einstellungen müssen dann in den jeweiligen Projekten in der Projektkonfiguration durchgeführt werden.
messenger_settings_project_intro: Wurde die Messenger URL im Administrationsbereich leer gelassen weil man Änderungen nur für bestimmte Projekte an den Messenger schicken will, trägt man in der jeweiligen Projektkonfiguration die Messenger URL ein.
messenger_url_info_html: 'Generiere eine <a target="_blank" href="https://github.com/AlphaNodes/redmine_messenger#prepare-your-messenger-service">Incoming WebHook</a> URL vom Messenger Service. Um nur aus bestimmten Projekten Nachrichten zu versenden, kann diese URL leer bleiben und in den Projekteinstellungen gesetzt werden.'
messenger_verify_ssl_info_html: 'Falls der Messenger Service ein ungültiges oder selbst erstelltes (self-signed) SSL Zertifikat verwendet bitte deaktivieren.'
messenger_wiki_intro: Legen Sie fest welche Einträge oder Änderungen für Wikis im angegebenen Messenger Channel versendet werden.
permission_manage_messenger: Messenger verwalten

View File

@@ -0,0 +1,57 @@
# English strings
en:
default_mentionsl_info: Default people to notify, comma separated (e.g. @all, @here)
label_messenger_contact_created: "%{project_url} - Contact %{url} created by *%{user}*"
label_messenger_contact_updated: "%{project_url} - Contact %{url} updated by *%{user}*"
label_messenger_db_entry_created: "%{project_url} - DB entry %{url} created by *%{user}*"
label_messenger_db_entry_updated: "%{project_url} - DB entry %{url} updated by *%{user}*"
label_messenger_default_not_visible: Default setting is not visible for security reasons
label_messenger_issue_created: "%{project_url} - Issue %{url} created by *%{user}*"
label_messenger_issue_updated: "%{project_url} - Issue %{url} updated by *%{user}*"
label_messenger_outgoing_webhook: Outgoing Webhook
label_messenger_password_created: "%{project_url} - Password %{url} created by *%{user}*"
label_messenger_password_updated: "%{project_url} - Password %{url} updated by *%{user}*"
label_messenger_project_text_field_info: Leave it blank for system default.
label_messenger_setting: Messenger Settings
label_messenger_settings_default: System default
label_messenger_settings_disabled: Disabled
label_messenger_settings_enabled: Enabled
label_messenger_wiki_created: "%{project_url} - Wiki %{url} created by *%{user}*"
label_messenger_wiki_updated: "%{project_url} - Wiki %{url} updated by *%{user}*"
label_messenger: Messenger
label_settings_auto_mentions: Convert names to mentions?
label_settings_default_mentions: Default people for mentions
label_settings_display_watchers: Display watchers?
label_settings_messenger_channel: Messenger Channel
label_settings_messenger_icon: Messenger Icon
label_settings_messenger_url: Messenger URL
label_settings_messenger_username: Messenger username
label_settings_messenger_verify_ssl: Verify SSL
label_settings_messenger_direct_users_messages: Send direct messages
label_settings_new_include_description: New issue description?
label_settings_post_contact_updates: Contact updates?
label_settings_post_contact: Contact added?
label_settings_post_db_updates: DB entry updates?
label_settings_post_db: DB entry added?
label_settings_post_password_updates: Password updates?
label_settings_post_password: Password added?
label_settings_post_private_contacts: Private contacts?
label_settings_post_private_db: Private DB entries?
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?
messenger_channel_info_html: 'Here you have to specify the channel, which should be used. You can define multiple channels, seperated by comma'
messenger_contacts_intro: Activate the changes for Issues that should be sent to the pre-defined Messenger channel.
messenger_db_intro: Activate the changes for DB that should be sent to the pre-defined Messenger channel.
messenger_issue_intro: Activate the changes for Issues that should be sent to the pre-defined Messenger channel.
messenger_passwords_intro: Activate the changes for Passwords that should be sent to the pre-defined Messenger channel.
messenger_settings_intro: "Leave the Messenger URL in the administration area empty in order to send no messages from Redmine to the Messenger. No matter what else you have configured here. In case you wish to send messages of all Redmine projects to the Messenger fill out the URL. The messages will be sent to the specific channel. If you want only to be notified by some of the projects (not all) leave the messenger URL here blank and go to the specific project configuration."
messenger_settings_project_intro: "If you left empty the Messenger URL in the administration area in case to be not globally notified by all project changes you can configure your Messenger URL in the project settings."
messenger_url_info_html: 'Generate an <a target="_blank" href="https://github.com/AlphaNodes/redmine_messenger#prepare-your-messenger-service">Incoming WebHook</a> URL from the messenger service. Leave it empty, if you only want to activate specific projects with project based settings'
messenger_verify_ssl_info_html: 'If your Messenger service uses an invalid or self-signed SSL certificate, disable it.'
messenger_direct_users_messages_info_html: 'If enabled Messenger will post http requests to each user as channel (direct message in RocketChat) along with post in channel'
messenger_wiki_intro: Activate the changes for Wikis that should be sent to the pre-defined Messenger channel.
permission_manage_messenger: Manage messenger

View File

@@ -0,0 +1,55 @@
# French strings
fr:
default_mentionsl_info: Personnes à notifier par défaut, séparées par des virgules (@all, @here)
label_messenger_contact_created: "%{project_url} - Le contact %{url} créé par *%{user}*"
label_messenger_contact_updated: "%{project_url} - Le contact %{url} mis à jour par *%{user}*"
label_messenger_db_entry_created: "%{project_url} - Entrée de base de données %{url} créée par *%{user}*"
label_messenger_db_entry_updated: "%{project_url} - Entrée de base de données %{url} mis à jour par *%{user}*"
label_messenger_default_not_visible: Le paramètre par défaut n'est pas visible pour des raisons de sécurité
label_messenger_issue_created: "%{project_url} - Ticket %{url} créé par *%{user}*"
label_messenger_issue_updated: "%{project_url} - Ticket %{url} mis à jour par *%{user}*"
label_messenger_outgoing_webhook: Webhook sortant
label_messenger_password_created: "%{project_url} - Mot de passe %{url} créé par *%{user}*"
label_messenger_password_updated: "%{project_url} - Mot de passe %{url} mis à jour par *%{user}*"
label_messenger_project_text_field_info: Laissez ce champ vide pour le système par défaut.
label_messenger_setting: Paramètres de messagerie
label_messenger_settings_default: Choix de l'option
label_messenger_settings_disabled: Désactivé
label_messenger_settings_enabled: Activé
label_messenger_wiki_created: "%{project_url} - Wiki %{url} créé par *%{user}*"
label_messenger_wiki_updated: "%{project_url} - Wiki %{url} mis à jour par *%{user}*"
label_messenger: Messenger
label_settings_auto_mentions: Convertir les noms en mentions
label_settings_default_mentions: Personnes mentionnées par défaut
label_settings_display_watchers: Afficher l'utilisateur assigné au ticket
label_settings_messenger_channel: Nom du salon
label_settings_messenger_icon: Icône affiché
label_settings_messenger_url: URL WebHook entrant
label_settings_messenger_username: Nom du robot
label_settings_messenger_verify_ssl: Vérifier SSL
label_settings_new_include_description: Inclure la description des nouveaux tickets
label_settings_post_contact_updates: Mises à jour de contact ?
label_settings_post_contact: Contact ajouté ?
label_settings_post_db_updates: Mises à jour des entrées de base de données ?
label_settings_post_db: Entrée de base de données ajoutée ?
label_settings_post_password_updates: Mises à jour du mot de passe ?
label_settings_post_password: Mot de passe ajouté ?
label_settings_post_private_contacts: Contacts privés ?
label_settings_post_private_db: Entrées de base de données privées ?
label_settings_post_private_issues: Inclure les mises à jour des tickets privés
label_settings_post_private_notes: Inclure les mises à jour des notes privées
label_settings_post_updates: Inclure toutes les mises à jour
label_settings_post_wiki_updates: Inclure les mises à jour du wiki
label_settings_post_wiki: Inclure les publications du wiki
label_settings_updated_include_description: Inclure la description suite à une mise à jour
messenger_channel_info_html: 'Spécifier le canal à utiliser. Vous pouvez définir plusieurs canaux, séparés par une virgule.'
messenger_contacts_intro: Activer les modifications pour les contacts à envoyer au canal Messenger prédéfini.
messenger_db_intro: Activer les modifications pour la base de données à envoyer au canal Messenger prédéfini.
messenger_issue_intro: Activer les modifications pour les tickets à envoyer au canal Messenger prédéfini.
messenger_passwords_intro: Activez les modifications pour les mots de passe devant être envoyés au canal Messenger prédéfini.
messenger_settings_intro: "Laisser l'URL de Messenger dans la zone d'administration vide pour ne pas envoyer de messages de Redmine à Messenger. Peu importe ce que vous avez configuré ici. Si vous souhaitez envoyer des messages de tous les projets Redmine à Messenger, renseignez lURL. Les messages seront envoyés au canal spécifique. Si vous souhaitez uniquement être averti par certains des projets (pas tous), laissez l'URL du messager ici vide et accédez à la configuration du projet spécifique."
messenger_settings_project_intro: "Si vous laissez vide l'URL de Messenger dans la zone d'administration au cas où vous ne seriez pas averti globalement de toutes les modifications apportées au projet, vous pouvez configurer votre URL Messenger dans les paramètres du projet."
messenger_url_info_html: 'Générer une adresse <a target="_blank" href="https://github.com/AlphaNodes/redmine_messenger#prepare-your-messenger-service">Incoming WebHook</a> pour le service global de Messenger. Laisser ce champ vide pour activer uniquement des projets spécifiques avec des paramètres personnalisés pour chaque projet.'
messenger_verify_ssl_info_html: 'Désactiver cette vérification si votre service Messenger utilise un certificat SSL non valide ou auto-signé.'
messenger_wiki_intro: Activer les notifications a envoyer au canal Messenger pour l'ensemble des wikis.
permission_manage_messenger: Gérer Messenger

View File

@@ -0,0 +1,55 @@
# Japanese strings
ja:
default_mentionsl_info: Default people to notify, comma separated (e.g. @all, @here)
label_messenger_contact_created: "%{project_url} - コンタクト %{url} が *%{user}* によって作成されました。"
label_messenger_contact_updated: "%{project_url} - コンタクト %{url} が*%{user}* によって更新されました。"
label_messenger_db_entry_created: "%{project_url} - DB entry %{url} created by *%{user}*"
label_messenger_db_entry_updated: "%{project_url} - DB entry %{url} updated by *%{user}*"
label_messenger_default_not_visible: デフォルトの設定はセキュリティ上の理由により表示されません。
label_messenger_issue_created: "%{project_url} - チケット %{url} が *%{user}* によって作成されました。"
label_messenger_issue_updated: "%{project_url} - チケット %{url} が *%{user}* によって更新されました。"
label_messenger_outgoing_webhook: Outgoing Webhook
label_messenger_password_created: "%{project_url} - Password %{url} created by *%{user}*"
label_messenger_password_updated: "%{project_url} - Password %{url} updated by *%{user}*"
label_messenger_project_text_field_info: デフォルトの設定を使う場合空欄にしてください。
label_messenger_setting: メッセンジャーの設定
label_messenger_settings_default: デフォルト
label_messenger_settings_disabled: 無効
label_messenger_settings_enabled: 有効
label_messenger_wiki_created: "%{project_url} - Wiki %{url} が by *%{user}* によって作成されました。"
label_messenger_wiki_updated: "%{project_url} - Wiki %{url} が *%{user}* によって更新されました。"
label_messenger: メッセンジャー
label_settings_auto_mentions: ユーザー名をその人についての投稿(@ユーザー名)に変換する
label_settings_default_mentions: Default people for mentions
label_settings_display_watchers: ウォッチャーを表示する
label_settings_messenger_channel: メッセンジャーのチャンネル
label_settings_messenger_icon: メッセンジャーのアイコン
label_settings_messenger_url: メッセンジャーのURL
label_settings_messenger_username: メッセンジャーのユーザー名
label_settings_messenger_verify_ssl: SSL証明書の検証
label_settings_new_include_description: チケット作成時に説明を含める
label_settings_post_contact_updates: コンタクトの更新
label_settings_post_contact: コンタクトの作成
label_settings_post_db_updates: DB entry updates?
label_settings_post_db: DB entry added?
label_settings_post_password_updates: Password updates?
label_settings_post_password: Password added?
label_settings_post_private_contacts: Private contacts?
label_settings_post_private_db: Private DB entries?
label_settings_post_private_issues: プライベートチケットの更新
label_settings_post_private_notes: プライベート注記の更新
label_settings_post_updates: チケットの更新
label_settings_post_wiki_updates: Wikiの更新
label_settings_post_wiki: Wikiの作成
label_settings_updated_include_description: チケット更新時に説明を含める
messenger_channel_info_html: チャンネルを指定する必要があります。複数のチャンネルを指定する場合は,(カンマ)で区切って下さい。
messenger_contacts_intro: メッセンジャーに送信するチケットのイベントにチェックを入れて下さい。
messenger_db_intro: Activate the changes for DB that should be sent to the pre-defined Messenger channel.
messenger_issue_intro: メッセンジャーに送信するチケットのイベントにチェックを入れて下さい。
messenger_passwords_intro: Activate the changes for Passwords that should be sent to the pre-defined Messenger channel.
messenger_settings_intro: 管理画面でメッセンジャーのURLを指定した場合、全てのプロジェクトのデフォルトの送信先になります。プロジェクト毎の送信先を設定する場合はプロジェクトの設定画面で設定して下さい。
messenger_settings_project_intro: メッセンジャーのURLを指定しない場合、管理者が指定したチャンネルにメッセージが送信されます。(管理者がチャンネルを指定していない場合は、空欄にすると機能は無効になります)
messenger_url_info_html: 'メッセンジャー サービスで <a target="_blank" href="https://github.com/AlphaNodes/redmine_messenger#prepare-your-messenger-service">内向きのウェブフック</a>のURLを作成して下さい。プロジェクト毎に設定を変えたい場合は空欄として下さい。'
messenger_verify_ssl_info_html: 'メッセンジャー サービスが自己署名証明書や不正な証明書を使っている場合、無効として下さい。'
messenger_wiki_intro: メッセンジャーに送信するWikiのイベントにチェックを入れて下さい。
permission_manage_messenger: メッセンジャーの管理

View File

@@ -0,0 +1,55 @@
# Korean strings
ko:
default_mentionsl_info: 알림을 받을 기본 사용자를 나타내며, 쉼표로 구분 (e.g. @all, @here)
label_messenger_contact_created: "%{project_url} - *%{user}*님이 연락처(%{url})를 만들었습니다."
label_messenger_contact_updated: "%{project_url} - *%{user}*님이 연락처(%{url})를 수정했습니다."
label_messenger_db_entry_created: "%{project_url} - *%{user}*님이 데이터베이스 항목(%{url})을 만들었습니다."
label_messenger_db_entry_updated: "%{project_url} - *%{user}*님이 데이터베이스 항목(%{url})을 수정했습니다."
label_messenger_default_not_visible: 보안 상의 이유로 기본값이 보여지지 않습니다.
label_messenger_issue_created: "%{project_url} - *%{user}*님이 일감(%{url})을 만들었습니다."
label_messenger_issue_updated: "%{project_url} - *%{user}*님이 일감(%{url})을 수정했습니다."
label_messenger_outgoing_webhook: 웹훅 발신
label_messenger_password_created: "%{project_url} - *%{user}*님이 암호(%{url})를 만들었습니다."
label_messenger_password_updated: "%{project_url} - *%{user}*님이 암호(%{url})를 수정했습니다."
label_messenger_project_text_field_info: 시스템 기본값을 사용하려면 빈 값으로 두세요.
label_messenger_setting: 메신저 설정
label_messenger_settings_default: 시스템 기본값
label_messenger_settings_disabled: 비활성화
label_messenger_settings_enabled: 활성화
label_messenger_wiki_created: "%{project_url} - *%{user}*님이 위키(%{url})를 만들었습니다."
label_messenger_wiki_updated: "%{project_url} - *%{user}*님이 위키(%{url})를 수정했습니다."
label_messenger: 메신저
label_settings_auto_mentions: 이름을 멘션으로 변환
label_settings_default_mentions: 멘션될 기본 사용자
label_settings_display_watchers: 지켜보는 사용자들을 보여줌
label_settings_messenger_channel: 메신저 채널
label_settings_messenger_icon: 메신저 아이콘
label_settings_messenger_url: 메신저 URL
label_settings_messenger_username: 메신저 사용자 이름
label_settings_messenger_verify_ssl: SSL
label_settings_new_include_description: 새로운 이슈의 설명을 포함
label_settings_post_contact_updates: 연락처 수정
label_settings_post_contact: 연락처 추가
label_settings_post_db_updates: 데이터베이스 항목 수정
label_settings_post_db: 데이터베이스 항목 추가
label_settings_post_password_updates: 암호 수정
label_settings_post_password: 암호 추가
label_settings_post_private_contacts: 비공개 연락처를 포함
label_settings_post_private_db: 비공개 데이터베이스 항목을 포함
label_settings_post_private_issues: 비공개 일감을 포함
label_settings_post_private_notes: 비공개 노트를 포함
label_settings_post_updates: 일감 수정
label_settings_post_wiki_updates: 위키 수정
label_settings_post_wiki: 위키 추가
label_settings_updated_include_description: 수정된 일감의 설명을 포함
messenger_channel_info_html: '메시지를 보낼 채널들을 선택합니다. 쉼표로 구분하여 여러 채널을 선택할 수 있습니다.'
messenger_contacts_intro: 사전에 정의된 메신저 채널로 연락처의 변경 사항을 보냅니다.
messenger_db_intro: 사전에 정의된 메신저 채널로 데이터베이스의 변경 사항을 보냅니다.
messenger_issue_intro: 사전에 정의된 메신저 채널로 일감의 변경 사항을 보냅니다.
messenger_passwords_intro: 사전에 정의된 메신저 채널로 암호의 변경 사항을 보냅니다.
messenger_settings_intro: "레드마인에서 메신저로 메시지를 보내지 않으려면 플러그인 관리 페이지에서 메신저 URL을 빈 값으로 둡니다. 여기에서 설정을 하면 모든 레드마인 프로젝트의 메시지들이 여기에서 설정된 URL의 지정된 채널로 전달됩니다. 일부 프로젝트에 대해서만 전달되게 하고 싶다면 여기에선 URL을 빈 값으로 두고 각 프로젝트에서 설정합니다."
messenger_settings_project_intro: "플러그인 관리 페이지에서 메신저 URL을 빈 값으로 두면 각 프로젝트 설정에서 메신저 URL을 설정함으로써 모든 프로젝트의 변경을 전역적으로 수신하지 않게 됩니다."
messenger_url_info_html: '메신저 서비스에서 <a target="_blank" href="https://github.com/AlphaNodes/redmine_messenger#prepare-your-messenger-service">Incoming WebHook</a> URL을 만드세요. 전역 설정을 따르려면 빈 값으로 둡니다.'
messenger_verify_ssl_info_html: '메신저 서비스가 유효하지 않거나 자가 서명된 SSL 인증서를 사용한다면 비활성화하세요.'
messenger_wiki_intro: 사전에 정의된 메신저 채널로 위키의 변경 사항을 보냅니다.
permission_manage_messenger: 메신저 관리

View File

@@ -0,0 +1,57 @@
# Dutch strings
nl:
default_mentionsl_info: Standaard gebruikers om op de hoogte te stellen, gescheiden door een komma (e.g. @all, @here)
label_messenger_contact_created: "%{project_url} - Contact %{url} aangemaakt door *%{user}*"
label_messenger_contact_updated: "%{project_url} - Contact %{url} bijgewerkt door *%{user}*"
label_messenger_db_entry_created: "%{project_url} - DB entry %{url} aangemaakt door *%{user}*"
label_messenger_db_entry_updated: "%{project_url} - DB entry %{url} bijgewerkt door *%{user}*"
label_messenger_default_not_visible: Standaardwaarde is niet zichtbaar vanwege beveiligingsredenen.
label_messenger_issue_created: "%{project_url} - Issue %{url} aangemaakt door *%{user}*"
label_messenger_issue_updated: "%{project_url} - Issue %{url} bijgewerkt door *%{user}*"
label_messenger_outgoing_webhook: Uitgaande Webhook
label_messenger_password_created: "%{project_url} - Wachtwoord %{url} aangemaakt door *%{user}*"
label_messenger_password_updated: "%{project_url} - Wachtwoord %{url} bijgewerkt door *%{user}*"
label_messenger_project_text_field_info: Laat leeg voor systeeminstelling.
label_messenger_setting: Messenger Instellingen
label_messenger_settings_default: Systeeminstelling
label_messenger_settings_disabled: Uitgeschakeld
label_messenger_settings_enabled: Ingeschakeld
label_messenger_wiki_created: "%{project_url} - Wiki %{url} aangemaakt door *%{user}*"
label_messenger_wiki_updated: "%{project_url} - Wiki %{url} bijgewerkt door *%{user}*"
label_messenger: Messenger
label_settings_auto_mentions: Zet namen om in mentions?
label_settings_default_mentions: Standaardgebuikers voor mentions
label_settings_display_watchers: Geef watchers weer?
label_settings_messenger_channel: Messenger Kanaal
label_settings_messenger_icon: Messenger Icoon
label_settings_messenger_url: Messenger URL
label_settings_messenger_username: Messenger gebruikersnaam
label_settings_messenger_verify_ssl: Verifieer SSL
label_settings_messenger_direct_users_messages: Stuur directe berichten
label_settings_new_include_description: Nieuwe issue beschrijving?
label_settings_post_contact_updates: Contact bijwerkingen?
label_settings_post_contact: Contact aangemaakt?
label_settings_post_db_updates: DB entry bijwerkingen?
label_settings_post_db: DB entry toegevoegd?
label_settings_post_password_updates: Wachtwoord bijwerkingen?
label_settings_post_password: Wachtwoord toegevoegd?
label_settings_post_private_contacts: Private contacten?
label_settings_post_private_db: Private DB entries?
label_settings_post_private_issues: Private issue bijwerkingen?
label_settings_post_private_notes: Private notes bijwerkingen?
label_settings_post_updates: Issue bijwerkingen?
label_settings_post_wiki_updates: Wiki bijwerkingen?
label_settings_post_wiki: Wiki toegevoegd?
label_settings_updated_include_description: Beschrijving in bijwerking issue?
messenger_channel_info_html: 'Hier kun je het kanaal opgeven dat gebruikt moet worden. Meerdere kanalen kunnen worden gebruikt, gescheiden door een komma'
messenger_contacts_intro: Activeer de bijwerkingen voor Issues die gestuurd moeten worden naar het van tevoren gekozen kanaal.
messenger_db_intro: Activeer de bijwerkingen van de database die gestuurd moeten worden naar het van tevoren gekozen kanaal.
messenger_issue_intro: Activeer de bijwerkingen voor Issues die gestuurd moeten worden naar het van tevoren gekozen kanaal.
messenger_passwords_intro: Activeer de bijwerkingen voor wachtwoorden die gestuurd moeten worden naar het van tevoren gekozen kanaal.
messenger_settings_intro: "Laat de Messenger-URL in het beheergedeelte leeg om geen berichten van Redmine naar de Messenger te sturen. Het maakt niet uit wat je hier nog meer hebt geconfigureerd. Als je berichten van alle Redmine-projecten naar de Messenger wilt sturen, vul dan de URL in. De berichten worden naar het specifieke kanaal gestuurd. Als je alleen door enkele van de projecten (niet alle) op de hoogte wilt worden gehouden, laat u de messenger-URL hier leeg en gebruik de specifieke projectconfiguratie."
messenger_settings_project_intro: "Als u de Messenger-URL in het beheergedeelte leeg hebt gelaten voor het geval je niet wereldwijd op de hoogte wordt gesteld door alle projectwijzigingen, kun je de Messenger-URL configureren in de projectinstellingen."
messenger_url_info_html: 'Genereer een <a target="_blank" href="https://github.com/AlphaNodes/redmine_messenger#prepare-your-messenger-service">Inkomende WebHook</a> URL van de messenger service. Laat het leeg als u alleen specifieke projecten wilt activeren met projectgebaseerde instellingen'
messenger_verify_ssl_info_html: 'Als je Messenger-service een ongeldig of zelfondertekend SSL-certificaat gebruikt, schakel deze checkbox uit.'
messenger_direct_users_messages_info_html: 'Indien ingeschakeld, zal Messenger http-verzoeken naar elke gebruiker plaatsen als kanaal (direct bericht in RocketChat) samen met een bericht in het kanaal'
messenger_wiki_intro: "Activeer de wijzigingen voor Wiki's die naar het vooraf gedefinieerde Messenger-kanaal moeten worden verzonden."
permission_manage_messenger: Beheer messenger

View File

@@ -0,0 +1,57 @@
# Brazilian Portuguese strings
pt-BR:
default_mentionsl_info: "Pessoas a notificar, separadas por vírgula (ex: @all, @here)"
label_messenger_contact_created: "%{project_url} - Contato %{url} criado por *%{user}*"
label_messenger_contact_updated: "%{project_url} - Contato %{url} atualizado por *%{user}*"
label_messenger_db_entry_created: "%{project_url} - Entrada de dado %{url} criada por *%{user}*"
label_messenger_db_entry_updated: "%{project_url} - Entrada de dado %{url} editada por *%{user}*"
label_messenger_default_not_visible: Configuração padrão não é viível por razões de segurança.
label_messenger_issue_created: "%{project_url} - Tarefa %{url} criada por *%{user}*"
label_messenger_issue_updated: "%{project_url} - Tarefa %{url} editada por *%{user}*"
label_messenger_outgoing_webhook: Webhook de saída
label_messenger_password_created: "%{project_url} - Senha %{url} criada por *%{user}*"
label_messenger_password_updated: "%{project_url} - Password %{url} updated by *%{user}*"
label_messenger_project_text_field_info: Deixe em branco para usar o padrão.
label_messenger_setting: Configurações do Messenger
label_messenger_settings_default: Configurações Padrão
label_messenger_settings_disabled: Desabilitado
label_messenger_settings_enabled: Habilitado
label_messenger_wiki_created: "%{project_url} - Wiki %{url} criado por *%{user}*"
label_messenger_wiki_updated: "%{project_url} - Wiki %{url} criado por *%{user}*"
label_messenger: Messenger
label_settings_auto_mentions: Converter nomes em menções?
label_settings_default_mentions: Pessoas padrão para menções
label_settings_display_watchers: Mostrar observadores?
label_settings_messenger_channel: Messenger - Canal
label_settings_messenger_icon: Messenger - Ícone
label_settings_messenger_url: Messenger - URL
label_settings_messenger_username: Messenger - nome de usuário
label_settings_messenger_verify_ssl: Verificar SSL
label_settings_messenger_direct_users_messages: Enviar mensagens diretas
label_settings_new_include_description: Descrição de novas tarefas?
label_settings_post_contact_updates: Edições de contato?
label_settings_post_contact: Contato adicionado?
label_settings_post_db_updates: Modificações de entrada BD?
label_settings_post_db: Nova entrada no BD?
label_settings_post_password_updates: Modificações de senha?
label_settings_post_password: Nova senha?
label_settings_post_private_contacts: Contatos privados?
label_settings_post_private_db: Entradas privadas BD?
label_settings_post_private_issues: Modificações em tarefas privadas?
label_settings_post_private_notes: Modificações em notas privadas?
label_settings_post_updates: Atualizações de tarefa?
label_settings_post_wiki_updates: Atualizações de Wiki?
label_settings_post_wiki: Novo post no Wiki?
label_settings_updated_include_description: Descrição em atualização de tarefa?
messenger_channel_info_html: 'Aqui você precisa especificar o canal a ser usado. Você pode definir múltiplos canais, separados por vírgula'
messenger_contacts_intro: Ative as modificações de Tarefas que devem ser enviadas para o canal predefinido no Messenger.
messenger_db_intro: Ative as modificações de Tarefas que devem ser enviadas para o canal predefinido no Messenger.
messenger_issue_intro: Ative as modificações de Tarefas que devem ser enviadas para o canal predefinido no Messenger.
messenger_passwords_intro: Ative as modificações de Senha que devem ser enviadas para o canal predefinido no Messenger.
messenger_settings_intro: "Deixe o campo Messenger URL vazio na área de administração para não enviar mensagens do Redmine para o Messenger, independente do que mais você tenha configurado. Caso deseje enviar mensagens de todos projetos do Redmine para o Messenger, informe a URL. As mensagens serão enviadas para o canal especificado. Se você só deseja ser notificado sobre algum(ns) projeto(s) (não todos) deixe o campo URL vazio aqui e vá para as configurações específicas do(s) projeto(s)."
messenger_settings_project_intro: "Se você deixar o campo Messenger URL vazio na área de administração para não ser notificado globalmente sobre todos os projetos, você pode configurar a Messenger URL nas configurações do(s) projeto(s)."
messenger_url_info_html: 'Gere uma URL <a target="_blank" href="https://github.com/AlphaNodes/redmine_messenger#prepare-your-messenger-service">Incoming WebHook</a> a partir do serviço de mensagens. Deixe em branco se você deseja ativar somente projetos específicos, com base nas configurações de projeto'
messenger_verify_ssl_info_html: 'Se o seu serviço Messenger usa um ceftificado SSL inválido ou auto assinado, desabilite.'
messenger_direct_users_messages_info_html: 'Se habilitado, o Messenger fará requisições http post para cada usuário como como um canal (mensagem direta no RocketChat) juntamente ao post no canal'
messenger_wiki_intro: Ative as modificações de Wikis que devem ser enviadas para o canal predefinido no Messenger.
permission_manage_messenger: Gerenciar messenger

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
Rails.application.routes.draw do
resources :projects, only: [] do
resource :messenger_setting, only: %i[show update]
end
end

View File

@@ -0,0 +1,26 @@
---
messenger_url: ''
messenger_icon: 'https://raw.githubusercontent.com/alphanodes/redmine_messenger/master/assets/images/icon.png'
messenger_channel: 'redmine'
messenger_username: 'robot'
messenger_verify_ssl: 1
messenger_direct_users_messages: 0
auto_mentions: 0
default_mentions: ''
display_watchers: 0
post_updates: 1
new_include_description: 1
updated_include_description: 1
post_private_contacts: 0
post_private_db: 0
post_private_issues: 0
post_private_notes: 0
post_wiki: 0
post_wiki_updates: 0
post_db: 0
post_db_updates: 0
post_contact: 0
post_contact_updates: 0
post_password: 0
post_password_updates: 0

View File

@@ -0,0 +1,29 @@
# frozen_string_literal: true
class CreateMessengerSettings < ActiveRecord::Migration[4.2]
def change
create_table :messenger_settings do |t|
t.references :project, null: false, index: true
t.string :messenger_url
t.string :messenger_icon
t.string :messenger_channel
t.string :messenger_username
t.integer :messenger_verify_ssl, default: 0, null: false
t.integer :auto_mentions, default: 0, null: false
t.integer :display_watchers, default: 0, null: false
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 :post_db, default: 0, null: false
t.integer :post_db_updates, default: 0, null: false
t.integer :post_contact, default: 0, null: false
t.integer :post_contact_updates, default: 0, null: false
t.integer :post_password, default: 0, null: false
t.integer :post_password_updates, default: 0, null: false
end
end
end

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddDefaultMentions < ActiveRecord::Migration[4.2]
def change
add_column :messenger_settings, :default_mentions, :string
end
end

View File

@@ -0,0 +1,10 @@
# frozen_string_literal: true
class AddPrivateSettings < ActiveRecord::Migration[4.2]
def change
change_table :messenger_settings, bulk: true do |t|
t.integer :post_private_contacts, default: 0, null: false
t.integer :post_private_db, default: 0, null: false
end
end
end

View File

@@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddDirectMessages < ActiveRecord::Migration[4.2]
def change
add_column :messenger_settings, :messenger_direct_users_messages, :integer, default: 0, null: false
end
end

View File

@@ -0,0 +1,21 @@
# frozen_string_literal: true
loader = RedminePluginKit::Loader.new plugin_id: 'redmine_messenger'
Redmine::Plugin.register :redmine_messenger do
name 'Redmine Messenger'
author 'AlphaNodes GmbH'
url 'https://github.com/alphanodes/redmine_messenger'
author_url 'https://alphanodes.com/'
description 'Messenger integration for Slack, Discord, Rocketchat and Mattermost support'
version RedmineMessenger::VERSION
requires_redmine version_or_higher: '4.2.0'
permission :manage_messenger, projects: :settings, messenger_settings: :update
settings default: loader.default_settings, partial: 'settings/messenger_settings'
end
RedminePluginKit::Loader.persisting { loader.load_model_hooks! }
RedminePluginKit::Loader.to_prepare { RedmineMessenger.setup! } if Rails.version < '6.0'

View File

@@ -0,0 +1,33 @@
# frozen_string_literal: true
module RedmineMessenger
VERSION = '1.0.15'
REDMINE_CONTACTS_SUPPORT = Redmine::Plugin.installed? 'redmine_contacts'
REDMINE_DB_SUPPORT = Redmine::Plugin.installed? 'redmine_db'
include RedminePluginKit::PluginBase
class << self
private
def setup
# Patches
loader.add_patch %w[Issue
Project
WikiPage]
loader.add_patch 'Contact' if RedmineMessenger::REDMINE_CONTACTS_SUPPORT
loader.add_patch 'DbEntry' if RedmineMessenger::REDMINE_DB_SUPPORT
loader.add_patch 'Password' if Redmine::Plugin.installed? 'redmine_passwords'
# Helper
loader.add_helper [{ controller: 'Projects', helper: 'MessengerProjects' }]
# Global helpers
loader.add_global_helper RedmineMessenger::Helpers
# Apply patches and helper
loader.apply!
end
end
end

View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
module RedmineMessenger
module Helpers
def project_messenger_options(active)
options_for_select({ l(:label_messenger_settings_default) => '0',
l(:label_messenger_settings_disabled) => '1',
l(:label_messenger_settings_enabled) => '2' }, active)
end
def project_setting_messenger_default_value(value)
if Messenger.default_project_setting @project, value
l :label_messenger_settings_enabled
else
l :label_messenger_settings_disabled
end
end
end
end

View File

@@ -0,0 +1,65 @@
# frozen_string_literal: true
module RedmineMessenger
module Hooks
class ModelHook < Redmine::Hook::Listener
def after_plugins_loaded(_context = {})
return if Rails.version < '6.0'
RedmineMessenger.setup!
end
def model_changeset_scan_commit_for_issue_ids_pre_issue_update(context = {})
issue = context[:issue]
journal = issue.current_journal
changeset = context[:changeset]
channels = Messenger.channels_for_project issue.project
url = Messenger.url_for_project issue.project
return unless channels.present? && url && issue.changes.any? && Messenger.setting_for_project(issue.project, :post_updates)
return if issue.is_private? && !Messenger.setting_for_project(issue.project, :post_private_issues)
msg = "[#{Messenger.markup_format issue.project}] " \
"#{Messenger.markup_format journal.user.to_s} updated <#{Messenger.object_url issue}|#{Messenger.markup_format 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}|#{Messenger.markup_format changeset.comments}>")
attachment[:fields] = journal.details.map { |d| Messenger.detail_to_field d }
Messenger.speak msg, channels, url, attachment: attachment, project: repository.project
end
end
end
end

View File

@@ -0,0 +1,64 @@
# frozen_string_literal: true
module RedmineMessenger
module Patches
module ContactPatch
extend ActiveSupport::Concern
included do
include InstanceMethods
after_create_commit :send_messenger_create
after_update_commit :send_messenger_update
end
module InstanceMethods
def send_messenger_create
return unless Messenger.setting_for_project project, :post_contact
return if is_private? && !Messenger.setting_for_project(project, :post_private_contacts)
channels = Messenger.channels_for_project project
url = Messenger.url_for_project project
return unless channels.present? && url
initial_language = ::I18n.locale
begin
set_language_if_valid Setting.default_language
Messenger.speak l(:label_messenger_contact_created,
project_url: Messenger.project_url_markdown(project),
url: Messenger.url_markdown(self, name),
user: User.current),
channels, url, project: project
ensure
::I18n.locale = initial_language
end
end
def send_messenger_update
return unless Messenger.setting_for_project project, :post_contact_updates
return if is_private? && !Messenger.setting_for_project(project, :post_private_contacts)
channels = Messenger.channels_for_project project
url = Messenger.url_for_project project
return unless channels.present? && url
initial_language = ::I18n.locale
begin
set_language_if_valid Setting.default_language
Messenger.speak l(:label_messenger_contact_updated,
project_url: Messenger.project_url_markdown(project),
url: Messenger.url_markdown(self, name),
user: User.current),
channels, url, project: project
ensure
::I18n.locale = initial_language
end
end
end
end
end
end

View File

@@ -0,0 +1,64 @@
# frozen_string_literal: true
module RedmineMessenger
module Patches
module DbEntryPatch
extend ActiveSupport::Concern
included do
include InstanceMethods
after_create_commit :send_messenger_create
after_update_commit :send_messenger_update
end
module InstanceMethods
def send_messenger_create
return unless Messenger.setting_for_project project, :post_db
return if is_private? && !Messenger.setting_for_project(project, :post_private_db)
channels = Messenger.channels_for_project project
url = Messenger.url_for_project project
return unless channels.present? && url
initial_language = ::I18n.locale
begin
set_language_if_valid Setting.default_language
Messenger.speak l(:label_messenger_db_entry_created,
project_url: Messenger.project_url_markdown(project),
url: Messenger.url_markdown(self, name),
user: User.current),
channels, url, project: project
ensure
::I18n.locale = initial_language
end
end
def send_messenger_update
return unless Messenger.setting_for_project project, :post_db_updates
return if is_private? && !Messenger.setting_for_project(project, :post_private_db)
channels = Messenger.channels_for_project project
url = Messenger.url_for_project project
return unless channels.present? && url
initial_language = ::I18n.locale
begin
set_language_if_valid Setting.default_language
Messenger.speak l(:label_messenger_db_entry_updated,
project_url: Messenger.project_url_markdown(project),
url: Messenger.url_markdown(self, name),
user: User.current),
channels, url, project: project
ensure
::I18n.locale = initial_language
end
end
end
end
end
end

View File

@@ -0,0 +1,141 @@
# frozen_string_literal: true
module RedmineMessenger
module Patches
module IssuePatch
extend ActiveSupport::Concern
included do
include InstanceMethods
after_create_commit :send_messenger_create
after_update_commit :send_messenger_update
end
module InstanceMethods
def send_messenger_create
channels = Messenger.channels_for_project project
url = Messenger.url_for_project project
if Messenger.setting_for_project project, :messenger_direct_users_messages
messenger_to_be_notified.each do |user|
channels.append "@#{user.login}" unless user == author
end
end
return unless channels.present? && url
return if is_private? && !Messenger.setting_for_project(project, :post_private_issues)
initial_language = ::I18n.locale
begin
set_language_if_valid Setting.default_language
attachment = {}
if description.present? && Messenger.setting_for_project(project, :new_include_description)
attachment[:text] = Messenger.markup_format description
end
attachment[:fields] = [{ title: I18n.t(:field_status),
value: Messenger.markup_format(status.to_s),
short: true },
{ title: I18n.t(:field_priority),
value: Messenger.markup_format(priority.to_s),
short: true }]
if assigned_to.present?
attachment[:fields] << { title: I18n.t(:field_assigned_to),
value: Messenger.markup_format(assigned_to.to_s),
short: true }
end
attachments.each do |att|
attachment[:fields] << { title: I18n.t(:label_attachment),
value: "<#{Messenger.object_url att}|#{ERB::Util.html_escape att.filename}>",
short: true }
end
if RedmineMessenger.setting?(:display_watchers) && watcher_users.count.positive?
attachment[:fields] << {
title: I18n.t(:field_watcher),
value: Messenger.markup_format(watcher_users.join(', ')),
short: true
}
end
Messenger.speak l(:label_messenger_issue_created,
project_url: Messenger.project_url_markdown(project),
url: send_messenger_mention_url(project, description),
user: author),
channels, url, attachment: attachment, project: project
ensure
::I18n.locale = initial_language
end
end
def send_messenger_update
return if current_journal.nil?
channels = Messenger.channels_for_project project
url = Messenger.url_for_project project
if Messenger.setting_for_project project, :messenger_direct_users_messages
messenger_to_be_notified.each do |user|
channels.append "@#{user.login}" unless user == current_journal.user
end
end
return unless channels.present? && url && Messenger.setting_for_project(project, :post_updates)
return if is_private? && !Messenger.setting_for_project(project, :post_private_issues)
return if current_journal.private_notes? && !Messenger.setting_for_project(project, :post_private_notes)
initial_language = ::I18n.locale
begin
set_language_if_valid Setting.default_language
attachment = {}
if Messenger.setting_for_project project, :updated_include_description
attachment_text = Messenger.attachment_text_from_journal current_journal
attachment[:text] = attachment_text if attachment_text.present?
end
fields = current_journal.details.map { |d| Messenger.detail_to_field d, project }
if current_journal.notes.present?
fields << { title: I18n.t(:label_comment),
value: Messenger.markup_format(current_journal.notes),
short: false }
end
fields << { title: I18n.t(:field_is_private), short: true } if current_journal.private_notes?
fields.compact!
attachment[:fields] = fields if fields.any?
Messenger.speak l(:label_messenger_issue_updated,
project_url: Messenger.project_url_markdown(project),
url: send_messenger_mention_url(project, description),
user: current_journal.user),
channels, url, attachment: attachment, project: project
ensure
::I18n.locale = initial_language
end
end
private
def messenger_to_be_notified
to_be_notified = (notified_users + notified_watchers).compact
to_be_notified.uniq
end
def send_messenger_mention_url(project, text)
mention_to = ''
if Messenger.setting_for_project(project, :auto_mentions) ||
Messenger.textfield_for_project(project, :default_mentions).present?
mention_to = Messenger.mentions project, text
end
if current_journal.nil?
"<#{Messenger.object_url self}|#{Messenger.markup_format self}>#{mention_to}"
else
"<#{Messenger.object_url self}#change-#{current_journal.id}|#{Messenger.markup_format self}>#{mention_to}"
end
end
end
end
end
end

View File

@@ -0,0 +1,64 @@
# frozen_string_literal: true
module RedmineMessenger
module Patches
module PasswordPatch
extend ActiveSupport::Concern
included do
include InstanceMethods
after_create_commit :send_messenger_create
after_update_commit :send_messenger_update
end
module InstanceMethods
def send_messenger_create
return unless Messenger.setting_for_project project, :post_password
return if is_private?
channels = Messenger.channels_for_project project
url = Messenger.url_for_project project
return unless channels.present? && url
initial_language = ::I18n.locale
begin
set_language_if_valid Setting.default_language
Messenger.speak l(:label_messenger_password_created,
project_url: Messenger.project_url_markdown(project),
url: Messenger.url_markdown(self, name),
user: User.current),
channels, url, project: project
ensure
::I18n.locale = initial_language
end
end
def send_messenger_update
return unless Messenger.setting_for_project project, :post_password_updates
return if is_private?
channels = Messenger.channels_for_project project
url = Messenger.url_for_project project
return unless channels.present? && url
initial_language = ::I18n.locale
begin
set_language_if_valid Setting.default_language
Messenger.speak l(:label_messenger_password_updated,
project_url: Messenger.project_url_markdown(project),
url: Messenger.url_markdown(self, name),
user: User.current),
channels, url, project: project
ensure
::I18n.locale = initial_language
end
end
end
end
end
end

View File

@@ -0,0 +1,13 @@
# frozen_string_literal: true
module RedmineMessenger
module Patches
module ProjectPatch
extend ActiveSupport::Concern
included do
has_one :messenger_setting, dependent: :destroy
end
end
end
end

View File

@@ -0,0 +1,68 @@
# frozen_string_literal: true
module RedmineMessenger
module Patches
module WikiPagePatch
extend ActiveSupport::Concern
included do
include InstanceMethods
after_create_commit :send_messenger_create
after_update_commit :send_messenger_update
end
module InstanceMethods
def send_messenger_create
return unless Messenger.setting_for_project project, :post_wiki
channels = Messenger.channels_for_project project
url = Messenger.url_for_project project
return unless channels.present? && url
initial_language = ::I18n.locale
begin
set_language_if_valid Setting.default_language
Messenger.speak l(:label_messenger_wiki_created,
project_url: Messenger.project_url_markdown(project),
url: Messenger.url_markdown(self, title),
user: User.current),
channels, url, project: project
ensure
::I18n.locale = initial_language
end
end
def send_messenger_update
return unless Messenger.setting_for_project project, :post_wiki_updates
channels = Messenger.channels_for_project project
url = Messenger.url_for_project project
return unless channels.present? && url
initial_language = ::I18n.locale
begin
set_language_if_valid Setting.default_language
attachment = nil
if !content.nil? && content.comments.present?
attachment = {}
attachment[:text] = Messenger.markup_format content.comments.to_s
end
Messenger.speak l(:label_messenger_wiki_updated,
project_url: Messenger.project_url_markdown(project),
url: Messenger.url_markdown(self, title),
user: content.author),
channels, url, project: project, attachment: attachment
ensure
::I18n.locale = initial_language
end
end
end
end
end
end

View File

@@ -0,0 +1,8 @@
{
"dependencies": {},
"devDependencies": {
"eslint": "^8.0.0",
"stylelint": "^14.0.0",
"stylelint-config-standard": "^29.0.0"
}
}

View File

@@ -0,0 +1,41 @@
# frozen_string_literal: true
require File.expand_path '../../test_helper', __FILE__
class CommonViewsTest < Redmine::IntegrationTest
fixtures :projects,
:users,
:roles,
:members,
:member_roles,
:trackers,
:projects_trackers,
:enabled_modules,
:issue_statuses,
:issues,
:enumerations,
:custom_fields,
:custom_values,
:custom_fields_trackers
def setup
RedmineMessenger::TestCase.prepare
end
test 'View user' do
log_user 'admin', 'admin'
get '/users/2'
assert_response :success
end
test 'View issue' do
log_user 'admin', 'admin'
EnabledModule.create project_id: 1, name: 'issue_tracking'
issue = Issue.where(id: 1).first
issue.save
get '/issues/1'
assert_response :success
end
end

View File

@@ -0,0 +1,10 @@
# frozen_string_literal: true
require File.expand_path '../../test_helper', __FILE__
class RoutingTest < Redmine::RoutingTest
test 'routing messenger' do
should_route 'GET /projects/1/settings/messenger' => 'projects#settings', id: '1', tab: 'messenger'
should_route 'PUT /projects/1/messenger_setting' => 'messenger_settings#update', project_id: '1'
end
end

View File

@@ -0,0 +1,6 @@
# = Redmine configuration file
# default configuration options for all environments
default:
sudo_mode: false
sudo_mode_timeout: 1

View File

@@ -0,0 +1,8 @@
test:
adapter: mysql2
database: redmine
port: <%= ENV["MYSQL_PORT"] %>
host: 127.0.0.1
username: root
password: BestPasswordEver
encoding: utf8mb4

View File

@@ -0,0 +1,23 @@
production:
adapter: postgresql
host: localhost
database: redmine
username: postgres
password: postgres
encoding: utf8
development:
adapter: postgresql
host: localhost
database: redmine
username: postgres
password: postgres
encoding: utf8
test:
adapter: postgresql
host: localhost
database: redmine
username: postgres
password: postgres
encoding: utf8

View File

@@ -0,0 +1,28 @@
# frozen_string_literal: true
if ENV['COVERAGE']
require 'simplecov'
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"
module RedmineMessenger
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

View File

@@ -0,0 +1,39 @@
# frozen_string_literal: true
require File.expand_path '../../test_helper', __FILE__
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_messenger/config/locales/*.yml')].size
assert_equal 7, lang_files_count
valid_languages.each do |lang|
assert set_language_if_valid(lang)
case lang.to_s
when 'en'
assert_equal 'Messenger username', l(:label_settings_messenger_username)
when 'de', 'fr', 'ja', 'ko', 'pt-BR'
assert_not l(:label_settings_messenger_username) == 'Messenger username', lang
end
end
set_language_if_valid 'en'
end
end

View File

@@ -0,0 +1,32 @@
# frozen_string_literal: true
require File.expand_path '../../test_helper', __FILE__
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_save issue
assert_equal issue.tracker.default_status, issue.status
assert_nil issue.description
end
end

View File

@@ -0,0 +1,40 @@
# frozen_string_literal: true
require File.expand_path '../../test_helper', __FILE__
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