Merge branch 'dev' into feature/18329-foundation-apps-framework-forms-refactor

Signed-off-by: Alex Coles <alex@alexbcoles.com>

Conflicts:
	app/assets/stylesheets/content/_work_packages.sass
pull/2612/head
Alex Coles 10 years ago
commit 7ebd7368ed
  1. 28
      Gemfile
  2. 101
      Gemfile.lock
  3. 9
      app/assets/stylesheets/content/_attributes_key_value.sass
  4. 29
      app/assets/stylesheets/content/_in_place_editing.sass
  5. 1
      app/assets/stylesheets/content/_work_packages.sass
  6. 2
      config/application.rb
  7. 19
      config/configuration.yml.example
  8. 12
      config/initializers/rack-attack.rb
  9. 29
      doc/CONFIGURATION.md
  10. 2
      doc/apiv3-documentation.apib
  11. 22
      frontend/app/services/timezone-service.js
  12. 12
      frontend/app/ui_components/inplace-editor-dispatcher.js
  13. 2
      frontend/bower.json
  14. 18
      frontend/public/templates/components/inplace_editor.html
  15. 4
      frontend/public/templates/components/inplace_editor/display/version.html
  16. 1
      lib/api/v3/root.rb
  17. 53
      lib/api/v3/string_objects/string_object_representer.rb
  18. 45
      lib/api/v3/string_objects/string_objects_api.rb
  19. 4
      lib/api/v3/utilities/path_helper.rb
  20. 3
      lib/open_project/configuration.rb
  21. 4
      lib/open_project/configuration/helpers.rb
  22. 58
      spec/lib/api/v3/string_objects/string_object_representer_spec.rb
  23. 23
      spec/lib/api/v3/utilities/path_helper_spec.rb
  24. 52
      spec/requests/api/v3/string_objects_resource_spec.rb

