Merge remote-tracking branch 'origin/release/12.4' into dev

docs-updates-for-12.5
Oliver Günther 2 years ago
commit 3807fd989f
No known key found for this signature in database
GPG Key ID: A3A8BDAD7C0C552C
  1. 4
      Gemfile.lock
  2. 2
      Gemfile.modules
  3. 2
      app/models/user_preference.rb
  4. 5
      app/views/roles/report.html.erb
  5. 2
      config/constants/settings/definitions.rb
  6. 2
      config/initializers/omniauth.rb
  7. 9
      docs/installation-and-operations/misc/custom-openid-connect-providers/README.md
  8. 2
      docs/user-guide/work-packages/set-change-dates/README.md
  9. 2
      modules/openid_connect/lib/open_project/openid_connect/engine.rb
  10. 2
      modules/openid_connect/lib/open_project/openid_connect/hooks/hook.rb
  11. 2
      modules/openid_connect/lib/open_project/openid_connect/session_mapper.rb
  12. 21
      modules/reporting/app/models/cost_query/custom_field_mixin.rb
  13. 15
      modules/reporting/app/models/cost_query/filter/custom_field_entries.rb
  14. 12
      modules/reporting/spec/features/custom_fields_spec.rb
  15. 3
      spec/features/notifications/reminder_mail_spec.rb
  16. 12
      spec/features/notifications/settings/immediate_reminder_spec.rb

@ -9,8 +9,8 @@ GIT
GIT
remote: https://github.com/opf/omniauth-openid-connect.git
revision: 5dfc1758ab010eca4aae8d0e0287ec4d9ec7a1ce
ref: 5dfc1758ab010eca4aae8d0e0287ec4d9ec7a1ce
revision: 0d2cd719e87021a14dd2b5cf8a6bf1831d4a497e
ref: 0d2cd71
specs:
omniauth-openid-connect (0.4.0)
addressable (~> 2.5)

@ -14,7 +14,7 @@ gem 'omniauth-openid_connect-providers',
gem 'omniauth-openid-connect',
git: 'https://github.com/opf/omniauth-openid-connect.git',
ref: '5dfc1758ab010eca4aae8d0e0287ec4d9ec7a1ce'
ref: '0d2cd71'
group :opf_plugins do
# included so that engines can reference OpenProject::Version

@ -132,7 +132,7 @@ class UserPreference < ApplicationRecord
end
def immediate_reminders
super.presence || { mentioned: false }.with_indifferent_access
super.presence || { mentioned: true }.with_indifferent_access
end
def pause_reminders

@ -39,13 +39,14 @@ See COPYRIGHT and LICENSE files for more details.
<% group_permissions_by_module(@permissions).each do |mod, mod_permissions| %>
<% module_name = mod.blank? ? "form--" + I18n.t('attributes.project') : "form--" + l_or_humanize(mod, prefix: 'project_module_').gsub(' ','_') %>
<fieldset class="form--fieldset -collapsible" id= "<%= module_name %>">
<% escaped_name = module_name.parameterize %>
<fieldset class="form--fieldset -collapsible" id= "<%= escaped_name %>">
<legend class="form--fieldset-legend" >
<%= mod.blank? ? I18n.t('attributes.project') : l_or_humanize(mod, prefix: 'project_module_') %>
</legend>
<div class="form--toolbar">
<span class="form--toolbar-item">
(<%= check_all_links module_name %>)
(<%= check_all_links escaped_name %>)
</span>
</div>

@ -525,7 +525,7 @@ Settings::Definition.define do
writable: true
add :log_level,
default: 'info',
default: Rails.env.development? ? 'debug' : 'info',
writable: false
add :log_requesting_user,

@ -26,6 +26,8 @@
# See COPYRIGHT and LICENSE files for more details.
#++
OmniAuth.config.logger = Rails.logger
Rails.application.config.middleware.use OmniAuth::Builder do
unless Rails.env.production?
provider :developer, fields: %i[first_name last_name email]

