diff --git a/.codeclimate.yml b/.codeclimate.yml
index f114b0b5a9..f00891fd1e 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -1,8 +1,30 @@
---
+version: "2"
languages:
Ruby: true
JavaScript: true
-engines:
+checks:
+ file-lines:
+ enabled: false
+ method-count:
+ enabled: false
+ method-lines:
+ enabled: false
+ method-complexity:
+ enabled: true
+ config:
+ threshold: 10
+ complex-logic:
+ enabled: true
+ config:
+ threshold: 10
+ # Similar codes trips up at the long TS/angular injection
+ # constructors all the time, which are similar by nature.
+ similar-code:
+ enabled: false
+ identical-code:
+ enabled: true
+plugins:
rubocop:
enabled: true
brakeman:
@@ -35,6 +57,8 @@ exclude_paths:
- .bundle/**/*
- lib/plugins/rfpdf/**/*
- frontend/vendor/**/*
+ - "**/*.d.ts"
+ - "**/node_modules/"
- spec/**
- spec_legacy/**/*
- lib/redcloth3.rb
diff --git a/Gemfile b/Gemfile
index f8868a5dd5..3d954896bc 100644
--- a/Gemfile
+++ b/Gemfile
@@ -153,9 +153,6 @@ gem 'cocaine', '~> 0.5.8'
# also, better than thin since we can control worker concurrency.
gem 'unicorn'
-# Puma server for development and on paas.
-gem 'puma', '~> 3.11.3'
-
gem 'nokogiri', '~> 1.8.2'
# carrierwave 0.11.3 should allow to use fog-aws without the rest of the
@@ -237,6 +234,7 @@ group :development do
end
group :development, :test do
+ gem 'puma', '~> 3.11.3'
gem 'pry-rails', '~> 0.3.6'
gem 'pry-stack_explorer', '~> 0.4.9.2'
@@ -267,6 +265,7 @@ group :opf_plugins do
end
group :docker, optional: true do
+ gem 'passenger', '~> 5.2'
# Used to easily precompile assets
gem 'sqlite3', require: false
gem 'rails_12factor', require: !!ENV['HEROKU']
diff --git a/Gemfile.lock b/Gemfile.lock
index be1a3fb778..ec50ee9dee 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -371,6 +371,9 @@ GEM
parallel
parser (2.4.0.0)
ast (~> 2.2)
+ passenger (5.2.1)
+ rack
+ rake (>= 0.8.1)
pdf-core (0.7.0)
pg (0.21.0)
plaintext (0.1.0)
@@ -661,6 +664,7 @@ DEPENDENCIES
openproject-token (~> 1.0.1)
openproject-translations!
parallel_tests (~> 2.14.0)
+ passenger (~> 5.2)
pg (~> 0.21.0)
plaintext (= 0.1.0)
prawn (~> 2.2)
diff --git a/app/models/queries/work_packages.rb b/app/models/queries/work_packages.rb
index 8331b80b72..09f558c55e 100644
--- a/app/models/queries/work_packages.rb
+++ b/app/models/queries/work_packages.rb
@@ -57,6 +57,7 @@ module Queries::WorkPackages
register.filter Query, filters_module::UpdatedAtFilter
register.filter Query, filters_module::VersionFilter
register.filter Query, filters_module::WatcherFilter
+ register.filter Query, filters_module::ParentFilter
columns_module = Queries::WorkPackages::Columns
diff --git a/app/models/queries/work_packages/filter/filter_for_wp_mixing.rb b/app/models/queries/work_packages/filter/filter_for_wp_mixing.rb
new file mode 100644
index 0000000000..3f4fbf5075
--- /dev/null
+++ b/app/models/queries/work_packages/filter/filter_for_wp_mixing.rb
@@ -0,0 +1,75 @@
+#-- encoding: UTF-8
+
+#-- 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.
+#++
+
+module Queries::WorkPackages::Filter::FilterForWpMixin
+ def type
+ :list
+ end
+
+ def allowed_values
+ raise NotImplementedError, 'There would be too many candidates'
+ end
+
+ def value_objects
+ scope.find(values)
+ end
+
+ def allowed_objects
+ raise NotImplementedError, 'There would be too many candidates'
+ end
+
+ def available?
+ scope.exists?
+ end
+
+ def ar_object_filter?
+ true
+ end
+
+ def allowed_values_subset
+ scope.where(id: values).pluck(:id).map(&:to_s)
+ end
+
+ private
+
+ def scope
+ if context.project
+ WorkPackage
+ .visible
+ .for_projects(context.project.self_and_descendants)
+ else
+ WorkPackage.visible
+ end
+ end
+
+ def type_strategy
+ @type_strategy ||= Queries::Filters::Strategies::HugeList.new(self)
+ end
+end
diff --git a/app/models/queries/work_packages/filter/id_filter.rb b/app/models/queries/work_packages/filter/id_filter.rb
index f9b163ef96..8337525391 100644
--- a/app/models/queries/work_packages/filter/id_filter.rb
+++ b/app/models/queries/work_packages/filter/id_filter.rb
@@ -28,48 +28,10 @@
# See docs/COPYRIGHT.rdoc for more details.
#++
-class Queries::WorkPackages::Filter::IdFilter < Queries::WorkPackages::Filter::WorkPackageFilter
- def type
- :list
- end
+require_relative './filter_for_wp_mixing'
- def allowed_values
- raise NotImplementedError, 'There would be too many candidates'
- end
+class Queries::WorkPackages::Filter::IdFilter <
+ Queries::WorkPackages::Filter::WorkPackageFilter
- def value_objects
- raise NotImplementedError, 'There would be too many candidates'
- end
-
- def allowed_objects
- raise NotImplementedError, 'There would be too many candidates'
- end
-
- def available?
- scope.exists?
- end
-
- def ar_object_filter?
- true
- end
-
- def allowed_values_subset
- scope.where(id: values).pluck(:id).map(&:to_s)
- end
-
- private
-
- def scope
- if context.project
- WorkPackage
- .visible
- .for_projects(context.project.self_and_descendants)
- else
- WorkPackage.visible
- end
- end
-
- def type_strategy
- @type_strategy ||= Queries::Filters::Strategies::HugeList.new(self)
- end
+ include ::Queries::WorkPackages::Filter::FilterForWpMixin
end
diff --git a/app/models/queries/work_packages/filter/parent_filter.rb b/app/models/queries/work_packages/filter/parent_filter.rb
new file mode 100644
index 0000000000..47c1f6d4b8
--- /dev/null
+++ b/app/models/queries/work_packages/filter/parent_filter.rb
@@ -0,0 +1,47 @@
+#-- encoding: UTF-8
+
+#-- 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.
+#++
+
+require_relative './filter_for_wp_mixing'
+
+class Queries::WorkPackages::Filter::ParentFilter <
+ Queries::WorkPackages::Filter::WorkPackageFilter
+
+ include ::Queries::WorkPackages::Filter::FilterForWpMixin
+
+ def includes
+ :parent_relation
+ end
+
+ def where
+ operator_strategy.sql_for_field(values,
+ Relation.table_name,
+ 'from_id')
+ end
+end
diff --git a/app/models/queries/work_packages/filter/type_filter.rb b/app/models/queries/work_packages/filter/type_filter.rb
index fba3785f64..a64b914812 100644
--- a/app/models/queries/work_packages/filter/type_filter.rb
+++ b/app/models/queries/work_packages/filter/type_filter.rb
@@ -1,4 +1,5 @@
#-- encoding: UTF-8
+
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2018 the OpenProject Foundation (OPF)
diff --git a/app/models/work_package.rb b/app/models/work_package.rb
index ea178b8d39..7b9a62d33c 100644
--- a/app/models/work_package.rb
+++ b/app/models/work_package.rb
@@ -299,6 +299,12 @@ class WorkPackage < ActiveRecord::Base
project && type ? (project.all_work_package_custom_fields & type.custom_fields) : []
end
+ # aliasing subject to name
+ # using :alias is not possible as AR will add the subject method later
+ def name
+ subject
+ end
+
def status_id=(sid)
self.status = nil
write_attribute(:status_id, sid)
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 1679d5574f..5a3a8c8ef8 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -52,15 +52,7 @@ OpenProject::Application.configure do
# config.action_dispatch.rack_cache = true
# Enable Rails's static asset server when requested
- if OpenProject::Configuration.enable_internal_assets_server?
- config.public_file_server.enabled = true
- config.public_file_server.headers = {
- 'Access-Control-Allow-Origin' => '*',
- 'Access-Control-Allow-Methods' => 'GET, OPTIONS, HEAD',
- 'Cache-Control' => 'public, s-maxage=31536000, max-age=15552000',
- 'Expires' => "#{1.year.from_now.to_formatted_s(:rfc822)}"
- }
- end
+ config.public_file_server.enabled = false
# Compress JavaScripts and CSS.
config.assets.js_compressor = nil
diff --git a/config/locales/crowdin/hu.yml b/config/locales/crowdin/hu.yml
index 4a75073896..813996b964 100644
--- a/config/locales/crowdin/hu.yml
+++ b/config/locales/crowdin/hu.yml
@@ -2225,7 +2225,7 @@ hu:
text_journal_aggregation_time_explanation: Fűzze össze a tartalmat az értesítésekben,
amennyiben az idő kisebb, mint a megadott érték. Ez ugyanúgy késleltetheti az
e-mail kiküldését.
- text_journal_changed: "%{label} changed from %{old} to %{new}"
+ text_journal_changed: "%{label} megváltoztatva %{old} %{new}"
text_journal_changed_no_detail: "%{label} frissítve"
text_journal_changed_with_diff: "%{label} megváltozott (%{link})"
text_journal_deleted: "%{label} törölve (%{old})"
diff --git a/config/locales/crowdin/js-lt.yml b/config/locales/crowdin/js-lt.yml
index 5e3187bb7d..dd852f8948 100644
--- a/config/locales/crowdin/js-lt.yml
+++ b/config/locales/crowdin/js-lt.yml
@@ -6,10 +6,10 @@ lt:
loading: Įkeliama ...
autocomplete_select:
placeholder:
- multi: Add "%{name}"
- single: Select "%{name}"
- remove: Remove %{name}
- active: Active %{label} %{name}
+ multi: Pridėti „%{name}“
+ single: Pasirinkti „%{name}“
+ remove: Pašalinti %{name}
+ active: Aktyvus %{label} %{name}
close_popup_title: Užverti iškylantį langą
close_filter_title: Užverti filtrą
close_form_title: Užverti formą
@@ -71,8 +71,8 @@ lt:
one: Pirmasis rikiavimo kriterijus
two: Antrasis rikiavimo kriterijus
three: Trečiasis rikiavimo kriterijus
- upsale_for_more: For more advanced filters, check out the
- upsale_link: Enterprise Edition.
+ upsale_for_more: Norėdami naudoti daugiau papildomų filtrų, patikrinkite
+ upsale_link: "„Enterprise Edition“."
general_text_no: ne
general_text_yes: taip
general_text_No: Ne
diff --git a/config/locales/crowdin/lt.yml b/config/locales/crowdin/lt.yml
index c35d65583e..c4c191c77a 100644
--- a/config/locales/crowdin/lt.yml
+++ b/config/locales/crowdin/lt.yml
@@ -61,16 +61,16 @@ lt:
custom_actions:
actions:
name: Veiksmai
- add: Add action
- conditions: Conditions
- plural: Custom actions
- new: New custom action
- edit: Edit custom action %{name}
- execute: Execute %{name}
+ add: Pridėti veiksmą
+ conditions: Sąlygos
+ plural: Pasirinktiniai veiksmai
+ new: Naujas pasirinktinis veiksmas
+ edit: Redaguoti pasirinktinį veiksmą %{name}
+ execute: Vykdyti %{name}
upsale:
- title: Custom actions is an Enterprise Edition feature
- description: Custom actions streamline everyday work by combining a set of individual
- steps into one button.
+ title: Pasirinktiniai veiksmai yra „Enterprise Edition“ funkcija
+ description: Pasirinktiniai veiksmai supaprastina kasdienį darbą suderindami
+ atskirus žingsnius į vieną mygtuką.
custom_fields:
text_add_new_custom_field: 'Norėdami pridėti naujus pritaikytus laukelius prie
projekto, pirmiausia reikia juos sukurti. Tik tada yra galimybė juos pridėti
@@ -271,8 +271,8 @@ lt:
announcements:
show_until: Rodyti iki
attachment:
- attachment_content: Attachment content
- attachment_file_name: Attachment file name
+ attachment_content: Prisegto failo turinys
+ attachment_file_name: Prisegto failo vardas
downloads: Atsisiuntimai
file: Failas
filename: Failas
@@ -453,12 +453,12 @@ lt:
custom_field:
at_least_one_custom_option: Turi būti prieinama bent viena savybė.
custom_actions:
- only_one_allowed: "(%{name}) only one value is allowed."
- empty: "(%{name}) value can't be empty."
- inclusion: "(%{name}) value is not set to one of the allowed values."
- not_an_integer: "(%{name}) is not an integer."
- smaller_than_or_equal_to: "(%{name}) must be smaller than or equal to %{count}."
- greater_than_or_equal_to: "(%{name}) must be greater than or equal to %{count}."
+ only_one_allowed: leidžiama (%{name}) tik viena reikšmė.
+ empty: "(%{name}) reikšmė negali būti tuščia."
+ inclusion: "(%{name}) nenustatyta kaip viena iš leidžiamų reikšmių."
+ not_an_integer: "(%{name}) nėra sveikasis skaičius."
+ smaller_than_or_equal_to: "(%{name}) turi būti mažesnis arba lygus %{count}."
+ greater_than_or_equal_to: "(%{name}) turi būti didesnis arba lygus %{count}."
enterprise_token:
unreadable: neįmanoma perskaityti. Ar tai tikrai yra paramos raktas?
parse_schema_filter_params_service:
@@ -571,7 +571,7 @@ lt:
attribute_help_text: Atributo pagalbos tekstas
board: Forumas
comment: Komentaras
- custom_action: Custom action
+ custom_action: Pasirinktinis veiksmas
custom_field: Kliento laukelis
group: Grupė
category: Kategorija
@@ -1026,12 +1026,12 @@ lt:
pdf_with_descriptions: PDF su aprašymu
extraction:
available:
- pdftotext: Pdftotext available (optional)
- unrtf: Unrtf available (optional)
- catdoc: Catdoc available (optional)
- xls2csv: Xls2csv available (optional)
- catppt: Catppt available (optional)
- tesseract: Tesseract available (optional)
+ pdftotext: Pdf-į-tekstą pasiekiamas (pasirinktinai)
+ unrtf: Unrtf pasiekiamas (pasirinktinai)
+ catdoc: Catdoc pasiekiamas (pasirinktinai)
+ xls2csv: Xls2csv pasiekiamas (pasirinktinai)
+ catppt: Catppt pasiekiamas (pasirinktinai)
+ tesseract: Tesseract pasiekiamas (pasirinktinai)
general_csv_decimal_separator: "."
general_csv_encoding: UTF-8
general_csv_separator: ","
@@ -2107,7 +2107,7 @@ lt:
setting_file_max_size_displayed: Maksimalus tekstinių failų dydis rodomas vienoje
eilutėje
setting_host_name: Šeimininko vardas
- setting_invitation_expiration_days: Activation E-Mail expires after
+ setting_invitation_expiration_days: Aktyvavimo laiškas baigia galioti po
setting_work_package_done_ratio: Skaičiuoti darbų paketo atlikimo santykį su
setting_work_package_done_ratio_field: Naudoti darbų paketo laukelį
setting_work_package_done_ratio_status: Naudoti darbų paketo būseną
@@ -2171,7 +2171,7 @@ lt:
setting_accessibility_mode_for_anonymous: Leisti lengvos prieigos režimą anoniminiams
vartotojams
setting_user_format: Vartotojo atvaizdavimo formatas
- setting_user_default_timezone: Users default time zone
+ setting_user_default_timezone: Numatytoji vartotojo laiko juosta
setting_users_deletable_by_admins: Administratoriai gali ištrinti vartotojų paskyras
setting_users_deletable_by_self: Vartotojai gali ištrinti savo paskyras
setting_welcome_text: Pasisveikinimo bloko tekstas
@@ -2243,7 +2243,7 @@ lt:
naudojant iOS.
'
- text_database_allows_tsv: Database allows TSVector (optional)
+ text_database_allows_tsv: Duomenų bazė leidžia TSVector (pasirinktinai)
text_default_administrator_account_changed: Administratoriaus numatytoji paskyra
pakeista
text_default_encoding: 'Numatytasis: UTF-8'
@@ -2281,7 +2281,7 @@ lt:
text_journal_aggregation_time_explanation: Kombinuoti žurnalus rodymui, ar jų amžius
skiriasi mažiau nei nustatyta trukmė. Tai taip pat vėlins įspėjimo el. laiškų
atsiuntimą tokia pat laiko trukme.
- text_journal_changed: "%{label} changed from %{old} to %{new}"
+ text_journal_changed: "%{label} pakeista iš %{old} į %{new}"
text_journal_changed_no_detail: "%{label} atnaujintas"
text_journal_changed_with_diff: "%{label} pasikeitė (%{link})"
text_journal_deleted: "%{label} ištrintas (%{old})"
@@ -2543,8 +2543,8 @@ lt:
years: Metai(-ų)
title_remove_and_delete_user: Pašalinti pakviestą vartotoją iš projekto ir ištrinti
jį/ją.
- tooltip_user_default_timezone: 'The default time zone for new users. Can be changed
- in a user''s settings.
+ tooltip_user_default_timezone: 'Numatytoji laiko juosta naujiems vartotojams. Gali
+ būti pakeista vartotojo nustatymuose.
'
tooltip_resend_invitation: 'Siunčia naują pakvietimo laišką su nauju atpažinimo
@@ -2620,9 +2620,11 @@ lt:
warning: Įspėjimas
warning_attachments_not_saved: "%{count} failas (-ai, -ų) negali būti išsaugotas
(-i)."
- warning_registration_token_expired: |
- The activation email has expired. We sent you a new one to %{email}.
- Please click the link inside of it to activate your account.
+ warning_registration_token_expired: 'Aktyvavimo el. laiško galiojimas pasibaigė.
+ Išsiuntėme jums naują %{email}. Paspauskite laiške duotą nuorodą, kad aktyvuotumėte
+ savo paskyrą.
+
+'
menu_item: Meniu punktas
menu_item_setting: Matomumas
wiki_menu_item_for: Meniu punktas wiki puslapiui „%{title}“
diff --git a/config/locales/crowdin/ru.yml b/config/locales/crowdin/ru.yml
index 4c537ea085..2525565721 100644
--- a/config/locales/crowdin/ru.yml
+++ b/config/locales/crowdin/ru.yml
@@ -2279,7 +2279,7 @@ ru:
text_journal_aggregation_time_explanation: Объединить журналы для отображения, если
разница в их возрасте меньше заданного значения. Это приведет к задержке почтовых
уведомлений на указанное время.
- text_journal_changed: "%{label} changed from %{old} to %{new}"
+ text_journal_changed: "%{label} изменено с %{old} на %{new}"
text_journal_changed_no_detail: "%{label} обновлено"
text_journal_changed_with_diff: "%{label} изменена (%{link})"
text_journal_deleted: "%{label} удалена (%{old})"
diff --git a/config/puma.rb b/config/puma.rb
new file mode 100644
index 0000000000..503121e660
--- /dev/null
+++ b/config/puma.rb
@@ -0,0 +1,143 @@
+#!/usr/bin/env puma
+
+# Load "path" as a rackup file.
+#
+# The default is "config.ru".
+#
+# rackup '/u/apps/lolcat/config.ru'
+
+# Set the port on which puma binds
+port ENV['PORT'] || 3000
+
+# Set the environment in which the rack's app will run. The value must be a string.
+#
+# The default is "development".
+#
+# environment 'production'
+environment ENV['RAILS_ENV'] || 'development'
+
+# Disable request logging.
+#
+# The default is "false".
+#
+# quiet
+
+# Configure "min" to be the minimum number of threads to use to answer
+# requests and "max" the maximum.
+#
+# The default is "0, 16".
+#
+threads 1, 1
+
+# Code to run before doing a restart. This code should
+# close log files, database connections, etc.
+#
+# This can be called multiple times to add code each time.
+#
+# on_restart do
+# puts 'On restart...'
+# end
+
+
+# Command to use to restart puma. This should be just how to
+# load puma itself (ie. 'ruby -Ilib bin/puma'), not the arguments
+# to puma, as those are the same as the original process.
+#
+# restart_command '/u/app/lolcat/bin/restart_puma'
+
+# === Cluster mode ===
+
+# How many worker processes to run. Typically this is set to
+# to the number of available cores.
+#
+# The default is "0".
+#
+workers ENV['WEB_CONCURRENCY'] || 4
+
+# Code to run immediately before the master starts workers.
+#
+# before_fork do
+# puts "Starting workers..."
+# end
+
+# Code to run in a worker before it starts serving requests.
+#
+# This is called everytime a worker is to be started.
+#
+on_worker_boot do
+ ActiveRecord::Base.establish_connection
+end
+
+# Code to run in a worker right before it exits.
+#
+# This is called everytime a worker is to about to shutdown.
+#
+# on_worker_shutdown do
+# puts 'On worker shutdown...'
+# end
+
+# Code to run in the master right before a worker is started. The worker's
+# index is passed as an argument.
+#
+# This is called everytime a worker is to be started.
+#
+# on_worker_fork do
+# puts 'Before worker fork...'
+# end
+
+# Code to run in the master after a worker has been started. The worker's
+# index is passed as an argument.
+#
+# This is called everytime a worker is to be started.
+#
+# after_worker_fork do
+# puts 'After worker fork...'
+# end
+
+# Allow workers to reload bundler context when master process is issued
+# a USR1 signal. This allows proper reloading of gems while the master
+# is preserved across a phased-restart. (incompatible with preload_app)
+# (off by default)
+
+# prune_bundler
+
+# Preload the application before starting the workers; this conflicts with
+# phased restart feature. (off by default)
+
+preload_app! if ENV['RAILS_ENV'] == 'production'
+
+# Additional text to display in process listing
+#
+# tag 'app name'
+#
+# If you do not specify a tag, Puma will infer it. If you do not want Puma
+# to add a tag, use an empty string.
+
+# Verifies that all workers have checked in to the master process within
+# the given timeout. If not the worker process will be restarted. This is
+# not a request timeout, it is to protect against a hung or dead process.
+# Setting this value will not protect against slow requests.
+# Default value is 60 seconds.
+#
+# worker_timeout 60
+
+# Change the default worker timeout for booting
+#
+# If unspecified, this defaults to the value of worker_timeout.
+#
+# worker_boot_timeout 60
+
+# === Puma control rack application ===
+
+# Start the puma control rack application on "url". This application can
+# be communicated with to control the main server. Additionally, you can
+# provide an authentication token, so all requests to the control server
+# will need to include that token as a query parameter. This allows for
+# simple authentication.
+#
+# Check out https://github.com/puma/puma/blob/master/lib/puma/app/status.rb
+# to see what the app has available.
+#
+# activate_control_app 'unix:///var/run/pumactl.sock'
+# activate_control_app 'unix:///var/run/pumactl.sock', { auth_token: '12345' }
+# activate_control_app 'unix:///var/run/pumactl.sock', { no_token: true }
diff --git a/frontend/app/components/wp-fast-table/wp-table-filters.ts b/frontend/app/components/wp-fast-table/wp-table-filters.ts
index 88b69d7f6c..d457f9df37 100644
--- a/frontend/app/components/wp-fast-table/wp-table-filters.ts
+++ b/frontend/app/components/wp-fast-table/wp-table-filters.ts
@@ -78,8 +78,8 @@ export class WorkPackageTableFilters extends WorkPackageTableBaseState (schema.filter.allowedValues as QueryFilterResource[])[0]);
- // We do not use the id filter as of now as we do not have adequate
+ // We do not use the filters id and parent as of now as we do not have adequate
// means to select the values.
- return _.filter(availableFilters, filter => filter.id !== 'id');
+ return _.filter(availableFilters, filter => filter.id !== 'id' && filter.id !== 'parent');
}
}
diff --git a/lib/api/v3/queries/schemas/by_work_package_filter_dependency_representer.rb b/lib/api/v3/queries/schemas/by_work_package_filter_dependency_representer.rb
new file mode 100644
index 0000000000..910f12e8a2
--- /dev/null
+++ b/lib/api/v3/queries/schemas/by_work_package_filter_dependency_representer.rb
@@ -0,0 +1,59 @@
+#-- encoding: UTF-8
+
+#-- 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.
+#++
+
+module API
+ module V3
+ module Queries
+ module Schemas
+ class ByWorkPackageFilterDependencyRepresenter <
+ FilterDependencyRepresenter
+
+ def json_cache_key
+ super + (filter.project.present? ? [filter.project.id] : [])
+ end
+
+ def href_callback
+ if filter.project
+ api_v3_paths.work_packages_by_project(filter.project.id)
+ else
+ api_v3_paths.work_packages
+ end
+ end
+
+ private
+
+ def type
+ '[]WorkPackage'
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/v3/queries/schemas/id_filter_dependency_representer.rb b/lib/api/v3/queries/schemas/id_filter_dependency_representer.rb
index 7ca259f011..6e015550cc 100644
--- a/lib/api/v3/queries/schemas/id_filter_dependency_representer.rb
+++ b/lib/api/v3/queries/schemas/id_filter_dependency_representer.rb
@@ -32,27 +32,7 @@ module API
module V3
module Queries
module Schemas
- class IdFilterDependencyRepresenter <
- FilterDependencyRepresenter
-
- def json_cache_key
- super + (filter.project.present? ? [filter.project.id] : [])
- end
-
- def href_callback
- if filter.project
- api_v3_paths.work_packages_by_project(filter.project.id)
- else
- api_v3_paths.work_packages
- end
- end
-
- private
-
- def type
- '[]WorkPackage'
- end
- end
+ class IdFilterDependencyRepresenter < ByWorkPackageFilterDependencyRepresenter; end
end
end
end
diff --git a/lib/api/v3/queries/schemas/parent_filter_dependency_representer.rb b/lib/api/v3/queries/schemas/parent_filter_dependency_representer.rb
new file mode 100644
index 0000000000..dd3109decb
--- /dev/null
+++ b/lib/api/v3/queries/schemas/parent_filter_dependency_representer.rb
@@ -0,0 +1,39 @@
+#-- encoding: UTF-8
+
+#-- 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.
+#++
+
+module API
+ module V3
+ module Queries
+ module Schemas
+ class ParentFilterDependencyRepresenter < ByWorkPackageFilterDependencyRepresenter; end
+ end
+ end
+ end
+end
diff --git a/lib/open_project/configuration.rb b/lib/open_project/configuration.rb
index cfa524842b..6f3d4b5c48 100644
--- a/lib/open_project/configuration.rb
+++ b/lib/open_project/configuration.rb
@@ -65,8 +65,6 @@ module OpenProject
'rails_relative_url_root' => '',
'rails_force_ssl' => false,
'rails_asset_host' => nil,
- # Enable internal asset server
- 'enable_internal_assets_server' => false,
# user configuration
'default_comment_sort_order' => 'asc',
diff --git a/spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb
new file mode 100644
index 0000000000..a93ee60c17
--- /dev/null
+++ b/spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb
@@ -0,0 +1,133 @@
+#-- 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.
+#++
+
+require 'spec_helper'
+
+describe ::API::V3::Queries::Schemas::ParentFilterDependencyRepresenter, clear_cache: true do
+ include ::API::V3::Utilities::PathHelper
+
+ let(:project) { FactoryGirl.build_stubbed(:project) }
+ let(:query) { FactoryGirl.build_stubbed(:query, project: project) }
+ let(:filter) { Queries::WorkPackages::Filter::ParentFilter.create!(context: query) }
+ let(:form_embedded) { false }
+
+ let(:instance) do
+ described_class.new(filter,
+ operator,
+ form_embedded: form_embedded)
+ end
+
+ subject(:generated) { instance.to_json }
+
+ context 'generation' do
+ context 'properties' do
+ describe 'values' do
+ context 'within project' do
+ let(:path) { 'values' }
+ let(:type) { '[]WorkPackage' }
+ let(:href) { api_v3_paths.work_packages_by_project(project.id) }
+
+ context "for operator 'Queries::Operators::Equals'" do
+ let(:operator) { Queries::Operators::Equals }
+
+ it_behaves_like 'filter dependency with allowed link'
+ end
+
+ context "for operator 'Queries::Operators::NotEquals'" do
+ let(:operator) { Queries::Operators::NotEquals }
+
+ it_behaves_like 'filter dependency with allowed link'
+ end
+ end
+
+ context 'outside of a project' do
+ let(:project) { nil }
+ let(:path) { 'values' }
+ let(:type) { '[]WorkPackage' }
+ let(:href) { api_v3_paths.work_packages }
+
+ context "for operator 'Queries::Operators::Equals'" do
+ let(:operator) { Queries::Operators::Equals }
+
+ it_behaves_like 'filter dependency with allowed link'
+ end
+
+ context "for operator 'Queries::Operators::NotEquals'" do
+ let(:operator) { Queries::Operators::NotEquals }
+
+ it_behaves_like 'filter dependency with allowed link'
+ end
+ end
+ end
+ end
+
+ describe 'caching' do
+ let(:operator) { Queries::Operators::Equals }
+ let(:other_project) { FactoryGirl.build_stubbed(:project) }
+
+ before do
+ # fill the cache
+ instance.to_json
+ end
+
+ it 'is cached' do
+ expect(instance)
+ .not_to receive(:to_hash)
+
+ instance.to_json
+ end
+
+ it 'busts the cache on a different operator' do
+ instance.send(:operator=, Queries::Operators::NotEquals)
+
+ expect(instance)
+ .to receive(:to_hash)
+
+ instance.to_json
+ end
+
+ it 'busts the cache on a different project' do
+ query.project = other_project
+
+ expect(instance)
+ .to receive(:to_hash)
+
+ instance.to_json
+ end
+
+ it 'busts the cache on changes to the locale' do
+ expect(instance)
+ .to receive(:to_hash)
+
+ I18n.with_locale(:de) do
+ instance.to_json
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/open_project/configuration_spec.rb b/spec/lib/open_project/configuration_spec.rb
index 2208650d4b..2e9aedd3e9 100644
--- a/spec/lib/open_project/configuration_spec.rb
+++ b/spec/lib/open_project/configuration_spec.rb
@@ -243,6 +243,8 @@ describe OpenProject::Configuration do
Setting[:email_delivery_method] = nil
# reload configuration to isolate specs
OpenProject::Configuration.load
+ # clear settings cache to isolate specs
+ Setting.clear_cache
end
it 'does nothing if no legacy configuration given' do
@@ -292,6 +294,8 @@ describe OpenProject::Configuration do
after do
# reload configuration to isolate specs
OpenProject::Configuration.load
+ # clear settings cache to isolate specs
+ Setting.clear_cache
end
it 'uses the legacy method to configure email settings' do
diff --git a/spec/models/queries/work_packages/filter/id_filter_spec.rb b/spec/models/queries/work_packages/filter/id_filter_spec.rb
index 4afbcbf374..322c051082 100644
--- a/spec/models/queries/work_packages/filter/id_filter_spec.rb
+++ b/spec/models/queries/work_packages/filter/id_filter_spec.rb
@@ -57,7 +57,7 @@ describe Queries::WorkPackages::Filter::IdFilter, type: :model do
expect(instance).to be_available
end
- it 'is fals if no work package exists/ is visible' do
+ it 'is false if no work package exists/ is visible' do
allow(WorkPackage)
.to receive_message_chain(:visible, :for_projects, :exists?)
.with(no_args)
@@ -105,8 +105,18 @@ describe Queries::WorkPackages::Filter::IdFilter, type: :model do
end
describe '#value_object' do
- it 'raises an error' do
- expect { instance.value_objects }.to raise_error NotImplementedError
+ let(:visible_wp) { FactoryGirl.build_stubbed(:work_package) }
+
+ it 'returns the work package for the values' do
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :for_projects, :find)
+ .with(no_args)
+ .with(project)
+ .with(instance.values)
+ .and_return([visible_wp])
+
+ expect(instance.value_objects)
+ .to match_array [visible_wp]
end
end
diff --git a/spec/models/queries/work_packages/filter/parent_filter_spec.rb b/spec/models/queries/work_packages/filter/parent_filter_spec.rb
new file mode 100644
index 0000000000..b3beb2c480
--- /dev/null
+++ b/spec/models/queries/work_packages/filter/parent_filter_spec.rb
@@ -0,0 +1,259 @@
+#-- encoding: UTF-8
+
+#-- 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.
+#++
+
+require 'spec_helper'
+
+describe Queries::WorkPackages::Filter::ParentFilter, type: :model do
+ let(:project) { FactoryGirl.build_stubbed(:project) }
+ let(:query) do
+ FactoryGirl.build_stubbed(:query, project: project)
+ end
+
+ it_behaves_like 'basic query filter' do
+ let(:class_key) { :parent }
+ let(:type) { :list }
+
+ before do
+ instance.context = query
+ end
+
+ describe '#available?' do
+ context 'within a project' do
+ it 'is true if any work package exists and is visible' do
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :for_projects, :exists?)
+ .with(no_args)
+ .with(project)
+ .with(no_args)
+ .and_return true
+
+ expect(instance).to be_available
+ end
+
+ it 'is false if no work package exists/ is visible' do
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :for_projects, :exists?)
+ .with(no_args)
+ .with(project)
+ .with(no_args)
+ .and_return false
+
+ expect(instance).not_to be_available
+ end
+ end
+
+ context 'outside of a project' do
+ let(:project) { nil }
+
+ it 'is true if any work package exists and is visible' do
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :exists?)
+ .with(no_args)
+ .and_return true
+
+ expect(instance).to be_available
+ end
+
+ it 'is false if no work package exists/ is visible' do
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :exists?)
+ .with(no_args)
+ .and_return false
+
+ expect(instance).not_to be_available
+ end
+ end
+ end
+
+ describe '#ar_object_filter?' do
+ it 'is true' do
+ expect(instance).to be_ar_object_filter
+ end
+ end
+
+ describe '#allowed_values' do
+ it 'raises an error' do
+ expect { instance.allowed_values }.to raise_error NotImplementedError
+ end
+ end
+
+ describe '#value_object' do
+ let(:visible_wp) { FactoryGirl.build_stubbed(:work_package) }
+
+ it 'returns the work package for the values' do
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :for_projects, :find)
+ .with(no_args)
+ .with(project)
+ .with(instance.values)
+ .and_return([visible_wp])
+
+ expect(instance.value_objects)
+ .to match_array [visible_wp]
+ end
+ end
+
+ describe '#allowed_objects' do
+ it 'raises an error' do
+ expect { instance.allowed_objects }.to raise_error NotImplementedError
+ end
+ end
+
+ describe '#valid_values!' do
+ let(:visible_wp) { FactoryGirl.build_stubbed(:work_package) }
+ let(:invisible_wp) { FactoryGirl.build_stubbed(:work_package) }
+
+ context 'within a project' do
+ it 'removes all non existing/non visible ids' do
+ instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, '999999']
+
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :for_projects, :where, :pluck)
+ .with(no_args)
+ .with(project)
+ .with(id: instance.values)
+ .with(:id)
+ .and_return([visible_wp.id])
+
+ instance.valid_values!
+
+ expect(instance.values)
+ .to match_array [visible_wp.id.to_s]
+ end
+ end
+
+ context 'outside of a project' do
+ let(:project) { nil }
+
+ it 'removes all non existing/non visible ids' do
+ instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, '999999']
+
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :where, :pluck)
+ .with(no_args)
+ .with(id: instance.values)
+ .with(:id)
+ .and_return([visible_wp.id])
+
+ instance.valid_values!
+
+ expect(instance.values)
+ .to match_array [visible_wp.id.to_s]
+ end
+ end
+ end
+
+ describe '#validate' do
+ let(:visible_wp) { FactoryGirl.build_stubbed(:work_package) }
+ let(:invisible_wp) { FactoryGirl.build_stubbed(:work_package) }
+
+ context 'within a project' do
+ it 'is valid if only visible wps are values' do
+ instance.values = [visible_wp.id.to_s]
+
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :for_projects, :where, :pluck)
+ .with(no_args)
+ .with(project)
+ .with(id: instance.values)
+ .with(:id)
+ .and_return([visible_wp.id])
+
+ expect(instance).to be_valid
+ end
+
+ it 'is invalid if invisible wps are values' do
+ instance.values = [invisible_wp.id.to_s, visible_wp.id.to_s]
+
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :for_projects, :where, :pluck)
+ .with(no_args)
+ .with(project)
+ .with(id: instance.values)
+ .with(:id)
+ .and_return([visible_wp.id])
+
+ expect(instance).not_to be_valid
+ end
+ end
+
+ context 'outside of a project' do
+ let(:project) { nil }
+
+ it 'is valid if only visible wps are values' do
+ instance.values = [visible_wp.id.to_s]
+
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :where, :pluck)
+ .with(no_args)
+ .with(id: instance.values)
+ .with(:id)
+ .and_return([visible_wp.id])
+
+ expect(instance).to be_valid
+ end
+
+ it 'is invalid if invisible wps are values' do
+ instance.values = [invisible_wp.id.to_s, visible_wp.id.to_s]
+
+ allow(WorkPackage)
+ .to receive_message_chain(:visible, :where, :pluck)
+ .with(no_args)
+ .with(id: instance.values)
+ .with(:id)
+ .and_return([visible_wp.id])
+
+ expect(instance).not_to be_valid
+ end
+ end
+ end
+
+ describe '#where and #includes' do
+ let(:parent) { FactoryGirl.create(:work_package) }
+ let(:visible_wp) { FactoryGirl.create(:work_package, parent: parent) }
+
+ before do
+ visible_wp
+ instance.values = [parent.id.to_s]
+ instance.operator = '='
+ end
+
+ it 'filters' do
+ scope = WorkPackage
+ .references(instance.includes)
+ .includes(instance.includes)
+ .where(instance.where)
+
+ expect(scope)
+ .to match_array [visible_wp]
+ end
+ end
+ end
+end
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index c3d6ee93e6..6c9ca7f5e5 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -41,7 +41,7 @@ Capybara.register_server :single_puma do |app, port, host|
workers: 0,
daemon: false,
Silent: false,
- Threads: "0:4",
+ Threads: "1:1",
config_files: ['-']
end
Capybara.server = :single_puma