@ -30,10 +30,10 @@ source 'https://rubygems.org'
gem "rails", "~> 3.2.21"
gem "coderay", "~> 1.0.5"
gem "coderay", "~> 1.0.9"
gem "rubytree", "~> 0.8.3"
gem "rdoc", ">= 2.4.2"
gem 'globalize'
gem 'globalize', "~> 3.1.0"
gem 'omniauth'
gem 'request_store'
gem 'gravatar_image_tag', '~> 1.2.0'
@ -56,7 +56,7 @@ gem 'htmldiff'
# used for statistics on svn repositories
gem 'svg-graph'
gem "date_validator"
gem "date_validator", '~> 0.7.1'
gem 'ruby-duration', '~> 3.2.0'
# We rely on this specific version, which is the latest as of now (end of 2013),
@ -65,7 +65,7 @@ gem 'ruby-duration', '~> 3.2.0'
# See: config/initializers/rabl_hack.rb
gem 'rabl', '0.9.3'
gem 'multi_json'
gem 'oj'
gem 'oj', '~> 2.11.4'
# will need to be removed once we are on rails4 as it will be part of the rails4 core
gem 'strong_parameters'
@ -80,6 +80,11 @@ gem 'daemons'
# (see https://community.openproject.org/work_packages/3029)
gem 'rack-protection', :git => "https://github.com/finnlabs/rack-protection.git", :ref => '5a7d1bd'
# Rack::Attack is a rack middleware to protect your web app from bad clients.
# It allows whitelisting, blacklisting, throttling, and tracking based on arbitrary properties of the request.
# https://github.com/kickstarter/rack-attack
gem 'rack-attack'
gem 'syck', :platforms => [:ruby_20, :mingw_20, :ruby_21, :mingw_21], :require => false
gem 'gon', '~> 4.0'
@ -88,7 +93,7 @@ group :production do
# we use dalli as standard memcache client
# requires memcached 1.4+
# see https://github.com/mperham/dalli
gem 'dalli'
gem 'dalli', '~> 2.7.2'
end
gem 'sprockets', git: 'https://github.com/tessi/sprockets.git', branch: '2_2_2_backport2'
@ -117,11 +122,10 @@ gem 'unicorn'
# Gems we don't depend directly on, but specify here to make sure we don't use a vulnerable
# version. Please add a link to a security advisory when adding a Gem here.
gem 'i18n', '>=0.6.8'
gem 'i18n', '~> 0.6.8'
# see https://groups.google.com/forum/#!topic/ruby-security-ann/pLrh6DUw998
gem 'nokogiri', '>=1.5.11'
# see https://groups.google.com/forum/#!topic/ruby-security-ann/DeJpjTAg1FA
gem 'nokogiri', '~> 1.6.6'
gem 'carrierwave', '~> 0.10.0'
gem 'fog', '~> 1.23.0', require: "fog/aws/storage"
@ -132,7 +136,7 @@ group :test do
gem 'object-daddy', '~> 1.1.0'
gem "launchy", "~> 2.3.0"
gem "factory_girl_rails", "~> 4.0"
gem 'cucumber-rails', :require => false
gem 'cucumber-rails', "~> 1.4.2", :require => false
gem 'rack_session_access'
# restrict because in version 1.3 a lot of tests using acts as journalized
# fail stating: "Column 'user_id' cannot be null". I don't understand the
@ -145,7 +149,7 @@ group :test do
gem 'rspec-activemodel-mocks'
gem 'rspec-example_disabler', git: "https://github.com/finnlabs/rspec-example_disabler.git"
gem 'capybara', '~> 2.3.0'
gem 'capybara-screenshot'
gem 'capybara-screenshot', '~> 1.0.4'
gem 'selenium-webdriver', '~> 2.44.0'
gem 'timecop', '~> 0.7.1'
@ -153,11 +157,10 @@ group :test do
# why in Gemfile? see: https://github.com/guard/guard-test
gem 'ruby-prof'
gem 'simplecov', '0.8.0.pre'
gem "shoulda-matchers"
gem "shoulda-matchers", '~> 2.5.0'
gem "json_spec"
gem "activerecord-tableless", "~> 1.0"
gem "codeclimate-test-reporter", :require => nil
gem 'test-unit', '2.5.5'
end
group :ldap do
@ -170,6 +173,7 @@ group :development do
gem 'thin'
gem 'faker'
gem 'quiet_assets'
gem 'rubocop', '~> 0.28'
end
group :development, :test do