@ -259,10 +259,11 @@ OPENPROJECT_OPENID__CONNECT_KEYCLOAK_DISPLAY__NAME="Keycloak"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_HOST="<Hostname of the keycloak server>"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_IDENTIFIER="https://<Your OpenProject hostname>"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SECRET="<The client secret you copied from keycloak>"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_AUTHORIZATION__ENDPOINT="/realms/REALM/protocol/openid-connect/auth"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_TOKEN__ENDPOINT="/realms/REALM/protocol/openid-connect/token"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_USERINFO__ENDPOINT="/realms/REALM/protocol/openid-connect/userinfo"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_END__SESSION__ENDPOINT="http://<Hostname of the keycloak server>/realms/REALM/protocol/openid-connect/logout"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ISSUER="https://<Hostname of the keycloak server>/realms/<REALM>"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_AUTHORIZATION__ENDPOINT="/realms/<REALM>/protocol/openid-connect/auth"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_TOKEN__ENDPOINT="/realms/<REALM>/protocol/openid-connect/token"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_USERINFO__ENDPOINT="/realms/<REALM>/protocol/openid-connect/userinfo"
OPENPROJECT_OPENID__CONNECT_KEYCLOAK_END__SESSION__ENDPOINT="http://<Hostname of the keycloak server>/realms/<REALM>/protocol/openid-connect/logout"
# Optional, if you have created the client scope mapper as shown above
# OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ATTRIBUTE__MAP_LOGIN="preferred_username"
```

@ -133,7 +133,7 @@ Setting only duration without start or finish dates is especially useful when yo
> **Pro tip:** This feature makes it possible to automatically derive an estimated start or finish date for entire project.
>
> To do so, create a series of work packages that represent the main phases and set the approximate duration for each. Link them all using follow/precedes relationships. Now, when you set an end date on the last work package or a start date on the first one in the series, the start and end dates for all other work packages will be derived.
> To do so, create a series of work packages that represent the main phases and set the approximate duration for each. Link them all using follow/precedes relationships. Now, when you set a start date on the first work package in the series, the start and end dates for all other work packages will be derived.

@ -48,7 +48,7 @@ module OpenProject::OpenIDConnect
end
# Remember oidc session values when logging in user
h[:retain_from_session] = %w[omniauth.openid_sid]
h[:retain_from_session] = %w[omniauth.oidc_sid]
h[:backchannel_logout_callback] = ->(logout_token) do
::OpenProject::OpenIDConnect::SessionMapper.handle_logout(logout_token)

@ -34,7 +34,7 @@ module OpenProject::OpenIDConnect
# we want to map that to the internal session
def user_logged_in(context)
session = context[:session]
oidc_sid = session['omniauth.openid_sid']
oidc_sid = session['omniauth.oidc_sid']
return if oidc_sid.nil?
::OpenProject::OpenIDConnect::SessionMapper.handle_login(oidc_sid, session)

@ -22,7 +22,7 @@ module OpenProject::OpenIDConnect
attr_reader :session_link
delegate :oidc_session, to: :session_link
delegate :oidc_session, to: :session_link, allow_nil: true
def initialize(link)
@session_link = link

@ -109,32 +109,27 @@ module CostQuery::CustomFieldMixin
end
def list_join_table(field)
cast_as = SQL_TYPES[field.field_format]
cf_name = "custom_field#{field.id}"
custom_values_table = CustomValue.table_name
custom_options_table = CustomOption.table_name
# CustomValues of lists MAY have non-integer values when the list contained invalid values.
# Because of this, we do not cast the cv.value but rather the co.id
<<-SQL
-- BEGIN Custom Field Join: #{cf_name}
-- BEGIN Custom Field Join: #{db_field}
LEFT OUTER JOIN (
SELECT
CAST(co.value AS #{cast_as}) AS #{cf_name},
co.id AS #{db_field},
co.value,
cv.customized_type,
cv.custom_field_id,
cv.customized_id
FROM #{custom_values_table} cv
INNER JOIN #{custom_options_table} co
ON cv.custom_field_id = co.custom_field_id AND cv.value = co.id::VARCHAR
) AS #{cf_name}
ON #{cf_name}.customized_type = 'WorkPackage'
) AS #{db_field}
ON #{db_field}.customized_type = 'WorkPackage'
AND #{cf_name}.custom_field_id = #{field.id}
AND #{cf_name}.customized_id = entries.work_package_id
-- END Custom Field Join: #{cf_name}
AND #{db_field}.custom_field_id = #{field.id}
AND #{db_field}.customized_id = entries.work_package_id
-- END Custom Field Join: #{db_field}
SQL
end

@ -45,6 +45,21 @@ class CostQuery::Filter::CustomFieldEntries < Report::Filter::Base
end
end
def self.field
# There is a special treatment for how list custom values are retrieved as those
# are not taken directly from the custom_values but from the custom_options table.
# But the value still has to be the id of the option which is later on mapped to the
# human readable value.
# Mapping to the human readable value is done for all custom values (e.g. users, versions)
# following the same pattern of code, so simply making the exception here to use the value
# would complicated the code later on.
if custom_field.field_format == 'list'
"#{db_field}.value"
else
super
end
end
def self.available_values(*)
@possible_values || get_possible_values
end

@ -105,7 +105,7 @@ describe 'Custom fields reporting', js: true do
# Expect empty result table
within('#result-table') do
expect(page).to have_no_selector('.top.result', text: '12.50 hours')
expect(page).not_to have_selector('.top.result', text: '12.50 hours')
end
expect(page).to have_selector('.generic-table--no-results-title')
@ -132,8 +132,9 @@ describe 'Custom fields reporting', js: true do
# Expect row of work package
within('#result-table') do
expect(page).to have_selector('a.work_package', text: "#{work_package.type} ##{work_package.id}")
expect(page).to have_selector('th.inner', text: 'First option')
expect(page).to have_no_selector('th.inner', text: 'Second option')
# There used to be additional and unwanted text after the option name being rendered.
expect(page).to have_selector('th.inner', text: /^First option$/)
expect(page).not_to have_selector('th.inner', text: 'Second option')
# Only first option should have content for the work package
expect(page).to have_selector('table.report tbody tr', count: 1)
@ -188,13 +189,14 @@ describe 'Custom fields reporting', js: true do
select 'Invalid List CF', from: 'group-by--add-columns'
select 'Work package', from: 'group-by--add-rows'
sleep(0.1)
click_link 'Apply'
# Expect row of work package
within('#result-table') do
expect(page).to have_selector('a.work_package', text: "#{work_package.type} ##{work_package.id}")
expect(page).to have_selector('th.inner', text: '1')
expect(page).to have_no_selector('th.inner', text: 'invalid!')
expect(page).not_to have_selector('th.inner', text: 'invalid!')
end
end
end
@ -227,7 +229,7 @@ describe 'Custom fields reporting', js: true do
within('#result-table') do
expect(page).to have_selector('a.work_package', text: "#{work_package.type} ##{work_package.id}")
expect(page).to have_selector('th.inner', text: 'foo')
expect(page).to have_no_selector('th.inner', text: 'None')
expect(page).not_to have_selector('th.inner', text: 'None')
# Only first option should have content for the work package
expect(page).to have_selector('table.report tbody tr', count: 1)

@ -32,6 +32,9 @@ describe "Reminder email sending", js: true do
daily_reminders: {
enabled: true,
times: [hitting_reminder_slot_for('Pacific/Honolulu', current_utc_time)]
},
immediate_reminders: {
mentioned: false
}
},
notification_settings: [

@ -9,11 +9,11 @@ describe "Immediate reminder settings", js: true do
# Configure the reminders
reminders_settings_page.visit!
# By default the immediate reminder is unchecked
expect(pref.immediate_reminders[:mentioned]).to be false
reminders_settings_page.expect_immediate_reminder :mentioned, false
# By default the immediate reminder is checked
expect(pref.immediate_reminders[:mentioned]).to be true
reminders_settings_page.expect_immediate_reminder :mentioned, true
reminders_settings_page.set_immediate_reminder :mentioned, true
reminders_settings_page.set_immediate_reminder :mentioned, false
reminders_settings_page.save
@ -21,9 +21,9 @@ describe "Immediate reminder settings", js: true do
reminders_settings_page.reload!
reminders_settings_page.expect_immediate_reminder :mentioned, true
reminders_settings_page.expect_immediate_reminder :mentioned, false
expect(pref.reload.immediate_reminders[:mentioned]).to be true
expect(pref.reload.immediate_reminders[:mentioned]).to be false
end
end

Loading…
Cancel
Save