Merge remote-tracking branch 'origin/dev' into housekeeping/convert-fields-implementation

pull/6365/head
Oliver Günther 7 years ago
commit f5e8a218e6
No known key found for this signature in database
GPG Key ID: 88872239EB414F99
  1. 2
      app/controllers/my_controller.rb
  2. 2
      app/controllers/users_controller.rb
  3. 43
      app/views/users/_mail_notifications.html.erb
  4. 2
      app/views/wiki/_menu_pages_tree.html.erb
  5. 63
      frontend/src/app/modules/common/hide-section/show-section-dropdown.component.ts
  6. 6
      frontend/src/app/modules/common/openproject-common.module.ts
  7. 10
      lib/api/v3/work_packages/work_package_payload_representer.rb
  8. 20
      lib/api/v3/work_packages/work_package_representer.rb
  9. 11
      spec/features/auth/consent_auth_stage_spec.rb
  10. 2
      spec/features/work_packages/custom_actions_spec.rb
  11. 20
      spec/requests/api/v3/work_packages/dependent_errors_spec.rb
  12. 1
      spec/views/users/edit.html.erb_spec.rb

@ -32,6 +32,8 @@ class MyController < ApplicationController
include Concerns::PasswordConfirmation
layout 'my'
helper_method :gon
before_action :require_login
before_action :check_password_confirmation,
only: [:account],