@ -85,6 +85,9 @@ GEM
activerecord (>= 3.0)
addressable (2.3.4)
arel (3.0.3)
ast (2.0.0)
astrolabe (1.3.0)
parser (>= 2.2.0.pre.3, < 3.0)
autoprefixer-rails (5.1.5)
execjs
json
@ -99,8 +102,6 @@ GEM
bourbon (4.1.1)
sass (~> 3.3)
thor
bourne (1.4.0)
mocha (~> 0.13.2)
builder (3.0.4)
byebug (2.7.0)
columnize (~> 0.3)
@ -111,8 +112,10 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
capybara-screenshot (0.3.6)
capybara-screenshot (1.0.5)
capybara (>= 1.0, < 3)
colored
launchy
carrierwave (0.10.0)
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
@ -130,23 +133,25 @@ GEM
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
color-tools (1.3.0)
colored (1.2)
columnize (0.8.9)
cucumber (1.3.8)
cucumber (1.3.18)
builder (>= 2.1.2)
diff-lcs (>= 1.1.3)
gherkin (~> 2.12.1)
gherkin (~> 2.12)
multi_json (>= 1.7.5, < 2.0)
multi_test (>= 0.0.2)
cucumber-rails (1.3.1)
capybara (>= 1.1.2)
cucumber (>= 1.2.0)
nokogiri (>= 1.5.0)
rails (~> 3.0)
multi_test (>= 0.1.1)
cucumber-rails (1.4.2)
capybara (>= 1.1.2, < 3)
cucumber (>= 1.3.8, < 2)
mime-types (>= 1.16, < 3)
nokogiri (~> 1.5)
rails (>= 3, < 5)
daemons (1.1.9)
dalli (2.6.4)
dalli (2.7.2)
database_cleaner (1.2.0)
date_validator (0.7.0)
activemodel (>= 3)
date_validator (0.7.1)
activemodel
debug_inspector (0.0.2)
debugger-linecache (1.2.0)
delayed_job (3.0.5)
@ -200,10 +205,9 @@ GEM
formatador (0.2.5)
gherkin (2.12.2)
multi_json (~> 1.3)
globalize (3.0.0)
activemodel (>= 3.0.0)
activerecord (>= 3.0.0)
paper_trail (~> 2)
globalize (3.1.0)
activemodel (>= 3.1.0, < 4.0.0)
activerecord (>= 3.1.0, < 4.0.0)
gon (4.0.0)
actionpack (>= 2.3.0)
json
@ -229,7 +233,7 @@ GEM
ipaddress (0.8.0)
iso8601 (0.8.2)
journey (1.0.4)
json (1.8.1)
json (1.8.2)
json_spec (1.1.1)
multi_json (~> 1.0)
rspec (~> 2.0)
@ -248,34 +252,31 @@ GEM
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
metaclass (0.0.1)
method_source (0.8.2)
mime-types (1.25.1)
mini_portile (0.6.2)
minisyntax (0.2.3)
mocha (0.13.3)
metaclass (~> 0.0.1)
multi_json (1.10.1)
multi_test (0.0.2)
multi_test (0.1.1)
multi_xml (0.5.5)
mysql2 (0.3.17)
net-ldap (0.8.0)
net-scp (1.2.1)
net-ssh (>= 2.6.5)
net-ssh (2.9.1)
nokogiri (1.6.5)
net-ssh (2.9.2)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
non-stupid-digest-assets (1.0.4)
object-daddy (1.1.1)
oj (2.1.6)
oj (2.11.4)
omniauth (1.2.1)
hashie (>= 1.2, < 3)
rack (~> 1.0)
paper_trail (2.7.2)
activerecord (~> 3.0)
railties (~> 3.0)
parser (2.2.0.2)
ast (>= 1.1, < 3.0)
pg (0.17.1)
polyglot (0.3.5)
powerpack (0.0.9)
prototype-rails (3.2.1)
rails (~> 3.2)
pry (0.9.12.6)
@ -303,6 +304,8 @@ GEM
rack (1.4.5)
rack-accept (0.4.5)
rack (>= 0.4)
rack-attack (4.2.0)
rack
rack-cache (1.2)
rack (>= 0.4)
rack-mount (0.8.3)
@ -334,8 +337,9 @@ GEM
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
rainbow (2.0.0)
raindrops (0.13.0)
rake (10.3.2)
rake (10.4.2)
rb-readline (0.5.1)
rdoc (3.12.2)
json (~> 1.4)
@ -375,6 +379,12 @@ GEM
rspec-core (~> 2.99.0)
rspec-expectations (~> 2.99.0)
rspec-mocks (~> 2.99.0)
rubocop (0.28.0)
astrolabe (~> 1.3)
parser (>= 2.2.0.pre.7, < 3.0)
powerpack (~> 0.0.6)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4)
ruby-duration (3.2.0)
activesupport (>= 3.0.0)
i18n
@ -394,10 +404,9 @@ GEM
shoulda (3.5.0)
shoulda-context (~> 1.0, >= 1.0.1)
shoulda-matchers (>= 1.4.1, < 3.0)
shoulda-context (1.1.2)
shoulda-matchers (2.1.0)
shoulda-context (1.2.1)
shoulda-matchers (2.5.0)
activesupport (>= 3.0.0)
bourne (~> 1.3)
simplecov (0.8.0.pre)
multi_json
simplecov-html (~> 0.7.1)
@ -410,7 +419,6 @@ GEM
structured_warnings (0.1.4)
svg-graph (1.0.5)
syck (1.0.1)
test-unit (2.5.5)
thin (1.5.1)
daemons (>= 1.0.9)
eventmachine (>= 0.12.6)
@ -422,7 +430,7 @@ GEM
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.42)
tzinfo (0.3.43)
uber (0.0.12)
uglifier (2.1.1)
execjs (>= 0.3.0)
@ -454,27 +462,27 @@ DEPENDENCIES
awesome_nested_set
bourbon (~> 4.1.1)
capybara (~> 2.3.0)
capybara-screenshot
capybara-screenshot (~> 1.0.4)
carrierwave (~> 0.10.0)
cocaine
codeclimate-test-reporter
coderay (~> 1.0.5)
coderay (~> 1.0.9)
color-tools (~> 1.3.0)
cucumber-rails
cucumber-rails (~> 1.4.2)
daemons
dalli
dalli (~> 2.7.2)
database_cleaner (~> 1.2.0)
date_validator
date_validator (~> 0.7.1)
delayed_job_active_record (= 0.3.3)
factory_girl_rails (~> 4.0)
faker
fog (~> 1.23.0)
globalize
globalize (~> 3.1.0)
gon (~> 4.0)
grape (~> 0.10.1)
gravatar_image_tag (~> 1.2.0)
htmldiff
i18n (>= 0.6.8)
i18n (~> 0.6.8)
jruby-openssl
json_spec
launchy (~> 2.3.0)
@ -483,10 +491,10 @@ DEPENDENCIES
multi_json
mysql2 (~> 0.3.11)
net-ldap (~> 0.8.0)
nokogiri (>= 1.5.11)
nokogiri (~> 1.6.6)
non-stupid-digest-assets
object-daddy (~> 1.1.0)
oj
oj (~> 2.11.4)
omniauth
pg (~> 0.17.1)
prototype-rails
@ -498,6 +506,7 @@ DEPENDENCIES
pry-stack_explorer
quiet_assets
rabl (= 0.9.3)
rack-attack
rack-protection!
rack-test (~> 0.6.2)
rack_session_access
@ -513,6 +522,7 @@ DEPENDENCIES
rspec-activemodel-mocks
rspec-example_disabler!
rspec-rails (~> 2.99.0)
rubocop (~> 0.28)
ruby-duration (~> 3.2.0)
ruby-prof
ruby-progressbar
@ -521,14 +531,13 @@ DEPENDENCIES
sass-rails!
selenium-webdriver (~> 2.44.0)
shoulda
shoulda-matchers
shoulda-matchers (~> 2.5.0)
simplecov (= 0.8.0.pre)
sprockets!
sprockets-rails!
strong_parameters
svg-graph
syck
test-unit (= 2.5.5)
thin
timecop (~> 0.7.1)
uglifier (>= 1.0.3)

