moonrope 1.4.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -0
  3. data/Gemfile.lock +47 -0
  4. data/MIT-LICENCE +20 -0
  5. data/README.md +24 -0
  6. data/bin/moonrope +28 -0
  7. data/docs/authentication.md +114 -0
  8. data/docs/controllers.md +106 -0
  9. data/docs/exceptions.md +27 -0
  10. data/docs/introduction.md +29 -0
  11. data/docs/structures.md +214 -0
  12. data/example/authentication.rb +50 -0
  13. data/example/controllers/meta_controller.rb +14 -0
  14. data/example/controllers/users_controller.rb +92 -0
  15. data/example/structures/pet_structure.rb +12 -0
  16. data/example/structures/user_structure.rb +35 -0
  17. data/html/assets/lock.svg +3 -0
  18. data/html/assets/reset.css +101 -0
  19. data/html/assets/style.css +348 -0
  20. data/html/assets/tool.svg +4 -0
  21. data/html/assets/try.js +151 -0
  22. data/html/authenticators/default.html +191 -0
  23. data/html/controllers/meta/version.html +144 -0
  24. data/html/controllers/meta.html +73 -0
  25. data/html/controllers/users/create.html +341 -0
  26. data/html/controllers/users/list.html +348 -0
  27. data/html/controllers/users/show.html +261 -0
  28. data/html/controllers/users/update.html +387 -0
  29. data/html/controllers/users.html +93 -0
  30. data/html/index.html +166 -0
  31. data/html/moonrope.txt +0 -0
  32. data/html/structures/pet.html +176 -0
  33. data/html/structures/user.html +338 -0
  34. data/lib/moonrope/action.rb +165 -37
  35. data/lib/moonrope/authenticator.rb +39 -0
  36. data/lib/moonrope/base.rb +24 -6
  37. data/lib/moonrope/controller.rb +4 -2
  38. data/lib/moonrope/doc_context.rb +94 -0
  39. data/lib/moonrope/doc_server.rb +123 -0
  40. data/lib/moonrope/dsl/action_dsl.rb +159 -9
  41. data/lib/moonrope/dsl/authenticator_dsl.rb +31 -0
  42. data/lib/moonrope/dsl/base_dsl.rb +21 -18
  43. data/lib/moonrope/dsl/controller_dsl.rb +60 -9
  44. data/lib/moonrope/dsl/filterable_dsl.rb +27 -0
  45. data/lib/moonrope/dsl/structure_dsl.rb +27 -2
  46. data/lib/moonrope/errors.rb +3 -0
  47. data/lib/moonrope/eval_environment.rb +82 -3
  48. data/lib/moonrope/eval_helpers/filter_helper.rb +82 -0
  49. data/lib/moonrope/eval_helpers.rb +28 -5
  50. data/lib/moonrope/guard.rb +35 -0
  51. data/lib/moonrope/html_generator.rb +65 -0
  52. data/lib/moonrope/param_set.rb +11 -1
  53. data/lib/moonrope/rack_middleware.rb +1 -1
  54. data/lib/moonrope/railtie.rb +31 -14
  55. data/lib/moonrope/request.rb +25 -14
  56. data/lib/moonrope/structure.rb +74 -11
  57. data/lib/moonrope/structure_attribute.rb +15 -0
  58. data/lib/moonrope/version.rb +1 -1
  59. data/lib/moonrope.rb +5 -4
  60. data/moonrope.gemspec +21 -0
  61. data/spec/spec_helper.rb +32 -0
  62. data/spec/specs/action_spec.rb +455 -0
  63. data/spec/specs/base_spec.rb +29 -0
  64. data/spec/specs/controller_spec.rb +31 -0
  65. data/spec/specs/param_set_spec.rb +31 -0
  66. data/templates/basic/_action_form.erb +77 -0
  67. data/templates/basic/_errors_table.erb +32 -0
  68. data/templates/basic/_structure_attributes_list.erb +55 -0
  69. data/templates/basic/action.erb +168 -0
  70. data/templates/basic/assets/lock.svg +3 -0
  71. data/templates/basic/assets/reset.css +101 -0
  72. data/templates/basic/assets/style.css +348 -0
  73. data/templates/basic/assets/tool.svg +4 -0
  74. data/templates/basic/assets/try.js +151 -0
  75. data/templates/basic/authenticator.erb +51 -0
  76. data/templates/basic/controller.erb +20 -0
  77. data/templates/basic/index.erb +114 -0
  78. data/templates/basic/layout.erb +46 -0
  79. data/templates/basic/structure.erb +23 -0
  80. data/test/test_helper.rb +81 -0
  81. data/test/tests/action_access_test.rb +63 -0
  82. data/test/tests/actions_test.rb +524 -0
  83. data/test/tests/authenticators_test.rb +87 -0
  84. data/test/tests/base_test.rb +35 -0
  85. data/test/tests/controllers_test.rb +49 -0
  86. data/test/tests/eval_environment_test.rb +136 -0
  87. data/test/tests/evel_helpers_test.rb +60 -0
  88. data/test/tests/examples_test.rb +11 -0
  89. data/test/tests/helpers_test.rb +97 -0
  90. data/test/tests/param_set_test.rb +44 -0
  91. data/test/tests/rack_middleware_test.rb +109 -0
  92. data/test/tests/request_test.rb +232 -0
  93. data/test/tests/structures_param_extensions_test.rb +159 -0
  94. data/test/tests/structures_test.rb +335 -0
  95. metadata +82 -48