@ -30,6 +30,8 @@
class UsersController < ApplicationController
layout 'admin'
helper_method :gon
before_action :disable_api
before_action :require_admin, except: [:show, :deletion_info, :destroy]
before_action :find_user, only: [:show,

@ -27,35 +27,44 @@ See docs/COPYRIGHT.rdoc for more details.
++#%>
<% active_sections = if @user.mail_notification == 'selected'
[{key: 'notified_projects'}]
else
[]
end %>
<%= initialize_hide_sections_with [{key: 'notified_projects'}], active_sections %>
<div class="form--field">
<%= styled_label_tag "user_mail_notification", t(:'user.settings.mail_notifications') %>
<div class="form--field-container">
<div class="form--select-container">
<%= styled_select_tag 'user[mail_notification]',
<show-section-dropdown opt-value="selected" hide-sec-with-name="notified_projects">
<%= styled_select_tag 'user[mail_notification]',
options_for_select(user_mail_notification_options(@user),
@user.mail_notification),
:'ng-model' => 'mail_notifications',
:'ng-init' => "mail_notifications = '#{@user.mail_notification}'",
container_class: '-wide' %>
</show-section-dropdown>
</div>
</div>
</div>
<%= content_tag 'div', id: 'notified-projects', class: "ng-cloak", :'ng-if' => "mail_notifications === 'selected'" do %>
<div class="form--field -no-label">
<div class="form--field-container -vertical">
<% @user.projects.each do |project| %>
<label class="form--label-with-check-box">
<%= styled_check_box_tag 'notified_project_ids[]', project.id, @user.notified_projects_ids.include?(project.id) %>
<%= project.name %>
</label>
<% end %>
</div>
<div class="form--field-instructions">
<%= t(:'user.settings.mail_project_explanaition') %>
</div>
<hide-section section-name="notified_projects">
<div id="notified-projects" class="form--field -no-label">
<div class="form--field-container -vertical">
<% @user.projects.each do |project| %>
<label class="form--label-with-check-box">
<%= styled_check_box_tag 'notified_project_ids[]', project.id, @user.notified_projects_ids.include?(project.id) %>
<%= project.name %>
</label>
<% end %>
</div>
<div class="form--field-instructions">
<%= t(:'user.settings.mail_project_explanaition') %>
</div>
</div>
<% end %>
</hide-section>
<div class="form--field">
<%= styled_label_tag 'self_notified', t(:'user.settings.mail_self_notified') %>

@ -1,7 +1,7 @@
<div class="menu-wiki-pages-tree tree-menu--container" data-selected-page="<%= @page.present? ? @page.slug : '' %>">
<% cache @project.wiki do %>
<div class="main-menu--segment-header ellipsis"><%= t('label_table_of_contents') %></div>
<% pages = @project.wiki.pages.order('title').includes(wiki: :project)
<% pages = @project.wiki.pages.order('title').includes(:project)
pages_by_parent_id = pages.group_by(&:parent_id) %>
<%= render_page_hierarchy(pages_by_parent_id, nil, timestamp: false) %>
<% end %>

@ -0,0 +1,63 @@
//-- copyright
// OpenProject is a project management system.
// Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
//
// 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-2017 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 docs/COPYRIGHT.rdoc for more details.
//++
import {Component, OnInit, ElementRef, Input} from '@angular/core';
import {opUiComponentsModule} from "core-app/angular-modules";
import {downgradeComponent} from '@angular/upgrade/static';
import {HideSectionService} from "core-app/modules/common/hide-section/hide-section.service";
@Component({
selector: 'show-section-dropdown',
template: '<ng-content></ng-content>'
})
export class ShowSectionDropdownComponent implements OnInit {
@Input() optValue:string; // value of option for which hide-section should be visible
@Input() hideSecWithName:string; // section-name of hide-section
constructor(protected hideSections:HideSectionService,
private elementRef:ElementRef) {
}
ngOnInit() {
jQuery(this.elementRef.nativeElement).change(event => {
let selectedOption = jQuery("option:selected", event.target);
if (selectedOption.val() !== this.optValue) {
this.hideSections.hide(this.hideSecWithName);
}
else {
this.hideSections.show({key: this.hideSecWithName, label: ""});
}
});
}
}
opUiComponentsModule.directive('showSectionDropdown',
downgradeComponent({component: ShowSectionDropdownComponent})
);

@ -59,6 +59,7 @@ import {FocusWithinDirective} from "core-app/modules/common/focus/focus-within.u
import {upgradeService} from "core-app/angular4-transition-utils";
import {FocusHelperService} from "core-app/modules/common/focus/focus-helper";
import {OpenprojectAccessibilityModule} from "core-app/modules/a11y/openproject-a11y.module";
import {ShowSectionDropdownComponent} from "core-app/modules/common/hide-section/show-section-dropdown.component";
const EXPORTED_DECLARATIONS = [
OpDatePickerComponent,
@ -90,6 +91,7 @@ const EXPORTED_DECLARATIONS = [
HideSectionComponent,
HideSectionLinkComponent,
AddSectionDropdownComponent,
ShowSectionDropdownComponent,
AutocompleteSelectDecorationComponent,
];
@ -103,6 +105,10 @@ const EXPORTED_DECLARATIONS = [
declarations: EXPORTED_DECLARATIONS,
entryComponents: [
OpDateTimeComponent,
ShowSectionDropdownComponent,
AddSectionDropdownComponent,
HideSectionComponent,
HideSectionLinkComponent,
NotificationsContainerComponent,
],
providers: [

@ -36,15 +36,13 @@ module API
cached_representer disabled: true
def initialize(model, current_user:, embed_links: false)
model = ::API::V3::WorkPackages::EagerLoading::NeutralWrapper.wrap_one(model, current_user)
super
end
def writeable_attributes
super + ["date"]
end
def load_complete_model(model)
model
end
end
end
end

@ -40,12 +40,7 @@ module API
disabled: false
def initialize(model, current_user:, embed_links: false)
# Define all accessors on the customizable as they
# will be used afterwards anyway. Otherwise, we will have to
# go through method_missing which will take more time.
model.define_all_custom_field_accessors
model = ::API::V3::WorkPackages::WorkPackageEagerLoadingWrapper.wrap_one(model, current_user)
model = load_complete_model(model)
super
end
@ -532,6 +527,15 @@ module API
'WorkPackage'
end
def to_hash(*args)
# Define all accessors on the customizable as they
# will be used afterwards anyway. Otherwise, we will have to
# go through method_missing which will take more time.
represented.define_all_custom_field_accessors
super
end
def watchers
# TODO/LEGACY: why do we need to ensure a specific order here?
watchers = represented.watcher_users.order(User::USER_FORMATS_STRUCTURE[Setting.user_format])
@ -639,6 +643,10 @@ module API
def view_time_entries_allowed?
current_user_allowed_to(:view_time_entries, context: represented.project)
end
def load_complete_model(model)
::API::V3::WorkPackages::WorkPackageEagerLoadingWrapper.wrap_one(model, current_user)
end
end
end
end

@ -32,7 +32,7 @@ describe 'Authentication Stages', type: :feature, js: true do
let(:language) { 'en' }
let(:user_password) { 'bob' * 4 }
let(:user) do
FactoryGirl.create(
FactoryBot.create(
:user,
admin: true,
force_password_change: false,
@ -48,7 +48,9 @@ describe 'Authentication Stages', type: :feature, js: true do
end
before do
Setting.consent_required = consent_required
allow(Setting)
.to receive(:consent_required?)
.and_return(consent_required)
end
def expect_logged_in
@ -61,7 +63,6 @@ describe 'Authentication Stages', type: :feature, js: true do
expect(page).to have_no_selector('.form--field-container', text: user.login)
end
context 'when disabled' do
let(:consent_required) { false }
it 'should not show consent' do
@ -84,7 +85,7 @@ describe 'Authentication Stages', type: :feature, js: true do
end
end
context 'when enabled, localized consent exists',
with_settings: { consent_info: { de: 'h1. Einwilligung', en: 'h1. Consent header!'} } do
with_settings: { consent_info: { de: 'h1. Einwilligung', en: 'h1. Consent header!' } } do
let(:consent_required) { true }
let(:language) { 'de' }
@ -96,7 +97,7 @@ describe 'Authentication Stages', type: :feature, js: true do
end
end
context 'when enabled, but consent exists', with_settings: { consent_info: { en: 'h1. Consent header!'} } do
context 'when enabled, but consent exists', with_settings: { consent_info: { en: 'h1. Consent header!' } } do
let(:consent_required) { true }
it 'should show consent' do
expect(Setting.consent_time).to be_blank

@ -138,7 +138,7 @@ describe 'Custom actions', type: :feature, js: true do
login_as(admin)
end
scenario 'viewing workflow buttons' do
scenario 'viewing workflow buttons', retry: 3 do
# create custom action 'Unassign'
index_ca_page.visit!

@ -35,7 +35,7 @@ describe 'API v3 Work package resource', type: :request, content_type: :json do
include API::V3::Utilities::PathHelper
let(:work_package) do
FactoryGirl.create(
FactoryBot.create(
:work_package,
project_id: project.id,
parent: parent,
@ -44,7 +44,7 @@ describe 'API v3 Work package resource', type: :request, content_type: :json do
end
let!(:parent) do
FactoryGirl.create(:work_package, project_id: project.id, type: type, subject: "Invalid Dependent WorkPackage").tap do |parent|
FactoryBot.create(:work_package, project_id: project.id, type: type, subject: "Invalid Dependent WorkPackage").tap do |parent|
parent.custom_values.create custom_field: custom_field, value: custom_field.possible_values.first.id
cv = parent.custom_values.last
@ -53,21 +53,21 @@ describe 'API v3 Work package resource', type: :request, content_type: :json do
end
let(:project) do
FactoryGirl.create(:project, identifier: 'deperr', is_public: false).tap do |project|
FactoryBot.create(:project, identifier: 'deperr', is_public: false).tap do |project|
project.types << type
end
end
let(:type) do
FactoryGirl.create(:type).tap do |type|
FactoryBot.create(:type).tap do |type|
type.custom_fields << custom_field
end
end
let(:status) { FactoryGirl.create :status }
let(:status) { FactoryBot.create :status }
let(:custom_field) do
FactoryGirl.create(
FactoryBot.create(
:list_wp_custom_field,
name: "Gate",
possible_values: %w(A B C),
@ -75,13 +75,13 @@ describe 'API v3 Work package resource', type: :request, content_type: :json do
)
end
let(:role) { FactoryGirl.create(:role, permissions: permissions) }
let(:role) { FactoryBot.create(:role, permissions: permissions) }
let(:permissions) { [:view_work_packages, :edit_work_packages, :create_work_packages] }
let(:current_user) do
user = FactoryGirl.create(:user, member_in_project: project, member_through_role: role)
user = FactoryBot.create(:user, member_in_project: project, member_through_role: role)
FactoryGirl.create(:user_preference, user: user, others: { no_self_notified: false })
FactoryBot.create(:user_preference, user: user, others: { no_self_notified: false })
user
end
@ -148,7 +148,7 @@ describe 'API v3 Work package resource', type: :request, content_type: :json do
end
describe '#post' do
let(:current_user) { FactoryGirl.create :admin }
let(:current_user) { FactoryBot.create :admin }
let(:path) { api_v3_paths.work_packages }
let(:valid_params) do

@ -35,6 +35,7 @@ describe 'users/edit', type: :view do
# The url_for is missing the users id that is usually taken
# from request parameters
controller.request.path_parameters[:id] = user.id
view.extend(Gon::ControllerHelpers)
end
context 'authentication provider' do

Loading…
Cancel
Save