@ -28,6 +28,8 @@
.attributes-key-value
@include grid-block($wrap: true)
overflow: visible
overflow-y: visible
.attributes-key-value--key
@include grid-content(4)
@ -37,14 +39,15 @@
font-weight: bold
line-height: $list-line-height / 0.9
text-overflow: ellipsis
overflow: hidden
white-space: nowrap
.attributes-key-value--value-container
@include grid-content(8)
overflow: visible
overflow-y: visible
margin-bottom: 0.4rem
padding: 0
.attributes-key-value--value
&.-user
overflow: hidden
overflow: visible
overflow-y: visible

@ -1,4 +1,8 @@
.select2-container
position: relative!important
.inplace-editor
ul
margin-left: auto
display: inline
font-size: medium
.ined-input-wrapper-inner
@ -44,6 +48,7 @@
margin-bottom: -1px
.ined-read-value
display: inline
position: relative
&.default
span
font-style: italic
@ -60,10 +65,8 @@
.ined-dashboard
min-height: 42px
.ined-errors
float: right
display: inline-block
line-height: 1.2em
width: 251px
width: 100%
padding: 5px
left: 251px
bottom: -11px
@ -102,19 +105,16 @@
display: block
.read-value-wrapper
display: inline-block
width: 400px
width: 100%
.editing-link-wrapper
position: relative
display: inline-block
float: right
top: 5px
right: 0px
.ined-dashboard
padding-left: 0px
width: 100%
.ined-controls
left: 0px
z-index: 1
.ined-errors
width: 307px
.jstHandle
display: none
.jstElements
@ -140,22 +140,13 @@
.jstb_strong, .jstb_em, .jstb_ins, .jstb_del, .jstb_ul, .jstb_ol
display: inline
&.type-select2
display: inline-block
width: 344px
.select2-display-none
display: none
.ui-select-choices
max-height: 100px
input[type='text']
width: 100%
.ined-dashboard
padding-left: 0px
width: 345px
.ined-errors
width: 225px
.ined-controls
.ined-edit
height: 175px
.ined-read-value
position: relative
display: block
@ -164,7 +155,7 @@
outline: 1px solid #cacaca
.editing-link-wrapper
position: absolute
right: -13px
right: -3px
top: 1px
width: 30px
.icon-context:before

