Merge branch 'dev' into feature/feature-flag-module-storages-active

pull/10417/head
Christophe Bliard 3 years ago committed by GitHub
commit 94e68bc951
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .editorconfig
  2. 6
      Gemfile
  3. 33
      Gemfile.lock
  4. 1
      app/contracts/queries/base_contract.rb
  5. 4
      app/controllers/admin/settings/aggregation_settings_controller.rb
  6. 2
      app/controllers/admin/settings/api_settings_controller.rb
  7. 5
      app/helpers/settings_helper.rb
  8. 2
      app/models/auth_source.rb
  9. 21
      app/models/ldap_auth_source.rb
  10. 2
      app/models/project.rb
  11. 27
      app/models/queries/work_packages/filter/project_filter.rb
  12. 4
      app/models/queries/work_packages/filter/status_filter.rb
  13. 6
      app/models/query.rb
  14. 6
      app/models/query/results.rb
  15. 14
      app/models/setting.rb
  16. 6
      app/seeders/basic_data/setting_seeder.rb
  17. 3
      app/seeders/demo_data/query_builder.rb
  18. 1
      app/seeders/demo_data/work_package_board_seeder.rb
  19. 2
      app/services/api/parse_resource_params_service.rb
  20. 42
      app/services/api/parser_struct.rb
  21. 2
      app/services/base_services/set_attributes.rb
  22. 103
      app/services/ldap/base_service.rb
  23. 30
      app/services/ldap/import_users_from_filter_service.rb
  24. 35
      app/services/ldap/import_users_from_list_service.rb
  25. 46
      app/services/ldap/synchronize_users_service.rb
  26. 30
      app/services/queries/create_service.rb
  27. 35
      app/services/queries/set_attributes_service.rb
  28. 2
      app/views/admin/index.html.erb
  29. 12
      app/views/admin/settings/aggregation_settings/show.html.erb
  30. 2
      app/views/admin/settings/api_settings/show.html.erb
  31. 49
      app/workers/ldap/synchronization_job.rb
  32. 5
      config/constants/settings/definition.rb
  33. 3
      config/initializers/cronjobs.rb
  34. 28
      config/initializers/menus.rb
  35. 3
      config/locales/crowdin/js-af.yml
  36. 3
      config/locales/crowdin/js-ar.yml
  37. 3
      config/locales/crowdin/js-az.yml
  38. 3
      config/locales/crowdin/js-bg.yml
  39. 3
      config/locales/crowdin/js-ca.yml
  40. 3
      config/locales/crowdin/js-cs.yml
  41. 3
      config/locales/crowdin/js-da.yml
  42. 3
      config/locales/crowdin/js-de.yml
  43. 3
      config/locales/crowdin/js-el.yml
  44. 3
      config/locales/crowdin/js-eo.yml
  45. 3
      config/locales/crowdin/js-es.yml
  46. 3
      config/locales/crowdin/js-et.yml
  47. 3
      config/locales/crowdin/js-fa.yml
  48. 3
      config/locales/crowdin/js-fi.yml
  49. 3
      config/locales/crowdin/js-fil.yml
  50. 3
      config/locales/crowdin/js-fr.yml
  51. 3
      config/locales/crowdin/js-he.yml
  52. 3
      config/locales/crowdin/js-hi.yml
  53. 3
      config/locales/crowdin/js-hr.yml
  54. 3
      config/locales/crowdin/js-hu.yml
  55. 3
      config/locales/crowdin/js-id.yml
  56. 3
      config/locales/crowdin/js-it.yml
  57. 3
      config/locales/crowdin/js-ja.yml
  58. 3
      config/locales/crowdin/js-ko.yml
  59. 3
      config/locales/crowdin/js-lol.yml
  60. 1
      config/locales/crowdin/js-lt.yml
  61. 3
      config/locales/crowdin/js-lv.yml
  62. 3
      config/locales/crowdin/js-ne.yml
  63. 3
      config/locales/crowdin/js-nl.yml
  64. 3
      config/locales/crowdin/js-no.yml
  65. 3
      config/locales/crowdin/js-pl.yml
  66. 3
      config/locales/crowdin/js-pt.yml
  67. 3
      config/locales/crowdin/js-ro.yml
  68. 1
      config/locales/crowdin/js-ru.yml
  69. 3
      config/locales/crowdin/js-rw.yml
  70. 3
      config/locales/crowdin/js-si.yml
  71. 3
      config/locales/crowdin/js-sk.yml
  72. 3
      config/locales/crowdin/js-sl.yml
  73. 3
      config/locales/crowdin/js-sv.yml
  74. 3
      config/locales/crowdin/js-th.yml
  75. 3
      config/locales/crowdin/js-tr.yml
  76. 3
      config/locales/crowdin/js-uk.yml
  77. 3
      config/locales/crowdin/js-vi.yml
  78. 3
      config/locales/crowdin/js-zh-TW.yml
  79. 6
      config/locales/crowdin/lt.yml
  80. 11
      config/locales/en.yml
  81. 35
      config/locales/js-en.yml
  82. 3
      config/routes.rb
  83. 14
      db/migrate/20220323083000_add_include_subprojects_to_query.rb
  84. 4
      docker/dev/backend/Dockerfile
  85. 3
      docs/api/apiv3/tags/configuration.yml
  86. 35
      docs/development/saml/README.md
  87. 44
      docs/system-admin-guide/README.md
  88. 24
      docs/system-admin-guide/authentication/saml/README.md
  89. 26
      docs/system-admin-guide/incoming-and-outgoing/README.md
  90. 4
      docs/system-admin-guide/users-permissions/README.md
  91. 2
      docs/system-admin-guide/users-permissions/avatars/README.md
  92. 2
      docs/system-admin-guide/users-permissions/groups/README.md
  93. 2
      docs/system-admin-guide/users-permissions/placeholder-users/README.md
  94. 2
      docs/system-admin-guide/users-permissions/roles-permissions/README.md
  95. 4
      docs/system-admin-guide/users-permissions/users-permissions-faq/README.md
  96. 2
      docs/system-admin-guide/users-permissions/users/README.md
  97. 2
      docs/user-guide/time-and-costs/time-tracking/README.md
  98. 13
      frontend/src/app/core/global_search/tabs/global-search-tabs.component.ts
  99. 4
      frontend/src/app/features/homescreen/blocks/new-features.component.ts
  100. 7
      frontend/src/app/features/team-planner/team-planner/calendar-drag-drop.service.ts
  101. Some files were not shown because too many files have changed in this diff Show More

@ -291,9 +291,6 @@ ij_javascript_while_on_new_line = false
ij_javascript_wrap_comments = false
[{*.sht,*.html,*.shtm,*.shtml,*.htm,*.ng}]
indent_size = 2
tab_width = 2
ij_continuation_indent_size = 2
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
ij_html_align_attributes = true
ij_html_align_text = false

@ -32,11 +32,13 @@ ruby '~> 3.0.3'
gem 'actionpack-xml_parser', '~> 2.0.0'
gem 'activemodel-serializers-xml', '~> 1.0.1'
gem 'activerecord-import', '~> 1.3.0'
gem 'activerecord-import', '~> 1.4.0'
gem 'activerecord-session_store', '~> 2.0.0'
gem 'rails', '~> 6.1.4', '>= 6.1.4.6'
gem 'responders', '~> 3.0'
gem 'ffi', '~> 1.15'
gem 'rdoc', '>= 2.4.2'
gem 'doorkeeper', '~> 5.5.0'
@ -135,7 +137,7 @@ gem 'okcomputer', '~> 1.18.1'
gem 'gon', '~> 6.4.0'
# Lograge to provide sane and non-verbose logging
gem 'lograge', '~> 0.11.0'
gem 'lograge', '~> 0.12.0'
# Structured warnings to selectively disable them in production
gem 'structured_warnings', '~> 0.4.0'