@@ -0,0 +1,151 @@
1
+ $(document).ready(function() {
2
+
3
+ $form = $('form.tryForm')
4
+
5
+ // Get all fields which will be added as headers
6
+ var headerFields = $('input.headerField', $form)
7
+
8
+ // Add stored values to header fields
9
+ if(typeof(Storage) !== "undefined") {
10
+ headerFields.each(function() {
11
+ $field = $(this)
12
+ $field.val(localStorage.getItem("header__" + $(this).attr('name')))
13
+ })
14
+
15
+ }
16
+
17
+
18
+ //
19
+ // Form submission
20
+ //
21
+ $form.on('submit', function() {
22
+
23
+ // Gets values used to make up the URL which should be
24
+ // requested for this request.
25
+ var host = $("input[name=host]", $(this)).val()
26
+ var version = $("input[name=version]", $(this)).val()
27
+ var controller = $("input[name=controller]", $(this)).val()
28
+ var action = $("input[name=action]", $(this)).val()
29
+ var url = host + "/api/" + version + "/" + controller + "/" + action
30
+ // Get the output box ready for use
31
+ var outputBox = $('.tryForm__output', $(this))
32
+ // Create a hash fo all parameters which will be submitted
33
+ var parameters = {}
34
+ $('input.paramField').each(function(){
35
+ $this = $(this)
36
+ value = $this.val()
37
+ type = $this.data('type')
38
+ name = $this.attr('name')
39
+ if(value.length) {
40
+ if(type == 'Integer') {
41
+ parameters[name] = parseInt(value);
42
+ } else if (type == "Hash" || type == "Array") {
43
+ parameters[name] = JSON.parse(value);
44
+ } else {
45
+ parameters[name] = value;
46
+ }
47
+ }
48
+ });
49
+
50
+ // Include/exclude full attributes as needed
51
+ var fullAttrsCheckbox = $('#full_attrs')
52
+ if(fullAttrsCheckbox.length) {
53
+ parameters['_full'] = !!fullAttrsCheckbox.prop('checked')
54
+ }
55
+
56
+ // Include/exclude expansions
57
+ var expansionCheckboxes = $('.tryForm__expansions')
58
+ if(expansionCheckboxes.length) {
59
+ parameters['_expansions'] = []
60
+ expansionCheckboxes.each(function() {
61
+ $this = $(this)
62
+ name = $(this).attr('name')
63
+ if($(this).prop('checked')) {
64
+ parameters['_expansions'].push(name)
65
+ }
66
+ })
67
+ }
68
+
69
+ // Make the AJAX request
70
+ $.ajax({
71
+ url: url,
72
+ method: 'POST',
73
+ contentType: 'application/json',
74
+ data: JSON.stringify(parameters),
75
+ beforeSend: function(xhr) {
76
+ // Add any headers which have been added
77
+ headerFields.each(function() {
78
+ $field = $(this)
79
+ name = $field.attr('name')
80
+ value = $field.val()
81
+ if(typeof(Storage) !== "undefined") {
82
+ localStorage.setItem("header__" + name, value)
83
+ }
84
+ if(value.length) {
85
+ xhr.setRequestHeader(name, $field.val())
86
+ }
87
+ })
88
+ },
89
+ success: function(data) {
90
+ // Success means that we got a 200 OK which means we can be pretty
91
+ // sure that we've got a moonrope response.
92
+ if(data.status == "success") {
93
+ outputBox.addClass('tryForm__output--success').removeClass('tryForm__output--error')
94
+ } else {
95
+ outputBox.addClass('tryForm__output--error').removeClass('tryForm__output--success')
96
+ }
97
+ outputBox.text(JSON.stringify(data, null, 4))
98
+ outputBox.show()
99
+ },
100
+ error: function() {
101
+ // Errors which occurr aren't very well reported at the moment.
102
+ // They should be.
103
+ outputBox.show()
104
+ outputBox.text("Failed to make request.")
105
+ outputBox.addClass('tryForm__output--error').removeClass('tryForm__output--success')
106
+ }
107
+ })
108
+ return false
109
+ });
110
+
111
+ //
112
+ // Open the try form
113
+ //
114
+ $('p.tryFormActivate a').on('click', function() {
115
+ $form = $('form.tryForm')
116
+ $parent = $(this).parents('p')
117
+ $form.show('fast')
118
+ $parent.hide()
119
+ return false
120
+ });
121
+
122
+ //
123
+ // Close the try form
124
+ //
125
+ $('button.tryFormCancel').on('click', function() {
126
+ $form = $('form.tryForm')
127
+ $parent = $('p.tryFormActivate')
128
+ $form.hide()
129
+ $parent.show()
130
+ return false
131
+ });
132
+
133
+ // http://stackoverflow.com/questions/8100770/auto-scaling-inputtype-text-to-width-of-value
134
+ // http://jsfiddle.net/MqM76/217/
135
+ $.fn.textWidth = function(text, font) {
136
+ if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').hide().appendTo(document.body);
137
+ $.fn.textWidth.fakeEl.text(text || this.val() || this.text()).css('font', font || this.css('font'));
138
+ return $.fn.textWidth.fakeEl.width();
139
+ };
140
+
141
+ // Automatically ensure that the size for the header inputs is
142
+ // correct
143
+ function resizeInput() {
144
+ $this = $(this)
145
+ $this.css('width', $this.textWidth() + "px")
146
+ $this.attr('size', $this.val().length)
147
+ }
148
+
149
+ $('form.tryForm .tryForm__header input').on('input', resizeInput).trigger('input')
150
+
151
+ });
@@ -0,0 +1,51 @@
1
+
2
+ <% if authenticator.name == :default %>
3
+ <% set_page_title "Authentication" %>
4
+ <% set_active_nav "authenticator-default" %>
5
+ <h1>Authentication</h1>
6
+ <% else %>
7
+ <% set_page_title "#{humanize(authenticator.name.to_s.capitalize)} Authenticator" %>
8
+ <h1><%= humanize(authenticator.name.to_s.capitalize) %> Authenticator</h1>
9
+ <% end %>
10
+
11
+ <p class='text'>
12
+ <%= authenticator.description %>
13
+ </p>
14
+
15
+ <h2>Authentication Headers</h2>
16
+ <p class='text'>
17
+ The following headers are used to identify yourself to the API client. These should be
18
+ sent as standard HTTP headers with any API request.
19
+ </p>
20
+ <table class='table paramTable'>
21
+ <thead>
22
+ <tr>
23
+ <th width="60%">Header</th>
24
+ <th width="40%">Example</th>
25
+ </tr>
26
+ </thead>
27
+ <% for name, options in authenticator.headers %>
28
+ <tr>
29
+ <td>
30
+ <p>
31
+ <span class='paramTable__name'><%= name %></span>
32
+ </p>
33
+ <% if options[:description] %>
34
+ <p class='paramTable__description'><%= options[:description] %></p>
35
+ <% end %>
36
+ </td>
37
+ <td><%= options[:eg] || options[:example] %> </td>
38
+ </tr>
39
+ <% end %>
40
+ </table>
41
+
42
+ <h2>Errors</h2>
43
+ <p class='text'>
44
+ The errors listed below may be raised if any issues occur when verifying your
45
+ identity with the API.
46
+ </p>
47
+ <% if authenticator.errors.empty? %>
48
+ <p><em>There are no errors which can be raised.</em></p>
49
+ <% else %>
50
+ <%= partial "errors_table", :errors => authenticator.errors %>
51
+ <% end %>
@@ -0,0 +1,20 @@
1
+ <% set_page_title controller.friendly_name || controller.name %>
2
+ <% set_active_nav "controller-#{controller.name}" %>
3
+ <h1><%= controller.friendly_name || controller.name %></h1>
4
+ <% if controller.description %>
5
+ <p class='text'><%= controller.description %></p>
6
+ <% end %>
7
+ <h2>Action</h2>
8
+ <p class='text'>
9
+ The following actions are available. Choose from the list below
10
+ to view full details of how to access them.
11
+ </p>
12
+ <ul class='standardList'>
13
+ <% for action in controller.actions.values.select { |a| a.doc != false } %>
14
+ <li>
15
+ <a class='link' href='<%= path("controllers/#{action.controller.name}/#{action.name}") %>'><%= action.title || action.name %></a>
16
+ <p class='apiURL'><span><%= full_prefix %>/</span><b><%= action.controller.name %>/<%= action.name %></b></p>
17
+ <% if action.description %><p class='meta'><%= action.description %></p><% end %>
18
+ </li>
19
+ <% end %>
20
+ </ul>
@@ -0,0 +1,114 @@
1
+ <% set_page_title "Welcome" %>
2
+ <% set_active_nav "home" %>
3
+ <h1>Welcome to our API documentation</h1>
4
+ <p class='text'>
5
+ From here you can browse the full documentation for our HTTP
6
+ API. Our API is split into sections which you can browse using
7
+ the menu on the right. If you have any questions, you can
8
+ <a href='#'>contact our team</a> and we'll be happy to help out.
9
+ </p>
10
+ <p class='text'>
11
+ Before you get started, take a few minutes to review the
12
+ information below about how to interact with our API. It includes
13
+ information about how to send requests, what response data is
14
+ sent in and how to handle errors.
15
+ </p>
16
+
17
+ <h2>Making requests</h2>
18
+ <p class='text'>
19
+ Our API works over the HTTP protocol with JSON. It is implemented
20
+ in an RPC-like manner and everything you can do with the API has
21
+ its own <em>action</em>.
22
+ </p>
23
+ <p class='text'>
24
+ All HTTP requests must be made over HTTPS to the URL shown on the
25
+ action's page in this documentation. All responses you receive from
26
+ the API will be returned in JSON. Requests should be made using the
27
+ <code>POST</code> method with any parameters encoded as JSON in the
28
+ body of the request.
29
+ </p>
30
+
31
+ <h2>Receiving responses</h2>
32
+ <p class='text'>
33
+ All responses will be returned to you encoded as JSON. You will always
34
+ receive a hash as the response which will look like the JSON below:
35
+ </p>
36
+ <pre class='code'>
37
+ {
38
+ <span class='jsonKey'>"status"</span>:<span class='jsonString'>"success"</span>,
39
+ <span class='jsonKey'>"time"</span>:<span class='jsonString'>0.123</span>,
40
+ <span class='jsonKey'>"flags"</span>:{
41
+ <span class='jsonComment'>... additional information about the request ...</span>
42
+ },
43
+ <span class='jsonKey'>"data"</span>:{
44
+ <span class='jsonComment'>... the data returned from the action ...</span>
45
+ }
46
+ }
47
+ </pre>
48
+ <p class='text'>
49
+ The <b>status</b> attribute will give you can indication about whether the
50
+ request was performed successfully or whether an error occurred. Values which
51
+ may be returned are shown below:
52
+ </p>
53
+ <ul class='standardList'>
54
+ <li>
55
+ <code>success</code> - this means that the request completed successfully
56
+ and returned the data that was expected.
57
+ </li>
58
+ <li>
59
+ <code>parameter-error</code> - the parameters provided for the action are
60
+ not valid and should be revised.
61
+ </li>
62
+ <li>
63
+ <code>error</code> - an error occurred that didn't fit into the above categories.
64
+ This will be accompanied with an error code, a descriptive message and further
65
+ attributes which may be useful. The actual potential errors for each action are
66
+ shown in the documentation.
67
+ </li>
68
+ </ul>
69
+ <p class='text'>
70
+ The <b>time</b> attribute shows how long the request took to complete on the
71
+ server side.
72
+ </p>
73
+ <p class='text'>
74
+ The <b>flags</b> attribute contains a hash of additional attributes
75
+ which are relevant to your request. For example, if you receive an array of data
76
+ it may be paginated and this pagination data will be returned in this
77
+ hash.
78
+ </p>
79
+ <p class='text'>
80
+ The <b>data</b> attribute contains the result of your request. Depending on the
81
+ status, this will either contain the data requested or details of any
82
+ error which has occurred.
83
+ </p>
84
+ <h3>A note about HTTP status code</h3>
85
+ <p class='text'>
86
+ The API does not generally use HTTP status codes to return information
87
+ about the outcome of a request. There are two supported statuses with
88
+ the API:
89
+ </p>
90
+ <ul class='standardList'>
91
+ <li>
92
+ <code>200 OK</code> - This is the code you'll usually receive.
93
+ It indicates that the response was successfully delivered and
94
+ returned to our service (although does not nessesary mean that
95
+ the action you were expecting was successful). Further status
96
+ information will be provided in the <code>status</code> attribute
97
+ on your response body.
98
+ </li>
99
+ <li>
100
+ <code>301 Moved Permanently</code> or <code>308 Permanent Redirect</code> -
101
+ This means that the API request should be sent to an alternative
102
+ URL. This may just mean you need to send your request using <code>https</code>
103
+ rather than <code>http</code> as the protocol.
104
+ </li>
105
+ <li>
106
+ <code>500 Internal Server Error</code> - This will be returned
107
+ when an error occurred within the API itself. This was not
108
+ anticipated by us and should be reported to us.
109
+ </li>
110
+ <li>
111
+ <code>503 Service Unavailable</code> - This will be returned if
112
+ API is currently unavailable for maintenance or other issue.
113
+ </li>
114
+ </ul>
@@ -0,0 +1,46 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title><%= page_title %> - API Documentation</title>
5
+ <link href='https://fonts.googleapis.com/css?family=Lato:400,700,900' rel='stylesheet' type='text/css'>
6
+ <link href='https://fonts.googleapis.com/css?family=Droid+Sans+Mono' rel='stylesheet' type='text/css'>
7
+ <link rel="stylesheet" href="<%= asset_path('reset.css') %>">
8
+ <link rel="stylesheet" href="<%= asset_path('style.css') %>">
9
+ </head>
10
+ <body>
11
+ <section class='sidebarBackground'></section>
12
+ <section class="sidebar">
13
+ <nav>
14
+ <ul>
15
+ <li>
16
+ <a href='<%= path(:root) %>' class="<%= active_nav == 'home' ? 'active' : '' %>">
17
+ Home
18
+ </a>
19
+ </li>
20
+ <% if base.authenticators[:default] %>
21
+ <li>
22
+ <a href='<%= path('authenticators/default') %>' class="<%= active_nav == 'authenticator-default' ? 'active' : '' %>">
23
+ Authentication
24
+ </a>
25
+ </li>
26
+ <% end %>
27
+ <% for controller in base.controllers.select { |c| c.doc != false }.sort_by { |c| c.name.to_s } %>
28
+ <li>
29
+ <a href='<%= path("controllers/#{controller.name}") %>' class="<%= active_nav == "controller-#{controller.name}" ? 'active' : '' %>">
30
+ <%= controller.friendly_name || controller.name %>
31
+ </a>
32
+ </li>
33
+ <% end %>
34
+ </ul>
35
+ </nav>
36
+ </section>
37
+ <section class='content'>
38
+ <%= body %>
39
+ </section>
40
+ <footer class='footer'>
41
+ <p>Generated by Moonrope at <%= Time.now.strftime("%H:%M on %A %e %B %Y") %> for <%= git_version[0,6] %></p>
42
+ </footer>
43
+ <script src='https://code.jquery.com/jquery-1.12.0.min.js'></script>
44
+ <script src='<%= asset_path('try.js') %>'></script>
45
+ </body>
46
+ </html>
@@ -0,0 +1,23 @@
1
+ <% set_page_title "#{humanize(structure.name.capitalize)} Structure" %>
2
+
3
+ <h1><%= humanize(structure.name.capitalize) %> Structure</h1>
4
+
5
+ <h2>Base Attributes</h2>
6
+ <%= partial 'structure_attributes_list', :structure => structure, :attributes => structure.attributes[:basic].select { |a| a.doc != false } %>
7
+
8
+ <% full_attrs = structure.attributes[:full].select { |a| a.doc != false } %>
9
+ <% unless full_attrs.empty? %>
10
+ <h2>Extended Attributes</h2>
11
+ <%= partial 'structure_attributes_list', :structure => structure, :attributes => full_attrs %>
12
+ <% end %>
13
+
14
+ <% if !structure.attributes[:expansion].empty? || !structure.expansions.empty? %>
15
+ <h2>Expansions</h2>
16
+ <p class='text'>
17
+ Expansions are embedded structures of other objects that are related to the structure
18
+ that you're viewing. Which expansions are returned by a specific action are shown on that
19
+ action's documentation however some actions allow you to choose which expansions are
20
+ returned.
21
+ </p>
22
+ <%= partial 'structure_attributes_list', :structure => structure, :attributes => structure.attributes[:expansion], :expansions => structure.expansions.select { |k,v| v[:doc] != false} %>
23
+ <% end %>
@@ -0,0 +1,81 @@
1
+ require 'test/unit'
2
+ require 'rack/test'
3
+ require 'moonrope'
4
+
5
+ class Test::Unit::TestCase
6
+
7
+ private
8
+
9
+ def make_rack_env_hash(path, params = {}, other_env = {})
10
+ request = Rack::Test::Session.new(nil)
11
+ request.send :env_for, path, {:params => params, :method => 'POST'}.merge(other_env)
12
+ end
13
+
14
+ end
15
+
16
+ #
17
+ # A fake base object for models
18
+ #
19
+ class ModelBase
20
+ def initialize(attributes = {})
21
+ attributes.each do |key, value|
22
+ instance_variable_set("@#{key}", value)
23
+ end
24
+ end
25
+ end
26
+
27
+ class Animal < ModelBase
28
+ attr_accessor :id, :name, :color, :user
29
+ end
30
+
31
+ class User < ModelBase
32
+ attr_accessor :id, :username, :private_code, :admin
33
+ def animals
34
+ @animals ||= []
35
+ end
36
+ end
37
+
38
+ class UserWithUnderscore < User
39
+ class << self
40
+ def name
41
+ s = Struct.new(:underscore, :to_s).new
42
+ s.to_s = 'User'
43
+ s.underscore = 'user'
44
+ s
45
+ end
46
+ end
47
+ end
48
+
49
+ #
50
+ # A fake request class for use in some tests
51
+ #
52
+ class FakeRequest
53
+
54
+ def initialize(options = {})
55
+ @options = options
56
+ end
57
+
58
+ def params
59
+ @params ||= Moonrope::ParamSet.new(@options[:params] || {})
60
+ end
61
+
62
+ def version
63
+ @options[:version]
64
+ end
65
+
66
+ def identity
67
+ @options[:identity]
68
+ end
69
+
70
+ def action
71
+ nil
72
+ end
73
+
74
+ end
75
+
76
+ #
77
+ # Require all tests
78
+ #
79
+ Dir[File.expand_path("../tests/**/*.rb", __FILE__)].each do |filename|
80
+ require filename
81
+ end
@@ -0,0 +1,63 @@
1
+ class ActionAccessTest < Test::Unit::TestCase
2
+
3
+ def setup
4
+ @base = Moonrope::Base.new do
5
+ authenticator :default do
6
+ rule :default, "AccessDenied" do
7
+ identity == :admin
8
+ end
9
+
10
+ rule :anonymous, "MustBeAnonymous" do
11
+ identity.nil?
12
+ end
13
+ end
14
+ end
15
+ @controller = Moonrope::Controller.new(@base, :users)
16
+ end
17
+
18
+ def test_action_uses_default_access_rule_by_default
19
+ action = Moonrope::Action.new(@controller, :list)
20
+ # no authentication has been provided
21
+ assert_equal false, action.check_access
22
+ # authentication which is not correct
23
+ authenticated_request = FakeRequest.new(:identity => :dave)
24
+ assert_equal false, action.check_access(authenticated_request)
25
+ # authentication which is correct
26
+ authenticated_request = FakeRequest.new(:identity => :admin)
27
+ assert_equal true, action.check_access(authenticated_request)
28
+ end
29
+
30
+ def test_action_can_use_controller_rule
31
+ controller = Moonrope::Controller.new(@base, :users) do
32
+ access_rule :anonymous
33
+ end
34
+ action = Moonrope::Action.new(controller, :list)
35
+ # anonymous is ok
36
+ assert_equal true, action.check_access
37
+ # with a user is not
38
+ authenticated_request = FakeRequest.new(:identity => :dave)
39
+ assert_equal false, action.check_access(authenticated_request)
40
+ end
41
+
42
+ def test_action_can_use_action_rule
43
+ action = Moonrope::Action.new(@controller, :list) do
44
+ access_rule :anonymous
45
+ end
46
+ # anonymous is ok
47
+ assert_equal true, action.check_access
48
+ # with a user is not
49
+ authenticated_request = FakeRequest.new(:identity => :dave)
50
+ assert_equal false, action.check_access(authenticated_request)
51
+ end
52
+
53
+ def test_that_invalid_rule_names_raise_errors
54
+ action = Moonrope::Action.new(@controller, :list) do
55
+ access_rule :missing
56
+ end
57
+ # anonymous is ok
58
+ assert_raises Moonrope::Errors::MissingAccessRule do
59
+ action.check_access
60
+ end
61
+ end
62
+
63
+ end