@ -56,6 +56,7 @@
margin: 0
padding: 0 0 10px 0
display: block
clear: both
.select-type
padding-top: 3px

@ -82,6 +82,8 @@ module OpenProject
env['PATH_INFO'] =~ /\/api\/v3/
}
config.middleware.use Rack::Attack
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
config.autoload_paths << Rails.root.join('lib')

@ -132,6 +132,25 @@
# - plugins
# - info
#
# Also there is a posibility to specify which routes are forbidden,
# they should be listed as an array in yml format more information
# regarding yml format you can find here:
# http://symfony.com/doc/current/components/yaml/yaml_format.html
# You can also use wildcards (*) in your url
#
# production:
# blacklisted_routes:
# - 'admin/info'
# - 'admin/plugins'
# - 'export_card_configurations'
# - 'project_types'
# - 'colors'
# - 'settings'
# - 'admin/enumerations'
# - 'workflows/*'
# - 'statuses'
# - 'types'
# - 'admin/roles'
# default configuration options for all environments

@ -0,0 +1,12 @@
if OpenProject::Configuration.blacklisted_routes.any?
# Block logins from a bad user agent
Rack::Attack.blacklist('block forbidden routes') do |req|
regex = OpenProject::Configuration.blacklisted_routes.map! { |str| Regexp.new(str) }
regex.any? { |i| i =~ req.path }
end
Rack::Attack.blacklisted_response = lambda do |_env|
# All blacklisted routes would return a 404.
[404, {}, ['Not found']]
end
end

