mumuki-laboratory 5.10.0 → 5.10.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5fa7aa2c319aee6bd932340664e1ed91d87d3dcee8f9b8f429301a7e02b2526
4
- data.tar.gz: d12b201ddb14ba04dfbe233d5e57fcec1b57260c85a622243ed03de1226550d2
3
+ metadata.gz: 42dc9471f1a0a74ace505a73db807a18852b0347f79059953eb5c46a2756fc73
4
+ data.tar.gz: e03f2a3eb2f5037cbe01d12847cd0c9bf200ce8d6c5729f7c20536837f09f8c3
5
5
  SHA512:
6
- metadata.gz: d5cc2dcc2980e75f1446a5f9b8c315efd3030e0ce90084edf406cb1303442d91870515d82d13051229458fe34c2bd60ce2e5a7560462188d806bd7b39cbc0bde
7
- data.tar.gz: 013b96fa9769ba74eba05dd26822872f35acc05e9e60f93b88cdf0c5d81bab5822dc025bb9f73d90168774e7aa6d3b61f6d0f2cd7a677376ae17a78b9187114a
6
+ metadata.gz: 2e36aac69358d75f9eceb7058c5fcbf38041acdc8be060aa0703bffab770175277a3b5b6bb669ce19118ce0c7b3cf95c9034584476e907d604e38a9eb583d2ce
7
+ data.tar.gz: e10e71a29c00f626bf47a5e2ab008bee671638bc57e8b633e9af62025e4edd330fb550014084e7f173f85ef1b5e64613da3465d6b2e65fc111ec4e158e383344
@@ -31,7 +31,7 @@ div.console div.jquery-console-focus span.jquery-console-cursor {
31
31
 
32
32
  div.console div.jquery-console-message-error {
33
33
  color: #d62c1a;
34
- font-family: sans-serif;
34
+ font-family: monospace;
35
35
  font-weight: bold;
36
36
  padding: 0.1em;
37
37
  }
@@ -4,7 +4,7 @@ module Api
4
4
 
5
5
  protect_from_forgery with: :null_session
6
6
 
7
- include WithApiErrors
7
+ include Mumuki::Laboratory::Controllers::DynamicErrors
8
8
  include WithAuthorization
9
9
  include Mumuki::Laboratory::Controllers::CurrentOrganization
10
10
 
@@ -9,12 +9,12 @@ class ApiClient < ApplicationRecord
9
9
  before_create :set_encoded_token!
10
10
 
11
11
  def verify!
12
- raise 'Invalid Api Client' if Mumukit::Auth::Token.decode(token).uid != user.uid
12
+ self.class.invalid_token! 'Invalid Api Client' if Mumukit::Auth::Token.decode(token).uid != user.uid
13
13
  end
14
14
 
15
15
  def self.verify_token!(token)
16
16
  client = find_by token: token
17
- raise 'No Api Client found for Token' unless client
17
+ invalid_token! 'No Api Client found for Token' unless client
18
18
  client.verify!
19
19
  end
20
20
 
@@ -24,4 +24,8 @@ class ApiClient < ApplicationRecord
24
24
  self.token = Mumukit::Auth::Token.encode user.uid, {}
25
25
  end
26
26
 
27
+ def self.invalid_token!(message)
28
+ raise Mumukit::Auth::InvalidTokenError, message
29
+ end
30
+
27
31
  end
@@ -8,37 +8,62 @@ module Mumuki::Laboratory::Controllers::DynamicErrors
8
8
  end
9
9
  rescue_from ActiveRecord::RecordNotFound, with: :not_found
10
10
  rescue_from Mumukit::Auth::UnauthorizedAccessError, with: :forbidden
11
+ rescue_from Mumukit::Auth::InvalidTokenError, with: :unauthorized
11
12
  rescue_from Mumuki::Laboratory::NotFoundError, with: :not_found
12
13
  rescue_from Mumuki::Laboratory::ForbiddenError, with: :forbidden
13
14
  rescue_from Mumuki::Laboratory::UnauthorizedError, with: :unauthorized
14
15
  rescue_from Mumuki::Laboratory::GoneError, with: :gone
15
16
  rescue_from Mumuki::Laboratory::BlockedForumError, with: :blocked_forum
17
+ rescue_from ActiveRecord::RecordInvalid, with: :bad_record
18
+ end
19
+
20
+ def bad_record(exception)
21
+ # bad records can only be produced thourgh API
22
+ render_api_errors exception.record.errors, 400
16
23
  end
17
24
 
18
25
  def not_found
19
- render 'errors/not_found', status: 404, formats: [:html]
26
+ render_error 'not_found', 404, formats: [:html]
20
27
  end
21
28
 
22
29
  def internal_server_error(exception)
23
30
  Rails.logger.error "Internal server error: #{exception} \n#{exception.backtrace.join("\n")}"
24
- render 'errors/internal_server_error', status: 500
31
+ render_error 'internal_server_error', 500
25
32
  end
26
33
 
27
- def unauthorized
28
- render 'errors/unauthorized', status: 401
34
+ def unauthorized(exception)
35
+ render_error 'unauthorized', 401, error_message: exception.message
29
36
  end
30
37
 
31
38
  def forbidden
32
- Rails.logger.info "Access to organization #{Organization.current} was forbidden to user #{current_user} with permissions #{current_user.permissions}"
33
- render 'errors/forbidden', status: 403, locals: { explanation: :forbidden_explanation }
39
+ message = "Access to organization #{Organization.current} was forbidden to user #{current_user.uid} with permissions #{current_user.permissions.to_json}"
40
+ Rails.logger.info message
41
+ render_error 'forbidden', 403, locals: { explanation: :forbidden_explanation }, error_message: message
34
42
  end
35
43
 
36
44
  def blocked_forum
37
- render 'errors/forbidden', status: 403, locals: { explanation: :blocked_forum_explanation }
45
+ render_error 'forbidden', 403, locals: { explanation: :blocked_forum_explanation }
38
46
  end
39
47
 
40
48
  def gone
41
- render 'errors/gone', status: 410
49
+ render_error 'gone', 410
50
+ end
51
+
52
+ def render_error(template, status, options={})
53
+ if Mumukit::Platform.organization_mapping.path_under_namespace? request.path, 'api'
54
+ render_api_errors [options[:error_message] || template.gsub('_', ' ')], status
55
+ else
56
+ render_app_errors template, options.merge(status: status).except(:error_message)
57
+ end
42
58
  end
43
59
 
60
+ private
61
+
62
+ def render_app_errors(template, options)
63
+ render "errors/#{template}", options
64
+ end
65
+
66
+ def render_api_errors(errors, status)
67
+ render json: { errors: errors }, status: status
68
+ end
44
69
  end
@@ -18,6 +18,14 @@ class Mumuki::Laboratory::Engine < ::Rails::Engine
18
18
  config.i18n.available_locales = Mumukit::Platform::Locale.supported
19
19
  end
20
20
 
21
+ module Mumukit::Platform::OrganizationMapping::Subdomain
22
+ class << self
23
+ def path_under_namespace?(path, namespace)
24
+ path.start_with? "/#{namespace}/"
25
+ end
26
+ end
27
+ end
28
+
21
29
  module Mumukit::Platform::OrganizationMapping::Path
22
30
  class << self
23
31
  alias __organization_name__ organization_name
@@ -30,5 +38,9 @@ module Mumukit::Platform::OrganizationMapping::Path
30
38
  name
31
39
  end
32
40
  end
41
+
42
+ def path_under_namespace?(path, namespace)
43
+ path.start_with? "/#{Mumukit::Platform.current_organization_name}/#{namespace}/"
44
+ end
33
45
  end
34
46
  end
@@ -1,5 +1,5 @@
1
1
  module Mumuki
2
2
  module Laboratory
3
- VERSION = '5.10.0'
3
+ VERSION = '5.10.1'
4
4
  end
5
5
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ApiClientsController, type: :controller, organization_workspace: :base do
4
- before { @request.env["HTTP_AUTHORIZATION"] = api_client.token }
4
+ before { set_api_client! api_client }
5
5
  let(:api_client) { create :api_client }
6
6
  let(:api_client_json) do
7
7
  {description: 'foo',
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Api::CoursesController, type: :controller, organization_workspace: :base do
4
- before { set_api_client! }
4
+ before { set_api_client! api_client }
5
5
  let(:api_client) { create :api_client }
6
6
  let(:course_json) do
7
7
  {slug: 'test/bar',
@@ -6,18 +6,22 @@ describe Api::OrganizationsController, type: :controller, organization_workspace
6
6
  end
7
7
 
8
8
  describe 'unauthenticated request' do
9
- it { expect { get :index }.to raise_error 'missing authorization header' }
9
+ before { get :index }
10
+ it { expect(response.body).to json_eq errors: ['missing authorization header'] }
11
+ it { check_status! 401 }
10
12
  end
11
13
 
12
- describe 'unauthenticated request' do
13
- before { @request.env["HTTP_AUTHORIZATION"] = 'foo' }
14
- it { expect { get :index }.to raise_error 'No Api Client found for Token' }
14
+ describe 'invalid authenticated request' do
15
+ before { set_token! 'foo' }
16
+ before { get :index }
17
+ it { expect(response.body).to json_eq errors: ['No Api Client found for Token'] }
18
+ it { check_status! 401 }
15
19
  end
16
20
 
17
21
  describe 'authenticated request' do
18
22
  let(:book) { create :book }
19
23
 
20
- before { set_api_client! }
24
+ before { set_api_client! api_client }
21
25
 
22
26
  describe 'GET' do
23
27
  let!(:public_organization) { create :organization, name: 'public' }
@@ -33,7 +37,7 @@ describe Api::OrganizationsController, type: :controller, organization_workspace
33
37
 
34
38
  it { check_status! 200 }
35
39
 
36
- it { expect(body[:organizations].map { |it| it[:name] }).to contain_exactly(*%w(base public dot.org private another_private)) }
40
+ it { expect(body[:organizations].map { |it| it[:name] }).to contain_exactly 'base', 'public', 'dot.org', 'private', 'another_private' }
37
41
  end
38
42
  context 'with non-wildcard permissions' do
39
43
  before { get :index }
@@ -42,7 +46,7 @@ describe Api::OrganizationsController, type: :controller, organization_workspace
42
46
 
43
47
  it { check_status! 200 }
44
48
 
45
- it { expect(body[:organizations].map { |it| it[:name] }).to eq %w(public private) }
49
+ it { expect(body[:organizations].map { |it| it[:name] }).to contain_exactly 'public', 'private' }
46
50
  end
47
51
  end
48
52
 
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  [:student, :teacher].each do |role|
4
4
 
5
5
  describe "Api::#{role.capitalize}sController".constantize, type: :controller, organization_workspace: :base do
6
- before { set_api_client! }
6
+ before { set_api_client! api_client }
7
7
  let(:api_client) { create :api_client, grant: 'anorganization/*' }
8
8
  let(:json) { {
9
9
  first_name: 'Agustin',
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Api::UsersController, type: :controller, organization_workspace: :base do
4
- before { set_api_client! }
4
+ before { set_api_client! api_client }
5
5
  let(:api_client) { create :api_client }
6
6
  let(:user_json) do
7
7
  {
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'not found on app', organization_workspace: :base do
4
+ before { set_subdomain_host! Organization.base.name }
5
+ before { Organization.base.switch! }
6
+
7
+ let(:owner) { create(:user, permissions: {owner: '*'}) }
8
+ let(:student_api_client) { create :api_client, role: :student, grant: 'central/*' }
9
+ let(:owner_api_client) { create :api_client, role: :owner, grant: '*' }
10
+
11
+ scenario 'app without authentication' do
12
+ visit '/nonexistentroute'
13
+
14
+ expect(page).to have_text 'You are not allowed to see this content'
15
+ end
16
+
17
+ scenario 'app with authentication' do
18
+ set_current_user! owner
19
+
20
+ visit '/nonexistentroute'
21
+
22
+ expect(page).to have_text 'You may have mistyped the address or the page may have moved'
23
+ end
24
+
25
+ scenario 'api without authorization' do
26
+ Capybara.current_session.driver.header 'Authorization', "Bearer #{student_api_client.token}"
27
+
28
+ visit '/api/nonexistentroute'
29
+
30
+ expect(page.text).to json_eq errors: [
31
+ 'Access to organization base' +
32
+ ' was forbidden to user foo+1@bar.com' +
33
+ ' with permissions {"student":"central/*","teacher":"","headmaster":"","janitor":"","owner":""}']
34
+ end
35
+
36
+ scenario 'api with authentication' do
37
+ Capybara.current_session.driver.header 'Authorization', "Bearer #{owner_api_client.token}"
38
+
39
+ visit '/api/nonexistentroute'
40
+
41
+ expect(page.text).to json_eq errors: ['not found']
42
+ end
43
+ end
@@ -57,8 +57,12 @@ Mumukit::Auth.configure do |c|
57
57
  c.clients.default = {id: 'test-client', secret: 'thisIsATestSecret'}
58
58
  end
59
59
 
60
- def set_api_client!
61
- @request.env["HTTP_AUTHORIZATION"] = api_client.token
60
+ def set_token!(token)
61
+ @request.env["HTTP_AUTHORIZATION"] = token
62
+ end
63
+
64
+ def set_api_client!(api_client)
65
+ set_token! api_client.token
62
66
  end
63
67
 
64
68
  def reindex_organization!(organization)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mumuki-laboratory
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.10.0
4
+ version: 5.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Franco Bulgarelli
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-09-24 00:00:00.000000000 Z
11
+ date: 2018-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -333,7 +333,6 @@ files:
333
333
  - app/controllers/concerns/on_base_organization_only.rb
334
334
  - app/controllers/concerns/organizations_controller_template.rb
335
335
  - app/controllers/concerns/users_controller_template.rb
336
- - app/controllers/concerns/with_api_errors.rb
337
336
  - app/controllers/concerns/with_authorization.rb
338
337
  - app/controllers/concerns/with_errors_filter.rb
339
338
  - app/controllers/discussions_controller.rb
@@ -960,7 +959,8 @@ files:
960
959
  - spec/features/links_flow_spec.rb
961
960
  - spec/features/login_flow_spec.rb
962
961
  - spec/features/menu_bar_spec.rb
963
- - spec/features/not_found_flow_spec.rb
962
+ - spec/features/not_found_private_flow_spec.rb
963
+ - spec/features/not_found_public_flow_spec.rb
964
964
  - spec/features/profile_flow_spec.rb
965
965
  - spec/features/progressive_tips_spec.rb
966
966
  - spec/features/standard_flow_spec.rb
@@ -1148,7 +1148,8 @@ test_files:
1148
1148
  - spec/features/links_flow_spec.rb
1149
1149
  - spec/features/login_flow_spec.rb
1150
1150
  - spec/features/menu_bar_spec.rb
1151
- - spec/features/not_found_flow_spec.rb
1151
+ - spec/features/not_found_private_flow_spec.rb
1152
+ - spec/features/not_found_public_flow_spec.rb
1152
1153
  - spec/features/profile_flow_spec.rb
1153
1154
  - spec/features/progressive_tips_spec.rb
1154
1155
  - spec/features/standard_flow_spec.rb
@@ -1,37 +0,0 @@
1
- module WithApiErrors
2
- # TODO we should extend DynamiceErrors
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- unless Rails.application.config.consider_all_requests_local
7
- rescue_from ActionController::RoutingError, with: :not_found!
8
- end
9
-
10
- rescue_from ActiveRecord::RecordNotFound, with: :not_found!
11
- rescue_from Mumukit::Auth::UnauthorizedAccessError, with: :forbidden!
12
- rescue_from ActiveRecord::RecordInvalid, with: :bad_record!
13
- end
14
-
15
- private
16
-
17
- def bad_record!(e)
18
- render_errors! e.record.errors, 400
19
- end
20
-
21
- def not_found!(e)
22
- render_error! e, 404
23
- end
24
-
25
- def forbidden!(e)
26
- render_error! e, 403
27
- end
28
-
29
- def render_error!(e, status)
30
- render_errors! [e.message], status
31
- end
32
-
33
- def render_errors!(errors, status)
34
- summary = { errors: errors }
35
- render json: summary, status: status
36
- end
37
- end