openstax_api 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +73 -0
- data/Rakefile +22 -0
- data/app/controllers/openstax/api/v1/api_controller.rb +75 -0
- data/app/controllers/openstax/api/v1/oauth_based_api_controller.rb +17 -0
- data/app/models/openstax/api/api_user.rb +82 -0
- data/app/representers/openstax/api/v1/representable_schema_printer.rb +85 -0
- data/lib/openstax_api/constraints.rb +21 -0
- data/lib/openstax_api/doorkeeper_extensions.rb +22 -0
- data/lib/openstax_api/engine.rb +20 -0
- data/lib/openstax_api/route_extensions.rb +17 -0
- data/lib/openstax_api/version.rb +5 -0
- data/lib/openstax_api.rb +8 -0
- data/spec/app/controllers/openstax/api/v1/api_controller_spec.rb +11 -0
- data/spec/app/controllers/openstax/api/v1/oauth_based_api_controller_spec.rb +11 -0
- data/spec/app/models/openstax/api/api_user_spec.rb +47 -0
- data/spec/app/representers/openstax/api/v1/representable_schema_printer_spec.rb +19 -0
- data/spec/dummy/README.md +1 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/app/representers/user_representer.rb +8 -0
- data/spec/dummy/config/application.rb +53 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +69 -0
- data/spec/dummy/config/environments/test.rb +35 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/doorkeeper.rb +75 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +2 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/0_create_doorkeeper_tables.rb +42 -0
- data/spec/dummy/db/migrate/1_create_users.rb +10 -0
- data/spec/dummy/db/schema.rb +62 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +541 -0
- data/spec/dummy/log/test.log +3183 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/lib/openstax_api/constraints_spec.rb +74 -0
- data/spec/lib/openstax_api/doorkeeper_extensions_spec.rb +17 -0
- data/spec/lib/openstax_api/route_extensions_spec.rb +21 -0
- data/spec/spec_helper.rb +18 -0
- metadata +248 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e65fff56b84dbf775bc833cac2d8c0d47ac17071
|
4
|
+
data.tar.gz: 50a0a75083a94728f96ae03850976d69591cfa3c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1ee105cdac7c958f73f350386dffad9440b7de73a860f607a5c7df4ef06aec8cfb113a974db0c5e894cc09a2e687f3c66dac4881e25c684b008dc1bd679bee67
|
7
|
+
data.tar.gz: d4e10fbe22973ad8d80143ccbf7e6013064ca6ec9f6792d2612043994fa1521f028c61e38e54db80269d7df9f730efaa4c019979678a4e904539ecd0b1ddab9b
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2014 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# openstax_api
|
2
|
+
|
3
|
+
API utilities for OpenStax products and tools.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```rb
|
10
|
+
gem 'openstax_api'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```sh
|
16
|
+
$ bundle
|
17
|
+
```
|
18
|
+
|
19
|
+
## Included classes
|
20
|
+
|
21
|
+
This gem includes the following classes, all under the OpenStax::Api namespace:
|
22
|
+
|
23
|
+
### Controllers
|
24
|
+
|
25
|
+
`ApiController`
|
26
|
+
|
27
|
+
`OauthBasedApiController`
|
28
|
+
|
29
|
+
Your API controllers should inherit from those classes.
|
30
|
+
|
31
|
+
### Models
|
32
|
+
|
33
|
+
`ApiUser`
|
34
|
+
|
35
|
+
This is the class of someone using the API, which can either be a (signed in) user, a doorkeeper application, or a combination of both.
|
36
|
+
|
37
|
+
## Doorkeeper Extensions
|
38
|
+
|
39
|
+
This gem also adds the following methods to Doorkeeper::Application:
|
40
|
+
|
41
|
+
`is_human?`, `is_application?` and `is_admin?`
|
42
|
+
|
43
|
+
## Route simplification
|
44
|
+
|
45
|
+
Finally, this gem allows API routes to be simplified by using the api method, like so:
|
46
|
+
|
47
|
+
```rb
|
48
|
+
apipie
|
49
|
+
|
50
|
+
get 'api', to: 'static_pages#api'
|
51
|
+
|
52
|
+
api :v1, true do
|
53
|
+
get '/your_api_routes_go_here'
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
The api route method takes a version argument and a boolean.
|
58
|
+
If the boolean is true, that version is the default (latest) and will always match the Accept header. It should be defined last, as any API route after that will be ignored.
|
59
|
+
|
60
|
+
## Testing
|
61
|
+
|
62
|
+
From the gem's main folder, run `bundle`, and then `rake` to run all the specs.
|
63
|
+
|
64
|
+
## Contributing
|
65
|
+
|
66
|
+
1. Fork it
|
67
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
68
|
+
3. Create specs for your feature
|
69
|
+
4. Ensure that all specs pass
|
70
|
+
5. Commit your changes (`git commit -am 'Add some feature'`)
|
71
|
+
6. Push to the branch (`git push origin my-new-feature`)
|
72
|
+
7. Create new pull request
|
73
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# http://viget.com/extend/rails-engine-testing-with-rspec-capybara-and-factorygirl
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
|
10
|
+
load 'rails/tasks/engine.rake'
|
11
|
+
|
12
|
+
Bundler::GemHelper.install_tasks
|
13
|
+
|
14
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
|
15
|
+
|
16
|
+
require 'rspec/core'
|
17
|
+
require 'rspec/core/rake_task'
|
18
|
+
|
19
|
+
desc 'Run all specs in spec directory (excluding plugin specs)'
|
20
|
+
RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
|
21
|
+
|
22
|
+
task :default => :spec
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'roar-rails'
|
2
|
+
|
3
|
+
module OpenStax
|
4
|
+
module Api
|
5
|
+
module V1
|
6
|
+
|
7
|
+
class ApiController < ::ApplicationController
|
8
|
+
|
9
|
+
include Roar::Rails::ControllerAdditions
|
10
|
+
|
11
|
+
fine_print_skip_signatures(:general_terms_of_use,
|
12
|
+
:privacy_policy) \
|
13
|
+
if respond_to? :fine_print_skip_signatures
|
14
|
+
|
15
|
+
skip_protect_beta if respond_to? :skip_protect_beta
|
16
|
+
|
17
|
+
skip_before_filter :authenticate_user!
|
18
|
+
|
19
|
+
respond_to :json
|
20
|
+
rescue_from Exception, :with => :rescue_from_exception
|
21
|
+
|
22
|
+
def self.api_example(options={})
|
23
|
+
return if Rails.env.test?
|
24
|
+
raise IllegalArgument, "must supply a :url parameter" if !options[:url_base]
|
25
|
+
|
26
|
+
url_base = options[:url_base].is_a?(Symbol) ?
|
27
|
+
UrlGenerator.new.send(options[:url_base], protocol: 'https') :
|
28
|
+
options[:url_base].to_s
|
29
|
+
|
30
|
+
"#{url_base}/#{options[:url_end] || ''}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.json_schema(representer, options={})
|
34
|
+
RepresentableSchemaPrinter.json(representer, options)
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def rescue_from_exception(exception)
|
40
|
+
# See https://github.com/rack/rack/blob/master/lib/rack/utils.rb#L453 for error names/symbols
|
41
|
+
error = :internal_server_error
|
42
|
+
notify = true
|
43
|
+
|
44
|
+
case exception
|
45
|
+
when SecurityTransgression
|
46
|
+
error = :forbidden
|
47
|
+
notify = false
|
48
|
+
when ActiveRecord::RecordNotFound,
|
49
|
+
ActionController::RoutingError,
|
50
|
+
ActionController::UnknownController,
|
51
|
+
AbstractController::ActionNotFound
|
52
|
+
error = :not_found
|
53
|
+
notify = false
|
54
|
+
end
|
55
|
+
|
56
|
+
if notify
|
57
|
+
# Not yet in OSU
|
58
|
+
=begin
|
59
|
+
ExceptionNotifier.notify_exception(
|
60
|
+
exception,
|
61
|
+
env: request.env,
|
62
|
+
data: { message: "An exception occurred" }
|
63
|
+
)
|
64
|
+
=end
|
65
|
+
Rails.logger.error("An exception occurred: #{exception.message}\n\n#{exception.backtrace.join("\n")}") \
|
66
|
+
end
|
67
|
+
|
68
|
+
head error
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# A "user" (lowercase 'u') of an API can take one of several forms.
|
2
|
+
#
|
3
|
+
# 1. It can just be a User (capital 'U') based on session data (e.g.
|
4
|
+
# someone who logs into this site and then uses this site's Backbone
|
5
|
+
# interface).
|
6
|
+
# 2. It can be a combination of a Doorkeeper Application and a User,
|
7
|
+
# given via OAuth's Authorization or Implicit flows.
|
8
|
+
# 3. It can just be a Doorkeeper Application, given through OAuth's
|
9
|
+
# Client Credentials flow.
|
10
|
+
#
|
11
|
+
# This API class gives us a way to abstract out these cases and also
|
12
|
+
# gives us accessors to get the Application and User objects, if available.
|
13
|
+
|
14
|
+
module OpenStax
|
15
|
+
module Api
|
16
|
+
class ApiUser
|
17
|
+
|
18
|
+
def initialize(doorkeeper_token, non_doorkeeper_user_proc)
|
19
|
+
# If we have a doorkeeper_token, derive the Application and User
|
20
|
+
# from it. If not, we're in case #1 above and the User should be
|
21
|
+
# retrieved from the alternative proc provided in arguments and
|
22
|
+
# there is no application.
|
23
|
+
#
|
24
|
+
# In both cases, don't actually retrieve any data -- just save off
|
25
|
+
# procs that can get it for us. This could save us some queries.
|
26
|
+
|
27
|
+
if doorkeeper_token
|
28
|
+
@application_proc = lambda { doorkeeper_token.application }
|
29
|
+
@user_proc = lambda {
|
30
|
+
doorkeeper_token.resource_owner_id ?
|
31
|
+
User.find(doorkeeper_token.resource_owner_id) :
|
32
|
+
nil
|
33
|
+
}
|
34
|
+
else
|
35
|
+
@user_proc = non_doorkeeper_user_proc
|
36
|
+
@application_proc = lambda { nil }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a Doorkeeper::Application or nil
|
41
|
+
# TODO should we have a NoApplication like NoUser (or maybe should
|
42
|
+
# NoUser just be replaced with nil)
|
43
|
+
def application
|
44
|
+
@application ||= @application_proc.call
|
45
|
+
end
|
46
|
+
|
47
|
+
# Can return an instance of User, AnonymousUser, or nil
|
48
|
+
def human_user
|
49
|
+
@user ||= @user_proc.call
|
50
|
+
end
|
51
|
+
|
52
|
+
##########################
|
53
|
+
# Access Control Helpers #
|
54
|
+
##########################
|
55
|
+
|
56
|
+
def can_do?(action, resource)
|
57
|
+
OSU::AccessPolicy.action_allowed?(action, self, resource)
|
58
|
+
end
|
59
|
+
|
60
|
+
def can_read?(resource)
|
61
|
+
can_do?(:read, resource)
|
62
|
+
end
|
63
|
+
|
64
|
+
def can_create?(resource)
|
65
|
+
can_do?(:create, resource)
|
66
|
+
end
|
67
|
+
|
68
|
+
def can_update?(resource)
|
69
|
+
can_do?(:update, resource)
|
70
|
+
end
|
71
|
+
|
72
|
+
def can_destroy?(resource)
|
73
|
+
can_do?(:destroy, resource)
|
74
|
+
end
|
75
|
+
|
76
|
+
def can_sort?(resource)
|
77
|
+
can_do?(:sort, resource)
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Api
|
3
|
+
module V1
|
4
|
+
class RepresentableSchemaPrinter
|
5
|
+
|
6
|
+
def self.json(representer, options={})
|
7
|
+
options[:include] ||= [:readable, :writeable]
|
8
|
+
options[:indent] ||= ' '
|
9
|
+
|
10
|
+
definitions = {}
|
11
|
+
|
12
|
+
schema = json_schema(representer, definitions, options)
|
13
|
+
schema[:definitions] = definitions
|
14
|
+
|
15
|
+
json_string = JSON.pretty_generate(schema, {indent: options[:indent]})
|
16
|
+
|
17
|
+
"\nSchema {##{SecureRandom.hex(4)} .schema}\n------\n" +
|
18
|
+
"<pre class='code'>\n#{json_string}\n</pre>\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def self.json_schema(representer, definitions, options={})
|
24
|
+
schema = {
|
25
|
+
# id: schema_id(representer),
|
26
|
+
# title: schema_title(representer),
|
27
|
+
type: "object",
|
28
|
+
properties: {},
|
29
|
+
required: []
|
30
|
+
# :$schema => "http://json-schema.org/draft-04/schema#"
|
31
|
+
}
|
32
|
+
|
33
|
+
representer.representable_attrs.each do |attr|
|
34
|
+
schema_info = attr.options[:schema_info] || {}
|
35
|
+
|
36
|
+
schema[:required].push(attr.name) if schema_info[:required]
|
37
|
+
|
38
|
+
next unless [options[:include]].flatten.any?{|inc| attr.send(inc.to_s+"?") || schema_info[:required]}
|
39
|
+
|
40
|
+
attr_info = {}
|
41
|
+
|
42
|
+
if attr.options[:collection]
|
43
|
+
attr_info[:type] = "array"
|
44
|
+
else
|
45
|
+
attr_info[:type] = attr.options[:type].to_s.downcase if attr.options[:type]
|
46
|
+
end
|
47
|
+
|
48
|
+
schema_info.each do |key, value|
|
49
|
+
next if [:required].include?(key)
|
50
|
+
value = value.to_s.downcase if key == :type
|
51
|
+
attr_info[key] = value
|
52
|
+
end
|
53
|
+
|
54
|
+
decorator = attr.options[:decorator].try(:is_a?, Proc) ? nil : attr.options[:decorator]
|
55
|
+
|
56
|
+
if decorator
|
57
|
+
relative_schema_id(decorator).tap do |id|
|
58
|
+
attr_info[:$ref] = "#/definitions/#{id}"
|
59
|
+
definitions[id] ||= json_schema(decorator, definitions, options)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
schema[:properties][attr.name.to_sym] = attr_info
|
64
|
+
end
|
65
|
+
|
66
|
+
schema
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.schema_title(representer)
|
70
|
+
representer.name.gsub(/Representer/,'')
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.schema_id(representer)
|
74
|
+
"http://#{OpenStax::Api::Engine::MAIN_APP_NAME.to_s}.openstax.org/" +
|
75
|
+
"#{schema_title(representer).downcase.gsub(/::/,'/')}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.relative_schema_id(representer)
|
79
|
+
representer.name.gsub(/Representer/,'').downcase.gsub(/::/,'/')
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Api
|
3
|
+
class Constraints
|
4
|
+
cattr_accessor :main_app_name
|
5
|
+
|
6
|
+
def initialize(options)
|
7
|
+
@version = options[:version]
|
8
|
+
@default = options[:default]
|
9
|
+
end
|
10
|
+
|
11
|
+
def api_accept_header
|
12
|
+
self.main_app_name ||= OpenStax::Api::Engine::MAIN_APP_NAME.underscore
|
13
|
+
"application/vnd.#{self.main_app_name}.openstax.#{@version.to_s}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def matches?(req)
|
17
|
+
@default || req.headers['Accept'].try(:include?, api_accept_header)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Api
|
3
|
+
module DoorkeeperExtensions
|
4
|
+
# Add some fields to Doorkeeper::Application
|
5
|
+
def is_human?
|
6
|
+
false
|
7
|
+
end
|
8
|
+
|
9
|
+
def is_application?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def is_admin?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
OpenStax::Api::Engine.config.after_initialize do
|
21
|
+
Doorkeeper::Application.send :include, OpenStax::Api::DoorkeeperExtensions
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Api
|
3
|
+
class Engine < ::Rails::Engine
|
4
|
+
isolate_namespace OpenStax::Api
|
5
|
+
|
6
|
+
config.after_initialize do
|
7
|
+
MAIN_APP_NAME = ::Rails.application.class.parent_name
|
8
|
+
end
|
9
|
+
|
10
|
+
config.generators do |g|
|
11
|
+
g.test_framework :rspec, :fixture => false
|
12
|
+
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveSupport::Inflector.inflections do |inflect|
|
16
|
+
inflect.acronym 'OpenStax'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'openstax_api/constraints'
|
2
|
+
|
3
|
+
module OpenStax
|
4
|
+
module Api
|
5
|
+
module RouteExtensions
|
6
|
+
def api(version = :v1, default = false)
|
7
|
+
constraints = Constraints.new(version: version, default: default)
|
8
|
+
namespace :api, defaults: {format: 'json'} do
|
9
|
+
scope(module: version,
|
10
|
+
constraints: constraints) { yield }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
ActionDispatch::Routing::Mapper.send :include, OpenStax::Api::RouteExtensions
|
data/lib/openstax_api.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module OpenStax
|
4
|
+
module Api
|
5
|
+
describe ApiUser do
|
6
|
+
let(:user) { User.create }
|
7
|
+
let(:application) { double('Doorkeeper::Application') }
|
8
|
+
let(:doorkeeper_token) { double('Doorkeeper::AccessToken') }
|
9
|
+
let(:non_doorkeeper_user_proc) { lambda { user } }
|
10
|
+
|
11
|
+
context 'human user' do
|
12
|
+
let(:api_user) { ApiUser.new(nil, non_doorkeeper_user_proc) }
|
13
|
+
|
14
|
+
it 'has a human_user but no application' do
|
15
|
+
expect(api_user.application).to be_nil
|
16
|
+
expect(api_user.human_user).to eq(user)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'application with human user' do
|
21
|
+
let(:api_user) { ApiUser.new(doorkeeper_token,
|
22
|
+
non_doorkeeper_user_proc) }
|
23
|
+
|
24
|
+
it 'has a human_user and an application' do
|
25
|
+
doorkeeper_token.stub(:application).and_return(application)
|
26
|
+
doorkeeper_token.stub(:resource_owner_id).and_return(user.id)
|
27
|
+
|
28
|
+
expect(api_user.application).to eq(application)
|
29
|
+
expect(api_user.human_user).to eq(user)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'application only' do
|
34
|
+
let(:api_user) { ApiUser.new(doorkeeper_token,
|
35
|
+
non_doorkeeper_user_proc) }
|
36
|
+
|
37
|
+
it 'has an application but no human_user' do
|
38
|
+
doorkeeper_token.stub(:application).and_return(application)
|
39
|
+
doorkeeper_token.stub(:resource_owner_id).and_return(nil)
|
40
|
+
|
41
|
+
expect(api_user.application).to eq(application)
|
42
|
+
expect(api_user.human_user).to be_nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module OpenStax
|
4
|
+
module Api
|
5
|
+
module V1
|
6
|
+
describe RepresentableSchemaPrinter do
|
7
|
+
it 'must print model schemas' do
|
8
|
+
schema = RepresentableSchemaPrinter.json(UserRepresenter)
|
9
|
+
expect(schema).to include('Schema')
|
10
|
+
expect(schema).to include('.schema')
|
11
|
+
expect(schema).to include('------')
|
12
|
+
expect(schema).to include("<pre class='code'>")
|
13
|
+
expect(schema).to include("{\n \"type\": \"object\",\n \"properties\": {\n \"username\": {\n },\n \"password_hash\": {\n }\n },\n \"required\": [\n\n ],\n \"definitions\": {\n }\n}")
|
14
|
+
expect(schema).to include('</pre>')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Dummy application used to test the openstax_api gem.
|
data/spec/dummy/Rakefile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
|
5
|
+
require File.expand_path('../config/application', __FILE__)
|
6
|
+
|
7
|
+
Dummy::Application.load_tasks
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// the compiled file.
|
9
|
+
//
|
10
|
+
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
11
|
+
// GO AFTER THE REQUIRES BELOW.
|
12
|
+
//
|
13
|
+
//= require jquery
|
14
|
+
//= require jquery_ujs
|
15
|
+
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|