@ -241,7 +241,7 @@ GEM
activerecord (6.1.5)
activemodel (= 6.1.5)
activesupport (= 6.1.5)
activerecord-import (1.3.0)
activerecord-import (1.4.0)
activerecord (>= 4.2)
activerecord-nulldb-adapter (0.8.0)
activerecord (>= 5.2.0, < 7.1)
@ -283,7 +283,7 @@ GEM
awesome_nested_set (3.5.0)
activerecord (>= 4.0.0, < 7.1)
aws-eventstream (1.2.0)
aws-partitions (1.568.0)
aws-partitions (1.573.0)
aws-sdk-core (3.130.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
@ -453,7 +453,7 @@ GEM
tzinfo
eventmachine (1.2.7)
eventmachine_httpserver (0.2.1)
excon (0.92.0)
excon (0.92.2)
factory_bot (6.2.1)
activesupport (>= 5.0.0)
factory_bot_rails (6.2.0)
@ -507,8 +507,8 @@ GEM
formatador (1.1.0)
friendly_id (5.4.2)
activerecord (>= 4.0.0)
fugit (1.5.2)
et-orbi (~> 1.1, >= 1.1.8)
fugit (1.5.3)
et-orbi (~> 1, >= 1.2.7)
raabro (~> 1.4)
fuubar (2.5.1)
rspec-core (~> 3.0)
@ -537,7 +537,7 @@ GEM
hashdiff (1.0.1)
hashery (2.1.2)
hashie (3.6.0)
html-pipeline (2.14.0)
html-pipeline (2.14.1)
activesupport (>= 2)
nokogiri (>= 1.4)
htmldiff (0.0.1)
@ -548,7 +548,7 @@ GEM
httpclient (2.8.3)
i18n (1.10.0)
concurrent-ruby (~> 1.0)
i18n-js (3.9.1)
i18n-js (3.9.2)
i18n (>= 0.6.6)
icalendar (2.7.1)
ice_cube (~> 0.16)
@ -561,7 +561,7 @@ GEM
activesupport (>= 4.2)
aes_key_wrap
bindata
json_schemer (0.2.19)
json_schemer (0.2.20)
ecma-re-validator (~> 0.3)
hana (~> 1.3)
regexp_parser (~> 2.0)
@ -569,7 +569,7 @@ GEM
json_spec (1.1.5)
multi_json (~> 1.0)
rspec (>= 2.0, < 4.0)
kramdown (2.3.1)
kramdown (2.3.2)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
@ -593,12 +593,12 @@ GEM
omniauth (~> 1.1)
omniauth-openid-connect (>= 0.2.1)
rails (>= 3.2.21)
lograge (0.11.2)
lograge (0.12.0)
actionpack (>= 4)
activesupport (>= 4)
railties (>= 4)
request_store (~> 1.0)
loofah (2.15.0)
loofah (2.16.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
@ -667,7 +667,7 @@ GEM
hashery (~> 2.0)
ruby-rc4
ttfunk
pg (1.3.4)
pg (1.3.5)
plaintext (0.3.4)
activesupport (> 2.2.1)
nokogiri (~> 1.10, >= 1.10.4)
@ -707,7 +707,7 @@ GEM
eventmachine_httpserver
http_parser.rb (~> 0.6.0)
multi_json
puma (5.6.2)
puma (5.6.4)
nio4r (~> 2.0)
puma-plugin-statsd (2.1.0)
puma (>= 5.0, < 6)
@ -812,7 +812,7 @@ GEM
rspec-expectations (3.11.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-mocks (3.11.0)
rspec-mocks (3.11.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.11.0)
rspec-rails (5.1.1)
@ -976,7 +976,7 @@ PLATFORMS
DEPENDENCIES
actionpack-xml_parser (~> 2.0.0)
activemodel-serializers-xml (~> 1.0.1)
activerecord-import (~> 1.3.0)
activerecord-import (~> 1.4.0)
activerecord-nulldb-adapter (~> 0.8.0)
activerecord-session_store (~> 2.0.0)
acts_as_list (~> 1.0.1)
@ -1018,6 +1018,7 @@ DEPENDENCIES
factory_bot (~> 6.2.0)
factory_bot_rails (~> 6.2.0)
faker
ffi (~> 1.15)
flamegraph
fog-aws
friendly_id (~> 5.4.0)
@ -1037,7 +1038,7 @@ DEPENDENCIES
letter_opener
listen (~> 3.7.0)
livingstyleguide (~> 2.1.0)
lograge (~> 0.11.0)
lograge (~> 0.12.0)
meta-tags (~> 2.16.0)
mini_magick (~> 4.11.0)
multi_json (~> 1.15.0)

@ -43,6 +43,7 @@ module Queries
attribute :highlighted_attributes
attribute :show_hierarchies
attribute :display_representation
attribute :include_subprojects
attribute :column_names # => columns
attribute :filters

@ -27,7 +27,7 @@
#++
module Admin::Settings
class NotificationsSettingsController < ::Admin::SettingsController
class AggregationSettingsController < ::Admin::SettingsController
current_menu_item [:show] do
:notification_settings
end
@ -37,7 +37,7 @@ module Admin::Settings
end
def default_breadcrumb
t(:'menus.admin.incoming_outgoing')
t(:'menus.admin.aggregation_and_retention')
end
def show_local_breadcrumb

@ -28,7 +28,7 @@
module Admin::Settings
class APISettingsController < ::Admin::SettingsController
menu_item :settings_api
menu_item :api
def default_breadcrumb
t(:label_api_access_key_type)

@ -54,11 +54,6 @@ module SettingsHelper
controller: '/admin/settings/attachments_settings',
label: :'attributes.attachments'
},
{
name: 'api',
controller: '/admin/settings/api_settings',
label: :label_api_access_key_type
},
{
name: 'repositories',
controller:'/admin/settings/repositories_settings',

@ -29,6 +29,8 @@
class AuthSource < ApplicationRecord
include Redmine::Ciphering
class Error < ::StandardError; end
has_many :users
validates :name,

@ -53,7 +53,7 @@ class LdapAuthSource < AuthSource
attrs.except(:dn)
end
rescue Net::LDAP::Error => e
raise 'LdapError: ' + e.message
raise AuthSource::Error, "LdapError: #{e.message}"
end
def find_user(login)
@ -66,7 +66,7 @@ class LdapAuthSource < AuthSource
attrs.except(:dn)
end
rescue Net::LDAP::Error => e
raise 'LdapError: ' + e.message
raise AuthSource::Error, "LdapError: #{e.message}"
end
# Open and return a system connection
@ -77,10 +77,10 @@ class LdapAuthSource < AuthSource
# test the connection to the LDAP
def test_connection
unless authenticate_dn(account, account_password)
raise I18n.t('auth_source.ldap_error', error_message: I18n.t('auth_source.ldap_auth_failed'))
raise AuthSource::Error, I18n.t('auth_source.ldap_error', error_message: I18n.t('auth_source.ldap_auth_failed'))
end
rescue Net::LDAP::Error => e
raise I18n.t('auth_source.ldap_error', error_message: e.to_s)
raise AuthSource::Error, I18n.t('auth_source.ldap_error', error_message: e.to_s)
end
def auth_method_name
@ -119,6 +119,13 @@ class LdapAuthSource < AuthSource
parsed_filter_string || object_filter
end
##
# Returns the filter object to search for a login
# adding the optional default filter
def login_filter(login)
Net::LDAP::Filter.eq(attr_login, login) & default_filter
end
def parsed_filter_string
Net::LDAP::Filter.from_rfc2254(filter_string) if filter_string.present?
end
@ -162,15 +169,15 @@ class LdapAuthSource < AuthSource
# Get the user's dn and any attributes for them, given their login
def get_user_dn(login)
ldap_con = initialize_ldap_con(account, account_password)
login_filter = Net::LDAP::Filter.eq(attr_login, login)
attrs = {}
filter = login_filter(login)
Rails.logger.debug do
"LDAP initializing search (BASE=#{base_dn}), (FILTER=#{default_filter & login_filter})"
"LDAP initializing search (BASE=#{base_dn}), (FILTER=#{filter})"
end
ldap_con.search(base: base_dn,
filter: default_filter & login_filter,
filter: filter,
attributes: search_attributes) do |entry|
attrs = if onthefly_register?
get_user_attributes_from_ldap_entry(entry)

@ -71,7 +71,7 @@ class Project < ApplicationRecord
}, dependent: :destroy
has_many :time_entries, dependent: :delete_all
has_many :time_entry_activities_projects, dependent: :delete_all
has_many :queries, dependent: :delete_all
has_many :queries, dependent: :destroy
has_many :news, -> { includes(:author) }, dependent: :destroy
has_many :categories, -> { order("#{Category.table_name}.name") }, dependent: :delete_all
has_many :forums, -> { order('position ASC') }, dependent: :destroy

@ -56,16 +56,33 @@ class Queries::WorkPackages::Filter::ProjectFilter < Queries::WorkPackages::Filt
end
def value_objects
available_projects = visible_projects.index_by(&:id)
visible_projects.where(id: values.map(&:to_i))
end
values
.map { |project_id| available_projects[project_id.to_i] }
.compact
def where
operator_strategy.sql_for_field(projects_and_descendants, self.class.model.table_name, :project_id)
end
private
def visible_projects
@visible_projects ||= Project.visible.active
Project.visible.active
end
##
# Depending on whether subprojects are included in the query,
# expand selected projects with its descendants
def projects_and_descendants
value_objects
.inject(Set.new) { |project_set, project| project_set + expand_subprojects(project) }
.map(&:id)
end
def expand_subprojects(selected_project)
if context.include_subprojects?
[selected_project].concat(selected_project.descendants.visible)
else
[selected_project]
end
end
end

@ -65,6 +65,10 @@ class Queries::WorkPackages::Filter::StatusFilter < Queries::WorkPackages::Filte
true
end
def joins
:status
end
private
def all_statuses

@ -45,6 +45,9 @@ class Query < ApplicationRecord
presence: true,
length: { maximum: 255 }
validates :include_subprojects,
inclusion: [true, false]
validate :validate_work_package_filters
validate :validate_columns
validate :validate_sort_criteria
@ -62,6 +65,7 @@ class Query < ApplicationRecord
query.add_default_filter
query.set_default_sort
query.show_hierarchies = true
query.include_subprojects = Setting.display_subprojects_work_packages?
end
end
@ -368,7 +372,7 @@ class Query < ApplicationRecord
subproject_filter = Queries::WorkPackages::Filter::SubprojectFilter.create!
subproject_filter.context = self
subproject_filter.operator = if Setting.display_subprojects_work_packages?
subproject_filter.operator = if include_subprojects?
'*'
else
'!*'

@ -41,9 +41,9 @@ class ::Query::Results
def work_package_count
work_package_scope
.joins(all_filter_joins)
.includes(:status, :project)
.includes(:project)
.where(query.statement)
.references(:statuses, :projects)
.references(:projects)
.count
rescue ::ActiveRecord::StatementInvalid => e
raise ::Query::StatementInvalid.new(e.message)
@ -79,7 +79,7 @@ class ::Query::Results
end
def all_includes
(%i(status project) +
(%i(project) +
includes_for_columns(include_columns)).uniq
end

@ -90,6 +90,12 @@ class Setting < ApplicationRecord
def self.#{name}?
# when running too early, there is no settings table. do nothing
return unless settings_table_exists_yet?
definition = Settings::Definition[:#{name}]
if definition.format != :boolean
ActiveSupport::Deprecation.warn "Calling #{self}.#{name}? is deprecated since it is not a boolean", caller
end
value = self[:#{name}]
ActiveRecord::Type::Boolean.new.cast(value)
end
@ -150,8 +156,12 @@ class Setting < ApplicationRecord
self.class.deserialize(name, read_attribute(:value))
end
def value=(v)
write_attribute(:value, formatted_value(v))
def value=(val)
unless Settings::Definition[name].writable?
raise NoMethodError, "#{name} is not writable but can be set through env vars or configuration.yml file."
end
write_attribute(:value, formatted_value(val))
end
def formatted_value(value)

@ -47,12 +47,12 @@ module BasicData
def data
@settings ||= begin
settings = Setting.definitions.each_with_object({}) do |definition, hash|
settings = Setting.definitions.select(&:writable?).each_with_object({}) do |definition, hash|
hash[definition.name] = definition.value || ''
end
# deviate from the defaults specified in settings.yml here
# to set a default role. The role cannot be specified in the settings.yml as
# deviate from the defaults specified in the settings definition here
# to set a default role. The role cannot be specified in the definition as
# that would mean to know the ID upfront.
update_unless_present(settings, 'new_project_user_role_id') do
Role.find_by(name: I18n.t(:default_role_project_admin)).try(:id)

@ -52,7 +52,8 @@ module DemoData
public: config.fetch(:public, true),
starred: config.fetch(:starred, false),
show_hierarchies: config.fetch(:hierarchy, false),
timeline_visible: config.fetch(:timeline, false)
timeline_visible: config.fetch(:timeline, false),
include_subprojects: true
}
end

@ -160,6 +160,7 @@ module DemoData
Query.new(project: project, user: admin).tap do |query|
# Make it public so that new members can see it too
query.public = true
query.include_subprojects = true
query.name = list[:name]

@ -76,7 +76,7 @@ module API
end
def struct
Hashie::Mash.new
ParserStruct.new
end
def deep_to_h(value)

@ -0,0 +1,42 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2022 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module API
class ParserStruct < ::Hashie::Mash
##
# TODO: Hashie::Mash extends from Hash and
# does not allow overriding any enumerable methods.
#
# This clashed with moving the queries services to BaseContracted,
# as we now use a +group_by+ attribute clashing with +Enumerable#group_by#.
# This redefines the method to ensure it works with queries, but does not solve the underlying issue.
def group_by
self[:group_by]
end
end
end

@ -31,6 +31,8 @@ module BaseServices
include Contracted
def initialize(user:, model:, contract_class:, contract_options: {})
super()
self.user = user
self.model = prepare_model(model)

@ -0,0 +1,103 @@
module Ldap
class BaseService
attr_reader :ldap
def initialize(ldap)
@ldap = ldap
end
def call
User.system.run_given do
OpenProject::Mutex.with_advisory_lock_transaction(ldap, 'import_users') do
perform
end
end
end
def perform
raise NotImplementedError
end
# rubocop:disable Metrics/AbcSize
def synchronize_user(user, ldap_con)
Rails.logger.debug { "[LDAP user sync] Synchronizing user #{user.login}." }
update_attributes = user_attributes(user.login, ldap_con)
if update_attributes.nil? && user.persisted?
Rails.logger.info { "Could not find user #{user.login} in #{ldap.name}. Locking the user." }
user.update_column(:status, Principal.statuses[:locked])
end
return unless update_attributes
if user.new_record?
try_to_create(update_attributes)
else
try_to_update(user, update_attributes)
end
end
# rubocop:enable Metrics/AbcSize
# Try to create the user from attributes
def try_to_update(user, attrs)
call = Users::UpdateService
.new(model: user, user: User.system)
.call(attrs)
if call.success?
# Ensure the user is activated
call.result.update_column(:status, Principal.statuses[:active])
Rails.logger.info { "[LDAP user sync] User '#{call.result.login}' updated." }
else
Rails.logger.error { "[LDAP user sync] User '#{user.login}' could not be updated: #{call.message}" }
end
end
def try_to_create(attrs)
call = Users::CreateService
.new(user: User.system)
.call(attrs)
if call.success?
Rails.logger.info { "[LDAP user sync] User '#{call.result.login}' created." }
else
Rails.logger.error { "[LDAP user sync] User '#{attrs[:login]}' could not be created: #{call.message}" }
end
end
##
# Get the user attributes of a single matching LDAP entry.
#
# If the login matches multiple entries, return nil and issue a warning.
# If the login does not match, returns nil
def user_attributes(login, ldap_con)
# Return the first matching user
entries = find_entries_by(login: login, ldap_con: ldap_con)
if entries.count == 0
Rails.logger.info { "[LDAP user sync] Did not find LDAP entry for #{login}" }
return
end
if entries.count > 1
Rails.logger.warn { "[LDAP user sync] Found multiple entries for #{login}: #{entries.map(&:dn)}. Skipping" }
return
end
entries.first
end
def find_entries_by(login:, ldap_con: new_ldap_connection)
ldap_con
.search(
base: ldap.base_dn,
filter: ldap.login_filter(login),
attributes: ldap.search_attributes(true)
)
.map { |entry| ldap.get_user_attributes_from_ldap_entry(entry).except(:dn) }
end
def new_ldap_connection
ldap.instance_eval { initialize_ldap_con(account, account_password) }
end
end
end

@ -0,0 +1,30 @@
module Ldap
class ImportUsersFromFilterService < BaseService
attr_reader :filter
def initialize(ldap, filter)
super(ldap)
@filter = filter
end
def perform
get_entries_from_filter do |entry|
attributes = ldap.get_user_attributes_from_ldap_entry(entry)
next if User.by_login(attributes[:login]).exists?
try_to_create attributes.except(:dn)
end
end
def get_entries_from_filter(&block)
ldap_con = new_ldap_connection
ldap_con.search(
base: ldap.base_dn,
filter: filter & ldap.default_filter,
attributes: ldap.search_attributes(true),
&block
)
end
end
end

@ -0,0 +1,35 @@
module Ldap
class ImportUsersFromListService < BaseService
attr_reader :logins
def initialize(ldap, logins)
super(ldap)
@logins = logins
end
def perform
new_users = logins - existing_users
Rails.logger.debug { "Importing LDAP user import for #{ldap.name} for #{new_users.count} new users." }
import! new_users
end
def import!(new_users)
ldap_con = new_ldap_connection
new_users.each do |login|
synchronize_user(User.new(login: login), ldap_con)
rescue ::AuthSource::Error => e
Rails.logger.error { "Failed to synchronize user #{ldap.name} due to LDAP error: #{e.message}" }
# Reset the LDAP connection
ldap_con = new_ldap_connection
rescue StandardError => e
Rails.logger.error { "Failed to synchronize user #{ldap.name}: #{e.message}" }
end
end
def existing_users
User.where("LOWER(login) in (?)", logins.map(&:downcase)).pluck(:login)
end
end
end

@ -0,0 +1,46 @@
module Ldap
class SynchronizeUsersService < BaseService
attr_reader :logins
def initialize(ldap, logins = nil)
super(ldap)
@logins = logins
end
def call
Rails.logger.debug { "Start LDAP user synchronization for #{ldap.name}." }
User.system.run_given do
OpenProject::Mutex.with_advisory_lock_transaction(ldap, 'synchronize_users') do
synchronize!
end
end
end
private
def synchronize!
ldap_con = new_ldap_connection
applicable_users.find_each do |user|
synchronize_user(user, ldap_con)
rescue ::AuthSource::Error => e
Rails.logger.error { "Failed to synchronize user #{ldap.name} due to LDAP error: #{e.message}" }
# Reset the LDAP connection
ldap_con = new_ldap_connection
rescue StandardError => e
Rails.logger.error { "Failed to synchronize user #{ldap.name}: #{e.message}" }
end
end
# Get the applicable users
# as the service can be called with just a subset of users
# from rake/external services.
def applicable_users
if logins.present?
ldap.users.where("LOWER(login) in (?)", logins.map(&:downcase))
else
ldap.users
end
end
end
end

@ -26,32 +26,4 @@
# See COPYRIGHT and LICENSE files for more details.
#++
class Queries::CreateService < Queries::BaseService
def initialize(**args)
super(**args)
self.contract_class = Queries::CreateContract
end
def call(query)
remove_invalid_order(query)
super
end
private
def remove_invalid_order(query)
# Check which of the work package IDs exist
ids = query.ordered_work_packages.map(&:work_package_id)
existent_wps = WorkPackage.where(id: ids).pluck(:id).to_set
query.ordered_work_packages = query.ordered_work_packages.select do |order_item|
existent_wps.include?(order_item.work_package_id)
end
end
def service_result(result, errors, query)
query.update user: user
super
end
end
class Queries::CreateService < ::BaseServices::Create; end

@ -26,4 +26,37 @@
# See COPYRIGHT and LICENSE files for more details.
#++
class Queries::SetAttributesService < ::BaseServices::SetAttributes; end
class Queries::SetAttributesService < ::BaseServices::SetAttributes
def set_attributes(params)
set_ordered_work_packages params.delete(:ordered_work_packages)
super
end
def set_default_attributes(_params)
if model.include_subprojects.nil?
model.include_subprojects = Setting.display_subprojects_work_packages?
end
set_default_user
end
def set_default_user
model.change_by_system do
model.user = user
end
end
def set_ordered_work_packages(ordered_hash)
return if ordered_hash.nil?
available = WorkPackage.where(id: ordered_hash.keys.map(&:to_s)).pluck(:id).to_set
ordered_hash.each do |key, position|
# input keys are symbols due to hashie::mash, and AR doesn't like that
wp_id = key.to_s.to_i
next unless available.include?(wp_id.to_s.to_i)
model.ordered_work_packages.build(work_package_id: wp_id, position: position)
end
end
end

@ -34,7 +34,7 @@ See COPYRIGHT and LICENSE files for more details.
<div class="menu-blocks--container">
<% @menu_nodes.each do |menu_node| -%>
<%= link_to menu_node.url, { class: 'menu-block' } do %>
<%= op_icon('menu-block--icon ' + menu_node.icon.gsub(/icon2/, "icon3")) %>
<%= op_icon('menu-block--icon ' + (menu_node.icon || '').gsub(/icon2/, "icon3")) %>
<span class="menu-block--title"> <%= menu_node.caption %> </span>
<% end %>
<% end %>

@ -27,18 +27,22 @@ See COPYRIGHT and LICENSE files for more details.
++#%>
<% html_title t(:label_administration), t(:'menus.admin.incoming_outgoing') -%>
<% html_title t(:label_administration), t(:'menus.admin.aggregation_and_retention') -%>
<%= toolbar title: t(:'menus.admin.incoming_outgoing') %>
<%= toolbar title: t(:'menus.admin.aggregation_and_retention') %>
<%= styled_form_tag(admin_settings_notifications_path, method: :patch) do %>
<%= styled_form_tag(admin_settings_aggregation_path, method: :patch) do %>
<div class="form--field">
<%= setting_number_field :journal_aggregation_time_minutes,
unit: t(:label_minute_plural),
min: 0,
container_class: '-xslim' %>
<span class="form--field-instructions">
<%= t(:text_journal_aggregation_time_explanation) %><br/>
<%= t(:'admin.journal_aggregation.explanation.text',
webhook_link: link_to(t(:'admin.journal_aggregation.explanation.link'),
admin_outgoing_webhooks_path,
target: '_blank')).html_safe %>
<br/>
<%= t(:text_hint_disable_with_0) %>
</span>
</div>

@ -28,7 +28,7 @@ See COPYRIGHT and LICENSE files for more details.
++#%>
<%= toolbar title: t(:label_api_access_key_type) %>
<%= styled_form_tag(admin_settings_update_api_path, method: :patch) do %>
<%= styled_form_tag(admin_settings_api_path, method: :patch) do %>
<section class="form--section">
<div class="form--field">
<%= setting_number_field :apiv3_max_page_size, min: 50, container_class: '-slim' %>

@ -0,0 +1,49 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2022 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See COPYRIGHT and LICENSE files for more details.
#++
module Ldap
class SynchronizationJob < ::Cron::CronJob
# Run once per night at 11:30pm
self.cron_expression = '30 23 * * *'
def perform
run_user_sync
end
private
def run_user_sync
return if OpenProject::Configuration.ldap_users_disable_sync_job?
::LdapAuthSource.find_each do |ldap|
Rails.logger.info { "[LDAP groups] Synchronizing users for LDAP connection #{ldap.name}" }
::Ldap::SynchronizeUsersService.new(ldap).perform
end
end
end
end

@ -83,6 +83,7 @@ module Settings
def override_value(other_value)
if format == :hash
self.value = {} if value.nil?
value.deep_merge! other_value
else
self.value = other_value
@ -151,8 +152,6 @@ module Settings
end
def [](name)
by_name ||= all.group_by(&:name).transform_values(&:first)
by_name[name.to_s]
end
@ -186,7 +185,7 @@ module Settings
end
def by_name
@by_name ||= all.group_by(&:name).transform_values(&:first)
@by_name ||= all.index_by(&:name)
end
def file_config

@ -7,6 +7,7 @@ OpenProject::Application.configure do |application|
::Cron::ClearUploadedFilesJob,
::OAuth::CleanupJob,
::Attachments::CleanupUncontaineredJob,
::Notifications::ScheduleReminderMailsJob
::Notifications::ScheduleReminderMailsJob,
::Ldap::SynchronizationJob
end
end

@ -288,29 +288,41 @@ Redmine::MenuManager.map :admin_menu do |menu|
parent: :settings
end
menu.push :in_out,
{ controller: '/admin/settings/notifications_settings', action: :show },
menu.push :mail_and_notifications,
{ controller: '/admin/settings/aggregation_settings', action: :show },
if: Proc.new { User.current.admin? },
caption: :'menus.admin.incoming_outgoing',
caption: :'menus.admin.mails_and_notifications',
icon: 'icon2 icon-mail1'
menu.push :notification_settings,
{ controller: '/admin/settings/notifications_settings', action: :show },
{ controller: '/admin/settings/aggregation_settings', action: :show },
if: Proc.new { User.current.admin? },
caption: :label_setting_plural,
parent: :in_out
caption: :'menus.admin.aggregation_and_retention',
parent: :mail_and_notifications
menu.push :mail_notifications,
{ controller: '/admin/settings/mail_notifications_settings', action: :show },
if: Proc.new { User.current.admin? },
caption: :'menus.admin.mail_notification',
parent: :in_out
parent: :mail_and_notifications
menu.push :incoming_mails,
{ controller: '/admin/settings/incoming_mails_settings', action: :show },
if: Proc.new { User.current.admin? },
caption: :label_incoming_emails,
parent: :in_out
parent: :mail_and_notifications
menu.push :api_and_webhooks,
{ controller: '/admin/settings/api_settings', action: :show },
if: Proc.new { User.current.admin? },
caption: :'menus.admin.api_and_webhooks',
icon: 'icon2 icon-relations'
menu.push :api,
{ controller: '/admin/settings/api_settings', action: :show },
if: Proc.new { User.current.admin? },
caption: :label_api_access_key_type,
parent: :api_and_webhooks
menu.push :authentication,
{ controller: '/admin/settings/authentication_settings', action: :show },

@ -996,6 +996,7 @@ af:
relations: Relations
watchers: Dophouers
files: Lêers
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dae"
weeks: "weeks"
@ -1165,7 +1166,7 @@ af:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projekte'
clear_selection: 'Clear selection'
apply: 'Pas toe'

@ -1000,6 +1000,7 @@ ar:
relations: صِلات
watchers: المشاهدون
files: الملفّات
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "أيام"
weeks: "أسابيع"
@ -1177,7 +1178,7 @@ ar:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'المشاريع'
clear_selection: 'Clear selection'
apply: 'تطبيق'

@ -996,6 +996,7 @@ az:
relations: Relations
watchers: Watchers
files: Files
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "days"
weeks: "weeks"
@ -1165,7 +1166,7 @@ az:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projects'
clear_selection: 'Clear selection'
apply: 'Apply'

@ -996,6 +996,7 @@ bg:
relations: Връзки с
watchers: Наблюдатели
files: Файлове
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "дни"
weeks: "седмици"
@ -1165,7 +1166,7 @@ bg:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Продължаване'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Проекти'
clear_selection: 'Clear selection'
apply: 'Приложи'

@ -996,6 +996,7 @@ ca:
relations: Relacions
watchers: Observadors
files: Arxius
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dies"
weeks: "setmanes"
@ -1165,7 +1166,7 @@ ca:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projectes'
clear_selection: 'Clear selection'
apply: 'Aplicar'

@ -999,6 +999,7 @@ cs:
relations: Vztahy
watchers: Sledující
files: Soubory
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dnů"
weeks: "týdny"
@ -1172,7 +1173,7 @@ cs:
group: 'Skupina je nyní součástí %{project}. Mezitím již můžete s touto skupinou plánovat a přiřadit například pracovní balíčky.'
next_button: 'Pokračovat'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projekty'
clear_selection: 'Clear selection'
apply: 'Použít'

@ -995,6 +995,7 @@ da:
relations: Tilknytninger
watchers: Tilsynsførende
files: Filer
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dage"
weeks: "uger"
@ -1164,7 +1165,7 @@ da:
group: 'Gruppen er nu en del af %{project}. I mellemtiden kan du allerede planlægge med denne gruppe og tildele arbejdspakker for eksempel.'
next_button: 'Fortsæt'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projekter'
clear_selection: 'Clear selection'
apply: 'Benyt'

@ -995,6 +995,7 @@ de:
relations: Beziehungen
watchers: Beobachter
files: Dateien
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "Tagen"
weeks: "Wochen"
@ -1164,7 +1165,7 @@ de:
group: 'Die Gruppe ist nun %{project} zugewiesen. In der Zwischenzeit können Sie bereits mit dieser Gruppe planen und ihr zum Beispiel Arbeitspakete zuweisen.'
next_button: 'Fortfahren'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projekte'
clear_selection: 'Clear selection'
apply: 'Anwenden'

@ -995,6 +995,7 @@ el:
relations: Συσχετίσεις
watchers: Παρατηρητές
files: Αρχεία
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "ημέρες"
weeks: "εβδομάδες"
@ -1164,7 +1165,7 @@ el:
group: 'Η ομάδα είναι τώρα μέρος του %{project}. Εν τω μεταξύ, μπορείτε να προγραμματίσετε ήδη με αυτή την ομάδα και να αντιστοιχίσετε πακέτα εργασίας.'
next_button: 'Συνέχεια'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Έργα'
clear_selection: 'Clear selection'
apply: 'Εφαρμογή'

@ -996,6 +996,7 @@ eo:
relations: Rilatoj
watchers: Atentantoj
files: Dosieroj
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "tagoj"
weeks: "weeks"
@ -1165,7 +1166,7 @@ eo:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Daŭrigi'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projektoj'
clear_selection: 'Clear selection'
apply: 'Ekuzi'

@ -996,6 +996,7 @@ es:
relations: Relaciones
watchers: Controladores
files: Archivos
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "días"
weeks: "semanas"
@ -1165,7 +1166,7 @@ es:
group: 'El grupo ya forma parte de %{project}. Mientras tanto, puede crear planes con ese grupo y asignar paquetes de trabajo a este.'
next_button: 'Continuar'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Proyectos'
clear_selection: 'Clear selection'
apply: 'Aplicar'

@ -996,6 +996,7 @@ et:
relations: Seosed
watchers: Jälgijad
files: Failid
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "päeva"
weeks: "nädalat"
@ -1165,7 +1166,7 @@ et:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Jätka'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projektid'
clear_selection: 'Clear selection'
apply: 'Rakenda'

@ -996,6 +996,7 @@ fa:
relations: Relations
watchers: Watchers
files: Files
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "days"
weeks: "weeks"
@ -1165,7 +1166,7 @@ fa:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projects'
clear_selection: 'Clear selection'
apply: 'درخواست'

@ -996,6 +996,7 @@ fi:
relations: Riippuvuudet
watchers: Seuraajat
files: Tiedostot
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "päivää"
weeks: "viikkoa"
@ -1165,7 +1166,7 @@ fi:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Jatka'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projektit'
clear_selection: 'Clear selection'
apply: 'Ota käyttöön'

@ -996,6 +996,7 @@ fil:
relations: Mga relasyon
watchers: Manonood
files: Mga file
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "mga araw"
weeks: "mga linggo"
@ -1165,7 +1166,7 @@ fil:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Magpatuloy'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Mga proyekto'
clear_selection: 'Clear selection'
apply: 'Ilagay'

@ -996,6 +996,7 @@ fr:
relations: Relations
watchers: Observateurs
files: Fichiers
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "jours"
weeks: "semaines"
@ -1165,7 +1166,7 @@ fr:
group: 'Le groupe fait maintenant partie du %{project}. Entre-temps, vous pouvez déjà planifier avec ce groupe et l''assigner des lots de travaux par exemple.'
next_button: 'Continuer'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projets'
clear_selection: 'Clear selection'
apply: 'Appliquer'

@ -998,6 +998,7 @@ he:
relations: קשרים
watchers: צופים
files: קבצים
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "ימים"
weeks: "שבועות"
@ -1171,7 +1172,7 @@ he:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'פרויקטים'
clear_selection: 'Clear selection'
apply: 'החל'

@ -996,6 +996,7 @@ hi:
relations: Relations
watchers: चर
files: इल
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "days"
weeks: "weeks"
@ -1165,7 +1166,7 @@ hi:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projects'
clear_selection: 'Clear selection'
apply: 'ल कर'

@ -997,6 +997,7 @@ hr:
relations: Relacije
watchers: Nadglednici
files: Datoteke
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dani"
weeks: "tjedana"
@ -1168,7 +1169,7 @@ hr:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Nastavi'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projekti'
clear_selection: 'Clear selection'
apply: 'Primjeni'

@ -1001,6 +1001,7 @@ hu:
relations: Kapcsolatok
watchers: Megfigyelők
files: Fájlok
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "nap"
weeks: "Hetek"
@ -1170,7 +1171,7 @@ hu:
group: "A csoport mostantól a %{project} része. Eközben már tervezhet ezzel a csoporttal, és például munkacsomagokat rendelhet hozzá.\n"
next_button: 'Folytatás'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projektek'
clear_selection: 'Clear selection'
apply: 'Alkalmaz'

@ -995,6 +995,7 @@ id:
relations: Relasi
watchers: Pemantau
files: File
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "hari"
weeks: "minggu"
@ -1162,7 +1163,7 @@ id:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Lanjut'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Project'
clear_selection: 'Clear selection'
apply: 'Apply'

@ -997,6 +997,7 @@ it:
relations: Relazioni
watchers: Osservatori
files: File
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "giorni"
weeks: "Settimane"
@ -1166,7 +1167,7 @@ it:
group: 'Il gruppo è ora parte di %{project}. Nel mentre puoi ad esempio già pianificare con quel gruppo e assegnare pacchetti di lavoro.'
next_button: 'Continua'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Progetti'
clear_selection: 'Clear selection'
apply: 'Applica'

@ -998,6 +998,7 @@ ja:
relations: 関係
watchers: ウォッチャー
files: ファイルを添付する
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "日"
weeks: "週"
@ -1165,7 +1166,7 @@ ja:
group: 'グループは %{project} の一部になりました。一方で、そのグループを使って計画を立てたり、ワークパッケージを割り当てたりすることができます。'
next_button: '続行'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'プロジェクト'
clear_selection: 'Clear selection'
apply: '適用'

@ -995,6 +995,7 @@ ko:
relations: 관계
watchers: 주시자
files: 파일
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "일"
weeks: "주"
@ -1162,7 +1163,7 @@ ko:
group: '이제 이 그룹은 %{project}의 일부입니다. 한편 당신은 해당 사용자에 대한 계획을 세우거나 작업 패키지를 할당할 수 있습니다.'
next_button: '계속'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: '프로젝트'
clear_selection: 'Clear selection'
apply: '적용'

@ -995,6 +995,7 @@ lol:
relations: crwdns788464:0crwdne788464:0
watchers: crwdns788466:0crwdne788466:0
files: crwdns807702:0crwdne807702:0
files_tab_migration_help: 'crwdns808154:0crwdne808154:0'
time_relative:
days: "crwdns788470:0crwdne788470:0"
weeks: "crwdns788472:0crwdne788472:0"
@ -1164,7 +1165,7 @@ lol:
group: 'crwdns788732:0%{project}crwdne788732:0'
next_button: 'crwdns788734:0crwdne788734:0'
include_projects:
toggle_title: 'crwdns788736:0crwdne788736:0'
toggle_title: 'crwdns808124:0crwdne808124:0'
title: 'crwdns788738:0crwdne788738:0'
clear_selection: 'crwdns788740:0crwdne788740:0'
apply: 'crwdns788742:0crwdne788742:0'

@ -998,6 +998,7 @@ lt:
relations: Ryšiai
watchers: Stebėtojai
files: Failai
files_tab_migration_help: 'Dabar jūs galite prisegti failus prie darbo paketųnaujoje kortelėje:'
time_relative:
days: "dienos"
weeks: "savaitės"

@ -997,6 +997,7 @@ lv:
relations: Saistītie
watchers: Sekotāji
files: Faili
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dienas"
weeks: "weeks"
@ -1168,7 +1169,7 @@ lv:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projekti'
clear_selection: 'Clear selection'
apply: 'Apstiprināt'

@ -996,6 +996,7 @@ ne:
relations: Relations
watchers: Watchers
files: Files
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "days"
weeks: "weeks"
@ -1165,7 +1166,7 @@ ne:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projects'
clear_selection: 'Clear selection'
apply: 'Apply'

@ -996,6 +996,7 @@ nl:
relations: Relaties
watchers: Volgers
files: Bestanden
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dagen"
weeks: "weken"
@ -1165,7 +1166,7 @@ nl:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Ga verder'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projecten'
clear_selection: 'Clear selection'
apply: 'Toepassen'

@ -996,6 +996,7 @@
relations: Relasjoner
watchers: Overvåkere
files: Filer
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dager"
weeks: "uker"
@ -1165,7 +1166,7 @@
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Fortsett'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Prosjekter'
clear_selection: 'Clear selection'
apply: 'Bruk'

@ -998,6 +998,7 @@ pl:
relations: Relacje
watchers: Obserwatorzy
files: Pliki
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dni"
weeks: "tygodnie"
@ -1171,7 +1172,7 @@ pl:
group: 'Grupa jest teraz częścią %{project}. Tymczasem możesz już planować z tą grupą i na przykład przypisać pakiety robocze.'
next_button: 'Kontynuuj'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projekty'
clear_selection: 'Clear selection'
apply: 'Zastosuj'

@ -995,6 +995,7 @@ pt:
relations: Relações
watchers: Observadores
files: Arquivos
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dias"
weeks: "semanas"
@ -1164,7 +1165,7 @@ pt:
group: 'O grupo agora faz parte de %{project}. Enquanto isso, você já pode planejar com este grupo e atribuir pacotes de trabalho por exemplo.'
next_button: 'Continuar'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projetos'
clear_selection: 'Clear selection'
apply: 'Aplicar'

@ -996,6 +996,7 @@ ro:
relations: Relații
watchers: Observatori
files: Fişiere
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "zile"
weeks: "săptămâni"
@ -1167,7 +1168,7 @@ ro:
group: 'Grupul este acum o parte din %{project}. Între timp, puteți deja să planificați cu acest grup și să atribuiți pachete de lucru, de exemplu.'
next_button: 'Continuaţi'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Proiecte'
clear_selection: 'Clear selection'
apply: 'Salvare'

@ -997,6 +997,7 @@ ru:
relations: Связи
watchers: Наблюдатель
files: Файлы
files_tab_migration_help: 'Теперь вы можете прикрепить файлы к рабочим пакетам через новую вкладку:'
time_relative:
days: "дней"
weeks: "недели"

@ -996,6 +996,7 @@ rw:
relations: Relations
watchers: Watchers
files: Files
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "days"
weeks: "weeks"
@ -1165,7 +1166,7 @@ rw:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projects'
clear_selection: 'Clear selection'
apply: 'Apply'

@ -996,6 +996,7 @@ si:
relations: සබඳත
watchers: රකරවන
files:
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "දන"
weeks: "සත"
@ -1165,7 +1166,7 @@ si:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'ඉදයට යනන'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'ව'
clear_selection: 'Clear selection'
apply: 'අයද කරනන'

@ -998,6 +998,7 @@ sk:
relations: Väzby
watchers: Pozorovatelia
files: Súbory
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dní"
weeks: "týždne"
@ -1171,7 +1172,7 @@ sk:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Pokračovať'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projekty'
clear_selection: 'Clear selection'
apply: 'Použiť'

@ -997,6 +997,7 @@ sl:
relations: Relacije
watchers: Opazovalci
files: Datoteke
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dnevi"
weeks: "tednov"
@ -1170,7 +1171,7 @@ sl:
group: 'Skupina je zdaj del %{project}. Medtem lahko planirate s to skupino in ji dodelite delovne naloge.'
next_button: 'Nadaljuj'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projekti'
clear_selection: 'Clear selection'
apply: 'Potrdi'

@ -995,6 +995,7 @@ sv:
relations: Relationer
watchers: Bevakare
files: Filer
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "dagar"
weeks: "veckor"
@ -1164,7 +1165,7 @@ sv:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: 'Fortsätt'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projekt'
clear_selection: 'Clear selection'
apply: 'Tilldela'

@ -995,6 +995,7 @@ th:
relations: Relations
watchers: เฝาด
files: ไฟล
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "วน"
weeks: "สปดาห"
@ -1162,7 +1163,7 @@ th:
group: 'ตอนนกลมนเปนสวนหนงของ %{project}, คณสามารถวางแผนกบกลมนนและกำหนดแพคเกจงานได'
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'โครงการ'
clear_selection: 'Clear selection'
apply: 'นำไปใช'

@ -996,6 +996,7 @@ tr:
relations: İlişkiler
watchers: Takip Edenler
files: Dosyalar
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "gün"
weeks: "hafta"
@ -1165,7 +1166,7 @@ tr:
group: 'Grup artık %{project} ''nin bir parçası. Bu arada, bu grupla zaten plan yapabilir ve örneğin iş paketleri atayabilirsiniz.'
next_button: 'Devam et'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projeler'
clear_selection: 'Clear selection'
apply: 'Uygula'

@ -998,6 +998,7 @@ uk:
relations: Зв'язки
watchers: Спостерігачі
files: Файли
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "днів"
weeks: "тижнів"
@ -1171,7 +1172,7 @@ uk:
group: 'Ця група тепер входить у проєкт «%{project}». Тим часом ви вже можете включати її в план і призначати їй пакети робіт.'
next_button: 'Продовжити'
include_projects:
toggle_title: 'Включити проєкти'
toggle_title: 'Include projects'
title: 'Проекти'
clear_selection: 'Очистити вибране'
apply: 'Застосувати'

@ -994,6 +994,7 @@ vi:
relations: Relations
watchers: Watchers
files: Tập tin
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "ngày"
weeks: "weeks"
@ -1161,7 +1162,7 @@ vi:
group: 'Nhóm này hiện là một phần của %{project}. Trong khi đó, bạn có thể lên kế hoạch cho nhóm đó và chỉ định các gói làm việc cho từng trường hợp.'
next_button: 'Tiếp tục'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Các dự án'
clear_selection: 'Clear selection'
apply: 'Áp dụng'

@ -994,6 +994,7 @@ zh-TW:
relations: 關聯
watchers: 監看者
files: 檔案
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "天"
weeks: "週"
@ -1161,7 +1162,7 @@ zh-TW:
group: 'The group is now a part of %{project}. Meanwhile you can already plan with that group and assign work packages for instance.'
next_button: '繼續'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: '專案'
clear_selection: 'Clear selection'
apply: '套用'

@ -1260,7 +1260,7 @@ lt:
error_enterprise_token_invalid_domain: "Enterprise Edition neaktyvi. Jūsų Enterprise rakto domenas (%{actual}) nesutampa su jūsų sistemos serverio vardu (%{expected})."
error_failed_to_delete_entry: 'Šio įrašo nepavyko panaikinti.'
error_in_dependent: "Klaida bandant pakeisti priklausomą objektą: %{dependent_class} #%{related_id} - %{related_subject}: %{error}"
error_in_new_dependent: "Error attempting to create dependent object: %{dependent_class} - %{related_subject}: %{error}"
error_in_new_dependent: "Klaida bandant sukurti priklausomą objektą: %{dependent_class} - %{related_subject}: %{error}"
error_invalid_selected_value: "Netinkama parinkta reikšmė."
error_journal_attribute_not_present: "Žurnale nėra atributo %{attribute}."
error_pdf_export_too_many_columns: "PDF eksportavimui pasirinkta per daug stulpelių. Prašome sumažinti stulpelių skaičių."
@ -2915,7 +2915,7 @@ lt:
work_package: "Jūsų ieškomas darbo paketas nerastas arba ištrintas."
expected:
date: "YYYY-MM-DD (ISO 8601 date only)"
datetime: "YYYY-MM-DDThh:mm:ss[.lll][+hh:mm] (any compatible ISO 8601 datetime)"
datetime: "YYYY-MM-DDThh:mm:ss[.lll][+hh:mm] (bet kokia ISO 8601 data/laikas)"
duration: "ISO 8601 trukmė"
invalid_content_type: "Laukiamas turinio tipas turi būti „%{content_type}“, bet gautas „%{actual}“."
invalid_format: "Netinkamas formatas ypatybei '%{property}': tikėtasi panašaus į '%{expected_format}', bet gautas '%{actual}'."
@ -2927,7 +2927,7 @@ lt:
select: "Prašomas %{invalid} pasirinkimas yra nepalaikomas. Palaikomi pasirinkimai yra %{supported}."
invalid_user_status_transition: "Esama vartotojo paskyros būsena neleidžia šios operacijos."
missing_content_type: "nenurodyta"
missing_property: "Missing property '%{property}'."
missing_property: "Trūkstama savybė '%{property}'."
missing_request_body: "Nėra užklausos turinio."
missing_or_malformed_parameter: "Užklausos '%{parameter}' parametras neegzistuoja arba yra neteisingai suformuluotas."
multipart_body_error: "Užklausos turinys neturi laukiamų dalių."

@ -87,6 +87,10 @@ en:
contact: "Contact us for a demo"
enterprise_info_html: "is an Enterprise <strong class='icon-medal'></strong> feature."
upgrade_info: "Please upgrade to a paid plan to activate and start using it in your team."
journal_aggregation:
explanation:
text: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent and will also affect %{webhook_link} delay."
link: "webhook"
announcements:
show_until: Show until
@ -1399,7 +1403,9 @@ en:
menus:
admin:
mail_notification: "Email notifications"
incoming_outgoing: "Incoming & Outgoing"
mails_and_notifications: "Emails and notification"
aggregation_and_retention: 'Aggregation and retention'
api_and_webhooks: "API and webhooks"
quick_add:
label: "Open quick add menu"
@ -1908,7 +1914,7 @@ en:
label_used_by_types: "Used by types"
label_used_in_projects: "Used in projects"
label_user: "User"
label_user_and_permission: "Users & Permissions"
label_user_and_permission: "Users and permissions"
label_user_named: "User %{name}"
label_user_activity: "%{value}'s activity"
label_user_anonymous: "Anonymous"
@ -2695,7 +2701,6 @@ en:
text_work_packages_destroy_confirmation: "Are you sure you want to delete the selected work package(s)?"
text_work_packages_ref_in_commit_messages: "Referencing and fixing work packages in commit messages"
text_journal_added: "%{label} %{value} added"
text_journal_aggregation_time_explanation: "Individual actions of a user (e.g. updating a work package twice) are aggregated into a single action if their age difference is less than the specified timespan. They will be displayed as a single action within the application. This will also delay notifications by the same amount of time reducing the number of emails being sent."
text_journal_changed_html: "%{label} changed from %{old} %{linebreak}<strong>to</strong> %{new}"
text_journal_changed_plain: "%{label} changed from %{old} %{linebreak}to %{new}"
text_journal_changed_no_detail: "%{label} updated"

@ -30,8 +30,8 @@ en:
js:
ajax:
hide: "Hide"
loading: "Loading ..."
updating: "Updating ..."
loading: "Loading"
updating: "Updating"
attachments:
draggable_hint: |
@ -317,27 +317,31 @@ en:
learn_about: "Learn more about the new features"
# Include the version to invalidate outdated translations in other locales.
# Otherwise, e.g. chinese might still have the translations for 10.0 in the 12.0 release.
'12_0':
'12_1':
standard:
learn_about_link: https://www.openproject.org/blog/openproject-12-0-release
learn_about_link: https://www.openproject.org/openproject-12-1-release
new_features_html: >
The release contains various new features and improvements: <br>
<ul class="%{list_styling_class}">
<li>With the new <b>in-app notifications</b> you receive all important updates directly in the application and don't get a flood of emails anymore.</li>
<li>The new <b>notification center</b> shows all the changes, including intuitive filter options, e.g. by reason for notification or projects. It even allows editing directly in a split view.</li>
<li>Improved <b>notification settings</b> allow to fine-tune for which actions and in which projects you want to receive a notification.</li>
<li><b>Email reminders</b> can be configured to receive important updates via a daily email summary.</li>
<li>The work package auto-completer for relations now also shows additional information (project name, status, ...) to easily identify the respective work package.</li>
<li>A <b>new team planner module</b> (Enterprise feature) allows you to visually assign tasks to team members to get an overview of who is working on what.</li>
<li>We are <b>releasing the basic agile boards</b> for the Community version.</li>
<li>The <b>"Include Projects" filter</b> option makes it easier to add different projects to your views, such as for work packages, calendars, and team planners.</li>
<li>We added <b>a new "Files" tab</b> in the work package details to have all possible information attached to a work package together.</li>
<li>We created <b>global roles for groups</b> to assign these roles to groups and create superuser groups.</li>
<li>Project status was given more options to choose from.</li>
</ul>
bim:
learn_about_link: https://www.openproject.org/blog/openproject-12-0-release
learn_about_link: https://www.openproject.org/openproject-12-1-release
new_features_html: >
The release contains various new features and improvements: <br>
<ul class="%{list_styling_class}">
<li>Notification center: Reduce the number of mails you receive. Instead find and act upon all relevant notifications in one central place.</li>
<li>All uploaded IFC files can now also be downloaded.</li>
<li>The uploading and processing of IFC got faster and received better error messages.</li>
<li>The <a href="https://github.com/opf/openproject-revit-add-in">OpenProject Revit Add-in</a> received many bug fixes.</li>
<li>In the BCF module you can now save your selected work package filters, columns etc. as <b>views</b> and share those with your team members.</li>
<li>A <b>new team planner module</b> (Enterprise feature) allows you to visually assign tasks to team members to get an overview of who is working on what.</li>
<li>We are <b>releasing the basic agile boards</b> for the Community version.</li>
<li>The <b>"Include Projects" filter</b> option makes it easier to add different projects to your views, such as for work packages, calendars, and team planners.</li>
<li>We added <b>a new "Files" tab</b> in the work package details to have all possible information attached to a work package together.</li>
<li>We created <b>global roles for groups</b> to assign these roles to groups and create superuser groups.</li>
<li>Project status was given more options to choose from.</li>
</ul>
label_activate: "Activate"
@ -1073,6 +1077,7 @@ en:
relations: Relations
watchers: Watchers
files: Files
files_tab_migration_help: 'You can now attach files to work packages via the new tab:'
time_relative:
days: "days"
weeks: "weeks"
@ -1260,7 +1265,7 @@ en:
next_button: 'Continue'
include_projects:
toggle_title: 'Include Projects'
toggle_title: 'Include projects'
title: 'Projects'
clear_selection: 'Clear selection'
apply: 'Apply'

@ -400,8 +400,9 @@ OpenProject::Application.routes.draw do
resource :authentication, controller: '/admin/settings/authentication_settings', only: %i[show update]
resource :incoming_mails, controller: '/admin/settings/incoming_mails_settings', only: %i[show update]
resource :notifications, controller: '/admin/settings/notifications_settings', only: %i[show update]
resource :aggregation, controller: '/admin/settings/aggregation_settings', only: %i[show update]
resource :mail_notifications, controller: '/admin/settings/mail_notifications_settings', only: %i[show update]
resource :api, controller: '/admin/settings/api_settings', only: %i[show update]
resource :work_packages, controller: '/admin/settings/work_packages_settings', only: %i[show update]
resource :users, controller: '/admin/settings/users_settings', only: %i[show update]

@ -0,0 +1,14 @@
class AddIncludeSubprojectsToQuery < ActiveRecord::Migration[6.1]
def change
add_column :queries,
:include_subprojects,
:boolean,
null: false,
default: Setting.display_subprojects_work_packages?
# Remove the default now
reversible do |dir|
dir.up { change_column_default :queries, :include_subprojects, nil }
end
end
end

@ -1,4 +1,4 @@
FROM ruby:3.0.3-buster as develop
FROM ruby:3.0.3-bullseye as develop
MAINTAINER operations@openproject.com
ARG DEV_UID=1000
@ -23,7 +23,7 @@ WORKDIR /home/$USER
RUN apt-get update -qq && \
DEBIAN_FRONTEND=noninteractive apt-get install -y \
postgresql-client
postgresql-client libffi7 libffi-dev
COPY ./docker/dev/backend/scripts/setup /usr/sbin/setup
COPY ./docker/dev/backend/scripts/run-app /usr/sbin/run-app

@ -1,7 +1,8 @@
---
description: |-
The configuration endpoint allows to read certain configuration parameters of the OpenProject instance.
Note that there is no 1:1 relationship between this endpoint and the settings you can find in your settings.yml.
Note that there is no 1:1 relationship between this endpoint and the settings an administrator has at hand to modify the behaviour
of the application via configuration.yml or ENV variables.
For now this endpoint will only allow access to settings deemed useful for a client to know in general.

@ -111,27 +111,28 @@ On the OpenProject side, you'll have to configure SAML to connect to the just st
Here's a minimal configuration that you can put into `config/plugins/auth_saml/settings.yml`
Here's a minimal configuration that you can put into `config/configuration.yml`
```yaml
saml:
name: "saml"
display_name: "simplesaml-docker"
# Use the default SAML icon
icon: "auth_provider-saml.png"
# omniauth-saml config
assertion_consumer_service_url: "http://localhost:3000/auth/saml/callback"
issuer: "http://localhost:3000"
idp_cert_fingerprint: "119b9e027959cdb7c662cfd075d9e2ef384e445f"
idp_sso_target_url: "http://localhost:8080/simplesaml/saml2/idp/SSOService.php"
idp_slo_target_url: "http://localhost:8080/simplesaml/saml2/idp/SingleLogoutService.php"
attribute_statements:
email: ['email']
login: ['uid']
first_name: ['givenName']
last_name: ['sn']
default:
saml:
name: "saml"
display_name: "simplesaml-docker"
# Use the default SAML icon
icon: "auth_provider-saml.png"
# omniauth-saml config
assertion_consumer_service_url: "http://localhost:3000/auth/saml/callback"
issuer: "http://localhost:3000"
idp_cert_fingerprint: "119b9e027959cdb7c662cfd075d9e2ef384e445f"
idp_sso_target_url: "http://localhost:8080/simplesaml/saml2/idp/SSOService.php"
idp_slo_target_url: "http://localhost:8080/simplesaml/saml2/idp/SingleLogoutService.php"
attribute_statements:
email: ['email']
login: ['uid']
first_name: ['givenName']
last_name: ['sn']
```

@ -22,25 +22,25 @@ Click on one of the categories in order to proceed with the configuration.
## Overview
| Topic | Content |
| ------------------------------------------------------ | :----------------------------------------------------------- |
| [Users and permissions](./users-permissions) | How to manage users, groups and permissions in OpenProject? |
| [Work packages](./manage-work-packages) | How to configure work packages, types, status and workflows? |
| [Custom fields](./custom-fields) | Set custom fields for work packages, Spent time, projects, versions, users, groups and more. |
| [Attribute help texts](./attribute-help-texts) | Add help texts to explain attributes (including custom fields) in projects and work packages. |
| [Enumerations](./enumerations) | Set enumerations, e.g. work package priorities, time tracking activities, document categories, and more. |
| [System settings](./system-settings) | Configure your system settings, e.g. a welcome text block on the landing page, display settings, repositories, and more. |
| [Incoming emails](./../installation-and-operations/configuration/incoming-emails) | Configure email settings in OpenProject. How to set up incoming email? |
| [Outbound emails](./../installation-and-operations/configuration/outbound-emails) | Configure email settings in OpenProject. How to configure email notifications and your email provider? |
| [Authentication](./authentication) | Configure authentication methods in OpenProject, e.g. OAuth, OpenID, Two-factor-authentication, LDAP, and more. |
| [Announcement](./announcement) | How to create a system announcement? |
| [Design](./design) | Create your own design and make it compliant to your company's Corporate Identity, upload logo and customize colors. |
| [Colors](./colors) | Configure colors used in the system, e.g. status colors, work package types, priorities and more. |
| [Time and costs](./time-and-costs) | Configure your currency and create cost types in OpenProject. |
| [Backlogs](./backlogs) | Configure your backlogs settings in OpenProject, e.g. story types to be displayed in the backlogs, task types, and more. |
| [Plugins](./plugins) | Manage plugins in OpenProject. |
| [Incoming & Outgoing](./incoming-and-outgoing/) | Manage notifications, email % webhooks |
| [Information](./information/) | View the latest system information status. |
| [Integrations](./integrations/) | How to combine OpenProject and e.g. GitHub. |
| [Enterprise on-premises](../enterprise-guide/enterprise-on-premises-guide/) | Upgrading your Community Edition to Enterprise on-premises and other administrative topics. |
| [Enterprise cloud](../enterprise-guide/enterprise-cloud-guide/) | Manage your OpenProject Enterprise cloud and other administrative topics. |
| Topic | Content |
|-----------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------|
| [Users and permissions](./users-permissions) | How to manage users, groups and permissions in OpenProject? |
| [Work packages](./manage-work-packages) | How to configure work packages, types, status and workflows? |
| [Custom fields](./custom-fields) | Set custom fields for work packages, Spent time, projects, versions, users, groups and more. |
| [Attribute help texts](./attribute-help-texts) | Add help texts to explain attributes (including custom fields) in projects and work packages. |
| [Enumerations](./enumerations) | Set enumerations, e.g. work package priorities, time tracking activities, document categories, and more. |
| [System settings](./system-settings) | Configure your system settings, e.g. a welcome text block on the landing page, display settings, repositories, and more. |
| [Incoming emails](./../installation-and-operations/configuration/incoming-emails) | Configure email settings in OpenProject. How to set up incoming email? |
| [Outbound emails](./../installation-and-operations/configuration/outbound-emails) | Configure email settings in OpenProject. How to configure email notifications and your email provider? |
| [Authentication](./authentication) | Configure authentication methods in OpenProject, e.g. OAuth, OpenID, Two-factor-authentication, LDAP, and more. |
| [Announcement](./announcement) | How to create a system announcement? |
| [Design](./design) | Create your own design and make it compliant to your company's Corporate Identity, upload logo and customize colors. |
| [Colors](./colors) | Configure colors used in the system, e.g. status colors, work package types, priorities and more. |
| [Time and costs](./time-and-costs) | Configure your currency and create cost types in OpenProject. |
| [Backlogs](./backlogs) | Configure your backlogs settings in OpenProject, e.g. story types to be displayed in the backlogs, task types, and more. |
| [Plugins](./plugins) | Manage plugins in OpenProject. |
| [Emails and notification](./incoming-and-outgoing/) | Manage notifications and email |
| [Information](./information/) | View the latest system information status. |
| [Integrations](./integrations/) | How to combine OpenProject and e.g. GitHub. |
| [Enterprise on-premises](../enterprise-guide/enterprise-on-premises-guide/) | Upgrading your Community Edition to Enterprise on-premises and other administrative topics. |
| [Enterprise cloud](../enterprise-guide/enterprise-cloud-guide/) | Manage your OpenProject Enterprise cloud and other administrative topics. |

@ -19,7 +19,7 @@ You can integrate your active directory or other SAML compliant identity provide
The configuration can be provided in one of two ways:
* `config/plugins/auth_saml/settings.yml` file (1.1)
* `config/configuration.yml` file (1.1)
* Environment variables (1.2)
@ -30,23 +30,19 @@ The configuration can be provided in one of two ways:
Whatever means are chosen, the plugin simply passes all options to omniauth-saml. See [their configuration
documentation](https://github.com/omniauth/omniauth-saml#usage) for further details.
The options are mutually exclusive. I.e. if settings are already provided via ENV variables, settings in a `settings.yml` file will be ignored. If you decide to save settings in the database, they will override any ENV variables you might have set.
The options are mutually exclusive. I.e. if settings are already provided via ENV variables, they will overwrite settings in a `configuration.yml` file.
If you decide to save settings in the database, they will override any ENV variables you might have set.
#### 1.1 config/plugins/auth_saml/settings.yml file
#### 1.1 config/configuration.yml file
You need to create the folder `plugins` and `auth_saml` first. You can do that with the following command
In your OpenProject packaged installation, you can modify the `/opt/openproject/config/configuration.yml` file.
Edit the file in your favorite editor
```
mkdir -p /opt/openproject/config/plugins/auth_saml
vim /opt/openproject/config/configuration.yml
```
and then edit the file in your favorite editor
```
vim /opt/openproject/config/plugins/auth_saml/settings.yml
```
In your OpenProject packaged installation, you can modify the `/opt/openproject/config/plugins/auth_saml/settings.yml` file. This will contains the complete OpenProject configuration and can be extended to also contain metadata settings and connection details for your SSO identity provider.
This will contains the complete OpenProject configuration and can be extended to also contain metadata settings and connection details for your SSO identity provider.
The following is an exemplary file with a set of common settings:
@ -87,7 +83,7 @@ saml:
last_name: ['sn']
```
Be sure to choose the correct indentation and base key. The items below the `saml` key should be indented two spaces. You will get an YAML parsing error otherwise when trying to start OpenProject.
Be sure to choose the correct indentation and base key. The items below the `saml` key should be indented two spaces more than `saml` already is. And `saml` can will need to be placed in the `default` or `production` group so it will already be indented. You will get an YAML parsing error otherwise when trying to start OpenProject.
#### 1.2 Environment variables
@ -122,7 +118,7 @@ That means it's best to set them using the console.
> docker-compose run --rm web bundle exec rails console
```
Once on the console you can set the same values as named in the `settings.yml` file, however they need to be nested within a 'providers' key as follows.
Once on the console you can set the same values as named in the `configuration.yml` file, however they need to be nested within a 'providers' key as follows.
For example:
```ruby

@ -1,26 +1,26 @@
---
sidebar_navigation:
title: Incoming & Outgoing
title: Emails and notification
priority: 760
description: incoming and outgoing notification settings in OpenProject.
robots: index, follow
keywords: incoming and outgoing notifications
---
# Incoming & outgoing
# Emails and notification
Configure **incoming & outgoing settings** in OpenProject, i.e. email notifications and incoming email configuration.
Configure **Emails and notification settings** in OpenProject, i.e. email notifications and incoming email configuration.
Navigate to *Administration* -> *Incoming & Outgoing*.
Navigate to *Administration* -> *Emails and notification*.
| Topic | Content |
| ------------------------------------------------------------ | ---------------------------------------------------------- |
| [Incoming & outgoing settings](#incoming--outgoing-settings) | How to configure the global incoming and outgoing settings |
| [Email notifications](#email-notifications-settings) | How to configure outgoing email notifications? |
| [Incoming emails](#incoming-emails-settings) | How to configure settings for inbound emails? |
| Topic | Content |
|------------------------------------------------------------------|------------------------------------------------------------|
| [Emails and notification settings](#incoming--outgoing-settings) | How to configure the global incoming and outgoing settings |
| [Email notifications](#email-notifications-settings) | How to configure outgoing email notifications? |
| [Incoming emails](#incoming-emails-settings) | How to configure settings for inbound emails? |
## Incoming & outgoing settings
## Emails and notification settings
To change the global settings for incoming and outgoing messages, navigate to *Administration* -> *Incoming & Outgoing*.
To change the global settings for incoming and outgoing messages, navigate to *Administration* -> *Emails and notification*.
![image-20211129133408193](image-20211129133408193.png)
@ -29,7 +29,7 @@ To change the global settings for incoming and outgoing messages, navigate to *A
## Email notifications settings
To adapt email notification settings, go to *Administration* -> *Incoming & Outgoing* -> *Email notifications*.
To adapt email notification settings, go to *Administration* -> *Emails and notification* -> *Email notifications*.
1. **Emission email address**. This email address will be shown as the sender for the email notifications sent by OpenProject (for example, when a work package is changed).
2. Activate **blind carbon copy recipients** (bcc).
@ -48,7 +48,7 @@ Configure your notification email header and footer which will be sent out for e
## Incoming emails settings
To adapt incoming email settings, go to *Administration* -> *Incoming & Outgoing* -> *Incoming emails*. Here you can configure the following options.
To adapt incoming email settings, go to *Administration* -> *Emails and notification* -> *Incoming emails*. Here you can configure the following options.
1. **Define after which lines an email should be truncated**. This setting allows shortening email after the entered lines.
2. Specify a **regular expression** to truncate emails.

@ -1,12 +1,12 @@
---
sidebar_navigation:
title: Users & Permissions
title: Users and permissions
priority: 997
description: Manage users and permissions.
robots: index, follow
keywords: users, permissions, roles, groups, avatars
---
# Users & Permissions
# Users and permissions
Manage users, placeholder users and permissions in OpenProject.

@ -8,7 +8,7 @@ keywords: Avatars
---
# OpenProject Avatars
To select which type of Avatars can be used in your OpenProject, navigate to -> *Administration* -> *Users & Permissions* -> *Avatars*.
To select which type of Avatars can be used in your OpenProject, navigate to -> *Administration* -> *Users and permissions* -> *Avatars*.
You can choose whether to allow user Gravatar or enable to upload custom avatars.

@ -10,7 +10,7 @@ keywords: manage groups
# Manage Groups
<div class="glossary">
A **Group** is defined as a list of users which can be assigned to a project with a selected role. New groups can be defined in *Administration -> Users & Permissions -> Groups*.
A **Group** is defined as a list of users which can be assigned to a project with a selected role. New groups can be defined in *Administration -> Users and permissions -> Groups*.
</div>
OpenProject allows creating tailored project member **groups**, which grant additional permissions to individual users within a project. Instead of adding individual users to a project you can add a user group, e.g. Marketing. You can edit existing groups, create new ones, add and remove users or delete groups.

@ -27,7 +27,7 @@ Placeholder users can be managed by system admins and by users with the [role](.
## Placeholder user list
To manage placeholder users navigate to *Administration -> Users & Permissions -> Placeholder users*. The placeholder user list gives you an overview of all placeholder users with their names and creation dates. From here you can also [add](#create-placeholder-users) placeholder users, [edit](#manage-placeholder-user-settings) them and [delete](#delete-placeholder-users) them.
To manage placeholder users navigate to *Administration -> Users and permissions -> Placeholder users*. The placeholder user list gives you an overview of all placeholder users with their names and creation dates. From here you can also [add](#create-placeholder-users) placeholder users, [edit](#manage-placeholder-user-settings) them and [delete](#delete-placeholder-users) them.
The column headers can be clicked to toggle sort direction. Arrows indicate sort order, up for ascending (a-z/0-9) and down for descending (z-a/9-0).

@ -38,7 +38,7 @@ Note: If a [project module](../../../user-guide/projects/project-settings/module
## Create a new role
To create a new role, navigate to the administration and select *Users & Permissions -> Roles and permissions* from the menu on the left.
To create a new role, navigate to the administration and select *Users and permissions -> Roles and permissions* from the menu on the left.
You will see the list of all the roles that have been created so far.

@ -1,6 +1,6 @@
---
sidebar_navigation:
title: Users & Permissions FAQ
title: Users and permissions FAQ
priority: 001
description: Frequently asked questions regarding user, permissions, roles and groups
robots: index, follow
@ -11,7 +11,7 @@ keywords: manage users FAQ, permissions, groups, roles, user settings
## I want to delete a user but it fails.
If you are using the Enterprise cloud and the user you are trying to delete is the user that initially set up OpenProject, you will need to contact us to delete this user. For other users please make sure the box "User accounts deletable by admins" in *Administration -> Users & Permissions -> Settings* is checked.
If you are using the Enterprise cloud and the user you are trying to delete is the user that initially set up OpenProject, you will need to contact us to delete this user. For other users please make sure the box "User accounts deletable by admins" in *Administration -> Users and permissions -> Settings* is checked.
## We use LDAP. How do we release a license should someone leave our team and no longer need access?

@ -14,7 +14,7 @@ The user list provides an overview of all users in OpenProject. You can create n
<div class="glossary">
**User** is defined as a person (described by an identifier) who uses OpenProject. Users can become project members by assigning them a role and adding them via the project settings.
</div>
To manage users click on your avatar (top right corner) and select *Administration*. Select *Users & Permissions -> Users*. The list of current users is shown.
To manage users click on your avatar (top right corner) and select *Administration*. Select *Users and permissions -> Users*. The list of current users is shown.
In the Community Edition there is no limit to the number of users. In Enterprise editions (cloud and on-premises) the user limit is based on your subscription. The number of users for your subscription is thus not bound to names. For example, if you block a user you can add a new one without upgrading.

@ -100,6 +100,6 @@ Here, you can click the **Edit button** on the top right corner of the user prof
![User-profile-edit](User-profile-edit.png)
Alternatively, you can navigate to *Administration -> Users & Permissions -> Users* and click on the respective user name.
Alternatively, you can navigate to *Administration -> Users and permissions -> Users* and click on the respective user name.
Click on the **Rate history** tab. Find out [here](../../../system-admin-guide/users-permissions/users/#rate-history) how to continue.

@ -31,7 +31,10 @@ import {
Component,
OnDestroy,
Injector,
OnInit,
ChangeDetectionStrategy,
} from '@angular/core';
import { StateService } from '@uirouter/core';
import { Subscription } from 'rxjs';
import { GlobalSearchService } from 'core-app/core/global_search/services/global-search.service';
import { ScrollableTabsComponent } from 'core-app/shared/components/tabs/scrollable-tabs/scrollable-tabs.component';
@ -42,9 +45,10 @@ export const globalSearchTabsSelector = 'global-search-tabs';
@Component({
selector: globalSearchTabsSelector,
templateUrl: '../../../shared/components/tabs/scrollable-tabs/scrollable-tabs.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GlobalSearchTabsComponent extends ScrollableTabsComponent implements OnDestroy {
export class GlobalSearchTabsComponent extends ScrollableTabsComponent implements OnInit, OnDestroy {
private currentTabSub:Subscription;
private tabsSub:Subscription;
@ -53,13 +57,14 @@ export class GlobalSearchTabsComponent extends ScrollableTabsComponent implement
constructor(
readonly globalSearchService:GlobalSearchService,
protected readonly $state:StateService,
public injector:Injector,
cdRef:ChangeDetectorRef,
) {
super(cdRef, injector);
super($state, cdRef, injector);
}
ngOnInit() {
ngOnInit():void {
this.currentTabSub = this.globalSearchService
.currentTab$
.subscribe((currentTab) => {
@ -74,7 +79,7 @@ export class GlobalSearchTabsComponent extends ScrollableTabsComponent implement
});
}
public clickTab(tab:TabDefinition, event:Event) {
public clickTab(tab:TabDefinition, event:Event):void {
super.clickTab(tab, event);
this.globalSearchService.currentTab = tab.id;

@ -34,7 +34,7 @@ import { imagePath } from 'core-app/shared/helpers/images/path-helper';
export const homescreenNewFeaturesBlockSelector = 'homescreen-new-features-block';
// The key used in the I18n files to distinguish between versions.
const OpVersionI18n = '12_0';
const OpVersionI18n = '12_1';
@Component({
template: `
@ -64,7 +64,7 @@ const OpVersionI18n = '12_0';
export class HomescreenNewFeaturesBlockComponent {
public isStandardEdition:boolean;
new_features_image = imagePath('12_0_features.png');
new_features_image = imagePath('12_1_features.png');
public text = {
newFeatures: this.i18n.t('js.label_new_features'),

@ -10,6 +10,7 @@ import { BehaviorSubject } from 'rxjs';
import { SchemaCacheService } from 'core-app/core/schemas/schema-cache.service';
import { AuthorisationService } from 'core-app/core/model-auth/model-auth.service';
import { I18nService } from 'core-app/core/i18n/i18n.service';
import { OpCalendarService } from 'core-app/features/calendar/op-calendar.service';
@Injectable()
export class CalendarDragDropService {
@ -27,6 +28,7 @@ export class CalendarDragDropService {
constructor(
readonly authorisation:AuthorisationService,
readonly schemaCache:SchemaCacheService,
readonly calendarService:OpCalendarService,
readonly I18n:I18nService,
) {
}
@ -89,10 +91,7 @@ export class CalendarDragDropService {
return { disabled: true, reason: this.text.draggingDisabled.permissionDenied };
}
const schema = this.schemaCache.of(workPackage);
const schemaEditable = schema.isAttributeEditable('startDate') && schema.isAttributeEditable('dueDate');
if (!schemaEditable) {
if (!this.calendarService.dateEditable(workPackage)) {
return { disabled: true, reason: this.text.draggingDisabled.fallback };
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save