@ -85,6 +85,7 @@ storage config above like this:
* [`attachments_storage`](#attachments-storage) (default: file)
* [`hidden_menu_items`](#hidden-menu-items) (default: {})
* [`disabled_modules`](#disabled-modules) (default: [])
* [`blacklisted_routes`](#blacklisted-routes) (default: [])
### disable password login
@ -181,6 +182,34 @@ For instance 'Roles' and 'Types' under 'Administration' can be disabled by defin
OPENPROJECT_HIDDEN__MENU__ITEMS_ADMIN__MENU='roles types'
```
### blacklisted routes
*default: []*
You can blacklist specific routes
The following example forbid all routes for above disabled menu:
```
blacklisted_routes:
- 'admin/info'
- 'admin/plugins'
- 'export_card_configurations'
- 'project_types'
- 'colors'
- 'settings'
- 'admin/enumerations'
- 'workflows/*'
- 'statuses'
- 'types'
- 'admin/roles'
```
The configuration can be overridden through environment variables.
```
OPENPROJECT_BLACKLISTED__ROUTES='admin/info admin/plugins'
```
### disabled modules
*default: []*

@ -1859,7 +1859,7 @@ This is an example of how a schema might look like. Note that this endpoint does
## Linked Properties:
| Link | Description | Type | Constraints | Supported operations |
|:-------------:|-------------------------- | ------------- | ----------- | -------------------- |
| self | This type | Type | not null | READ |
| self | This string object | StringObject | not null | READ |
## Properties
| Property | Description | Type | Constraints | Supported operations |

@ -45,28 +45,14 @@ module.exports = function(ConfigurationService, I18n) {
},
formattedDate: function(date) {
var date;
if (ConfigurationService.dateFormatPresent()) {
date = TimezoneService.parseDate(date).format(ConfigurationService.dateFormat());
} else {
date = TimezoneService.parseDate(date).format('L');
}
return date;
var format = ConfigurationService.dateFormatPresent() ? ConfigurationService.dateFormat() : 'L';
return TimezoneService.parseDate(date).format(format);
},
formattedTime: function(date) {
var time;
if (ConfigurationService.timeFormatPresent()) {
time = TimezoneService.parseDate(date).format(ConfigurationService.timeFormat());
} else {
time = TimezoneService.parseDate(date).format('LT');
var format = ConfigurationService.timeFormatPresent() ? ConfigurationService.timeFormat() : 'LT';
return TimezoneService.parseDate(date).format(format);
}
return time;
},
};
return TimezoneService;

@ -103,8 +103,6 @@ module.exports = function($sce, $http, $timeout, AutoCompleteHelper, TextileServ
$scope.options = options;
}
$scope.$broadcast('focusSelect2');
} else {
$scope.isEditable = false;
}
}
@ -149,10 +147,14 @@ module.exports = function($sce, $http, $timeout, AutoCompleteHelper, TextileServ
enableAutoCompletion(element);
scope.$on('startEditing', function() {
$timeout(function() {
element.find('.ined-dashboard').css({
'margin-left': element
var typeWidth = element
.closest('.work-packages--details-content')
.find('.select-type:first').width()
.find('.select-type:first').width();
element.find('.ined-dashboard').css({
'margin-left': typeWidth
});
element.find('input[type=text]').css({
'width': element.find('.ined-dashboard').width()
});
}, 0, false);
});

@ -13,7 +13,7 @@
"angular-ui-select2": "0.0.5",
"angular-ui-select2-sortable": "0.0.1",
"angular-ui-date": "0.0.3",
"angular-ui-router": "0.2.11",
"angular-ui-router": "0.2.13",
"angular-i18n": "~1.3.0",
"angular-modal": "finnlabs/angular-modal#d45eb9ceb720b8785613ba89ba0f14f8ab197569",
"angular-sanitize": "~1.3.11",

@ -1,22 +1,6 @@
<div class="inplace-editor type-{{type}} attribute-{{attribute}}" ng-class="{busy: isBusy, preview: isPreview, editable: isEditable}" aria-busy="{{ isBusy }}" ng-disabled="!isEditable">
<div class="ined-read-value" ng-class="{ default: placeholderSet, editable: isEditable }" ng-hide="isEditing" ng-switch="type">
<span class="read-value-wrapper" ng-switch-when="wiki_textarea" ng-bind-html="readValue"></span>
<span class="read-value-wrapper" ng-switch-default>
<span ng-if="!isUserLink">
<span ng-if="attribute == 'version.name'">
<span ng-if="entity.links.version">
<a href="{{pathHelper.versionPath(entity.embedded.version.props.id)}}">
{{entity.links.version.props.title}}
</a>
</span>
<span ng-if="!entity.links.version">
{{readValue}}
</span>
</span>
<span ng-if="attribute != 'version.name'" ng-bind="readValue"></span>
</span>
<user-field ng-if="isUserLink" user="readValue"></user-field>
</span>
<span class="read-value-wrapper" ng-include src="getDisplayTemplateUrl()"></span>
<span ng-if="isEditable" class="editing-link-wrapper">
<accessible-by-keyboard execute="startEditing()">
<icon-wrapper icon-name="edit" icon-title="{{ editTitle }}">

@ -1,8 +1,8 @@
<span ng-if="entity.links.version">
<span ng-if="entity.links.version.href">
<a href="{{pathHelper.versionPath(entity.embedded.version.props.id)}}">
{{entity.links.version.props.title}}
</a>
</span>
<span ng-if="!entity.links.version">
<span ng-if="!entity.links.version.href">
{{readValue}}
</span>

@ -44,6 +44,7 @@ module API
mount ::API::V3::Queries::QueriesAPI
mount ::API::V3::Render::RenderAPI
mount ::API::V3::Statuses::StatusesAPI
mount ::API::V3::StringObjects::StringObjectsAPI
mount ::API::V3::Users::UsersAPI
mount ::API::V3::Versions::VersionsAPI
mount ::API::V3::WorkPackages::WorkPackagesAPI

@ -0,0 +1,53 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2015 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-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 doc/COPYRIGHT.rdoc for more details.
#++
require 'roar/decorator'
require 'roar/json/hal'
module API
module V3
module StringObjects
class StringObjectRepresenter < ::API::Decorators::Single
link :self do
{
href: api_v3_paths.string_object(represented)
}
end
property :value,
exec_context: :decorator,
getter: -> (*) { represented }
def _type
'StringObject'
end
end
end
end
end

@ -0,0 +1,45 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2015 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-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 doc/COPYRIGHT.rdoc for more details.
#++
module API
module V3
module StringObjects
class StringObjectsAPI < Grape::API
resources :string_objects do
namespace ':value' do
get do
StringObjectRepresenter.new(params[:value])
end
end
end
end
end
end
end

@ -102,6 +102,10 @@ module API
"#{statuses}/#{id}"
end
def self.string_object(value)
"#{root}/string_objects/#{::ERB::Util::url_encode(value)}"
end
def self.users
"#{root}/users"
end

@ -77,7 +77,8 @@ module OpenProject
'disable_password_choice' => false,
'disabled_modules' => [], # allow to disable default modules
'hidden_menu_items' => {}
'hidden_menu_items' => {},
'blacklisted_routes' => []
}
@config = nil

@ -82,6 +82,10 @@ module OpenProject
array self['disabled_modules']
end
def blacklisted_routes
array self['blacklisted_routes']
end
def available_file_uploaders
{
fog: ::FogFileUploader,

@ -0,0 +1,58 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2015 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-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 doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe ::API::V3::StringObjects::StringObjectRepresenter do
let(:value) { 'foo bar' }
let(:representer) { described_class.new(value) }
include API::V3::Utilities::PathHelper
context 'generation' do
subject { representer.to_json }
it 'should indicate its type' do
is_expected.to be_json_eql('StringObject'.to_json).at_path('_type')
end
describe 'links' do
it 'should link to self' do
path = api_v3_paths.string_object(value)
is_expected.to be_json_eql(path.to_json).at_path('_links/self/href')
end
end
describe 'value' do
it 'should have a value' do
is_expected.to be_json_eql(value.to_json).at_path('value')
end
end
end
end

@ -187,6 +187,29 @@ describe ::API::V3::Utilities::PathHelper do
end
end
describe 'string object paths' do
describe '#string_object' do
subject { helper.string_object 'foo' }
it_behaves_like 'api v3 path'
it { is_expected.to match(/^\/api\/v3\/string_objects\/foo/) }
it 'escapes correctly' do
value = 'foo/bar baz'
expect(helper.string_object value).to eql('/api/v3/string_objects/foo%2Fbar%20baz')
end
end
describe '#status' do
subject { helper.status 1 }
it_behaves_like 'api v3 path'
it { is_expected.to match(/^\/api\/v3\/statuses\/1/) }
end
end
describe '#user' do
subject { helper.user 1 }

@ -0,0 +1,52 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2015 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-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 doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
require 'rack/test'
describe 'API v3 String Objects resource' do
include Rack::Test::Methods
describe 'string_objects' do
subject(:response) { last_response }
let(:path) { '/api/v3/string_objects/foo%20bar' }
before do
get path
end
it 'is successful' do
expect(subject.status).to eql(200)
end
it 'returns the value' do
expect(subject.body).to be_json_eql('foo bar'.to_json).at_path('value')
end
end
end
Loading…
Cancel
Save