Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/controllers/api/open_api_clients_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ class API::OpenAPIClientsController < API::APIController

def index
authorize OpenAPI::Client
@clients = OpenAPI::Client.order(:created_at)
@clients = policy_scope(OpenAPI::Client).order(:created_at)
end

def create
@client = OpenAPI::Client.new(client_params)
@client.user = current_user
authorize @client
if @client.save
render status: :created
Expand Down
34 changes: 30 additions & 4 deletions app/controllers/open_api/v1/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@ module OpenAPI::V1; end
# Parameters for OpenAPI endpoints
class OpenAPI::V1::BaseController < ActionController::Base # rubocop:disable Rails/ApplicationController
include ApplicationHelper
include Pundit

protect_from_forgery with: :null_session
skip_before_action :verify_authenticity_token
before_action :authenticate
before_action :increment_calls_count
before_action :check_api_permissions

rescue_from ActiveRecord::RecordNotFound, with: :not_found
rescue_from OpenAPI::ParameterError, with: :bad_request
rescue_from ActionController::ParameterMissing, with: :bad_request

rescue_from Pundit::NotAuthorizedError, with: :render_forbidden

rescue_from TypeError, with: :server_error
rescue_from NoMethodError, with: :server_error
rescue_from ArgumentError, with: :server_error

helper_method :current_api_client
helper_method :current_user

protected

Expand All @@ -42,18 +46,40 @@ def authenticate

def authenticate_token
authenticate_with_http_token do |token, _options|
@open_api_client = OpenAPI::Client.find_by(token: token)
api_client = OpenAPI::Client.find_by(token: token)
if api_client&.user
@current_user = api_client.user
@open_api_client = api_client
true
else
false
end
end
end

def current_api_client
@open_api_client
def check_api_permissions
return if current_user.blank?

protected_actions = %i[create update destroy delete]
if protected_actions.include?(action_name.to_sym) && !current_user.admin?
render_forbidden
return false
end
true
end

def current_user
@current_user || super
end

def render_unauthorized
render json: { errors: ['Bad credentials'] }, status: :unauthorized
end

def render_forbidden
render json: { errors: ['Forbidden'] }, status: :forbidden
end

private

def increment_calls_count
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/src/javascript/controllers/admin/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -402,8 +402,8 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
selector: 'body',
stepId: 'conclusion',
order: 4,
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
title: _t('app.shared.tour.conclusion.title'),
content: _t('app.shared.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/src/javascript/controllers/admin/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,8 @@ Application.Controllers.controller('AdminEventsController', ['$scope', '$state',
selector: 'body',
stepId: 'conclusion',
order: 7,
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
title: _t('app.shared.tour.conclusion.title'),
content: _t('app.shared.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/src/javascript/controllers/admin/invoices.js
Original file line number Diff line number Diff line change
Expand Up @@ -672,8 +672,8 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
selector: 'body',
stepId: 'conclusion',
order: 11,
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
title: _t('app.shared.tour.conclusion.title'),
content: _t('app.shared.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/src/javascript/controllers/admin/members.js
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,8 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
selector: 'body',
stepId: 'conclusion',
order: 11,
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
title: _t('app.shared.tour.conclusion.title'),
content: _t('app.shared.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
Expand Down
28 changes: 14 additions & 14 deletions app/frontend/src/javascript/controllers/admin/open_api_clients.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ Application.Controllers.controller('OpenAPIClientsController', ['$scope', 'clien
if (client.id != null) {
OpenAPIClient.update({ id: client.id }, { open_api_client: client }, function (clientResp) {
client = clientResp;
return growl.success(_t('app.admin.open_api_clients.client_successfully_updated'));
return growl.success(_t('app.logged.open_api_clients.client_successfully_updated'));
});
} else {
OpenAPIClient.save({ open_api_client: client }, function (client) {
$scope.clients.push(client);
return growl.success(_t('app.admin.open_api_clients.client_successfully_created'));
return growl.success(_t('app.logged.open_api_clients.client_successfully_created'));
});
}

Expand All @@ -76,16 +76,16 @@ Application.Controllers.controller('OpenAPIClientsController', ['$scope', 'clien
resolve: {
object () {
return {
title: _t('app.admin.open_api_clients.confirmation_required'),
msg: _t('app.admin.open_api_clients.do_you_really_want_to_delete_this_open_api_client')
title: _t('app.logged.open_api_clients.confirmation_required'),
msg: _t('app.logged.open_api_clients.do_you_really_want_to_delete_this_open_api_client')
};
}
}
}
, () =>
OpenAPIClient.delete({ id: $scope.clients[index].id }, function () {
$scope.clients.splice(index, 1);
return growl.success(_t('app.admin.open_api_clients.client_successfully_deleted'));
return growl.success(_t('app.logged.open_api_clients.client_successfully_deleted'));
})
);

Expand All @@ -94,16 +94,16 @@ Application.Controllers.controller('OpenAPIClientsController', ['$scope', 'clien
resolve: {
object () {
return {
title: _t('app.admin.open_api_clients.confirmation_required'),
msg: _t('app.admin.open_api_clients.do_you_really_want_to_revoke_this_open_api_access')
title: _t('app.logged.open_api_clients.confirmation_required'),
msg: _t('app.logged.open_api_clients.do_you_really_want_to_revoke_this_open_api_access')
};
}
}
}
, () =>
OpenAPIClient.resetToken({ id: client.id }, {}, function (clientResp) {
client.token = clientResp.token;
return growl.success(_t('app.admin.open_api_clients.access_successfully_revoked'));
return growl.success(_t('app.logged.open_api_clients.access_successfully_revoked'));
})
);

Expand All @@ -118,25 +118,25 @@ Application.Controllers.controller('OpenAPIClientsController', ['$scope', 'clien
selector: 'body',
stepId: 'welcome',
order: 0,
title: _t('app.admin.tour.open_api.welcome.title'),
content: _t('app.admin.tour.open_api.welcome.content'),
title: _t('app.logged.tour.open_api.welcome.title'),
content: _t('app.logged.tour.open_api.welcome.content'),
placement: 'bottom',
orphan: true
});
uitour.createStep({
selector: '.heading .documentation-button',
stepId: 'doc',
order: 1,
title: _t('app.admin.tour.open_api.doc.title'),
content: _t('app.admin.tour.open_api.doc.content'),
title: _t('app.logged.tour.open_api.doc.title'),
content: _t('app.logged.tour.open_api.doc.content'),
placement: 'bottom'
});
uitour.createStep({
selector: 'body',
stepId: 'conclusion',
order: 2,
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
title: _t('app.shared.tour.conclusion.title'),
content: _t('app.shared.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/src/javascript/controllers/admin/pricing.js
Original file line number Diff line number Diff line change
Expand Up @@ -731,8 +731,8 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
selector: 'body',
stepId: 'conclusion',
order: 7,
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
title: _t('app.shared.tour.conclusion.title'),
content: _t('app.shared.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/src/javascript/controllers/admin/projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,8 @@ Application.Controllers.controller('AdminProjectsController', ['$scope', '$state
selector: 'body',
stepId: 'conclusion',
order: 3,
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
title: _t('app.shared.tour.conclusion.title'),
content: _t('app.shared.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/src/javascript/controllers/admin/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,8 +431,8 @@ Application.Controllers.controller('SettingsController', ['$scope', '$rootScope'
selector: 'body',
stepId: 'conclusion',
order: 11,
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
title: _t('app.shared.tour.conclusion.title'),
content: _t('app.shared.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/src/javascript/controllers/admin/statistics.js
Original file line number Diff line number Diff line change
Expand Up @@ -394,8 +394,8 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
selector: 'body',
stepId: 'conclusion',
order: 3,
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
title: _t('app.shared.tour.conclusion.title'),
content: _t('app.shared.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
Expand Down
4 changes: 2 additions & 2 deletions app/frontend/src/javascript/controllers/admin/trainings.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,8 @@ Application.Controllers.controller('TrainingsAdminController', ['$scope', '$stat
selector: 'body',
stepId: 'conclusion',
order: 4,
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
title: _t('app.shared.tour.conclusion.title'),
content: _t('app.shared.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
Expand Down
11 changes: 5 additions & 6 deletions app/frontend/src/javascript/controllers/main_nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ Application.Controllers.controller('MainNavController', ['$scope', 'settingsProm
linkText: 'app.public.common.subscriptions',
linkIcon: 'credit-card',
class: 'plans-link'
},
{
state: 'app.logged.open_api_clients',
linkText: 'app.public.common.open_api_clients',
linkIcon: 'cloud'
}
].filter(Boolean);

Expand Down Expand Up @@ -167,12 +172,6 @@ Application.Controllers.controller('MainNavController', ['$scope', 'settingsProm
linkText: 'app.public.common.projects',
linkIcon: 'tasks',
authorizedRoles: ['admin']
},
{
state: 'app.admin.open_api_clients',
linkText: 'app.public.common.open_api_clients',
linkIcon: 'cloud',
authorizedRoles: ['admin']
}
].filter(Boolean).concat(Fablab.adminNavLinks);
}
Expand Down
2 changes: 1 addition & 1 deletion app/frontend/src/javascript/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -1299,7 +1299,7 @@ angular.module('application.router', ['ui.router'])
})

// OpenAPI Clients
.state('app.admin.open_api_clients', {
.state('app.logged.open_api_clients', {
url: '/open_api_clients',
views: {
'main@': {
Expand Down
2 changes: 1 addition & 1 deletion app/frontend/src/javascript/services/help.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Application.Services.factory('Help', ['$rootScope', '$uibModal', '$state', 'Auth
'app.admin.projects': 'projects',
'app.admin.statistics': 'statistics',
'app.admin.settings': 'settings',
'app.admin.open_api_clients': 'open-api'
'app.logged.open_api_clients': 'open-api'
};

return function (e) {
Expand Down
18 changes: 9 additions & 9 deletions app/frontend/templates/admin/open_api_clients/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
</div>
<div class="col-xs-10 col-sm-10 col-md-7 b-l b-r-md">
<section class="heading-title">
<h1 translate>{{ 'app.admin.open_api_clients.open_api_clients' }}</h1>
<h1 translate>{{ 'app.logged.open_api_clients.open_api_clients' }}</h1>
</section>
</div>

<div class="col-xs-12 col-sm-12 col-md-4 b-t hide-b-md">
<section class="heading-actions wrapper">
<a href="<%= apipie_apipie_path({version: 'v1'}) %>" target="_blank" class="fab-button is-info m-t-sm documentation-button">
<i class="fa fa-book" aria-hidden="true"></i>&nbsp;
<span translate>{{ 'app.admin.open_api_clients.api_documentation' }}</span>&nbsp;
<span translate>{{ 'app.logged.open_api_clients.api_documentation' }}</span>&nbsp;
<span class="exponent"><i class="fa fa-external-link" aria-hidden="true"></i></span>
</a>
</section>
Expand All @@ -36,11 +36,11 @@
<div class="col-md-12">
<div class="col-md-12">

<button type="button" class="fab-button is-secondary m-t m-b" ng-click="createClient()" ng-show="!clientFormVisible" translate>{{ 'app.admin.open_api_clients.add_new_client' | translate }}</button>
<button type="button" class="fab-button is-secondary m-t m-b" ng-click="createClient()" ng-show="!clientFormVisible" translate>{{ 'app.logged.open_api_clients.add_new_client' | translate }}</button>

<form role="form" id="clientForm" ng-show="clientFormVisible" name="clientForm" class="form-inline m-b m-t" novalidate>
<div class="form-group" ng-class="{'has-error': clientForm['client[name]'].$dirty && clientForm['client[name]'].$invalid}">
<input class="form-control" type="text" name="client[name]" ng-model="client.name" value="" placeholder="{{ 'app.admin.open_api_clients.client_name' | translate }}" required>
<input class="form-control" type="text" name="client[name]" ng-model="client.name" value="" placeholder="{{ 'app.logged.open_api_clients.client_name' | translate }}" required>
</div>

<button class="fab-button" ng-click="cancelEdit()" name="button">{{ 'app.shared.buttons.cancel' | translate }}</button>
Expand All @@ -50,13 +50,13 @@
<table class="table">
<thead>
<tr>
<th style="width:20%"><a ng-click="setOrder('name')">{{ 'app.admin.open_api_clients.name' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': order == 'name', 'fa fa-sort-alpha-desc': order == '-name', 'fa fa-arrows-v': order }"></i></a></th>
<th style="width:20%"><a ng-click="setOrder('name')">{{ 'app.logged.open_api_clients.name' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-alpha-asc': order == 'name', 'fa fa-sort-alpha-desc': order == '-name', 'fa fa-arrows-v': order }"></i></a></th>

<th style="width:15%"><a ng-click="setOrder('calls_count')">{{ 'app.admin.open_api_clients.calls_count' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': order == 'calls_count', 'fa fa-sort-numeric-desc': order == '-calls_count', 'fa fa-arrows-v': order }"></i></a></th>
<th style="width:15%"><a ng-click="setOrder('calls_count')">{{ 'app.logged.open_api_clients.calls_count' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': order == 'calls_count', 'fa fa-sort-numeric-desc': order == '-calls_count', 'fa fa-arrows-v': order }"></i></a></th>

<th style="width:20%"><a>{{ 'app.admin.open_api_clients.token' | translate }}</a></th>
<th style="width:20%"><a>{{ 'app.logged.open_api_clients.token' | translate }}</a></th>

<th style="width:20%"><a ng-click="setOrder('created_at')">{{ 'app.admin.open_api_clients.created_at' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': order == 'created_at', 'fa fa-sort-numeric-desc': order == '-created_at', 'fa fa-arrows-v': order }"></i></a></th>
<th style="width:20%"><a ng-click="setOrder('created_at')">{{ 'app.logged.open_api_clients.created_at' | translate }} <i class="fa fa-arrows-v" ng-class="{'fa fa-sort-numeric-asc': order == 'created_at', 'fa fa-sort-numeric-desc': order == '-created_at', 'fa fa-arrows-v': order }"></i></a></th>

<th style="width:25%"></th>
</tr>
Expand All @@ -74,7 +74,7 @@
</button>

<button class="btn btn-default" ng-click="resetToken(client)">
<i class="fa fa-times"></i> {{ 'app.admin.open_api_clients.reset_token' | translate }}
<i class="fa fa-times"></i> {{ 'app.logged.open_api_clients.reset_token' | translate }}
</button>

<button class="btn btn-danger" ng-click="deleteClient($index)" ng-show="client.calls_count == 0">
Expand Down
6 changes: 6 additions & 0 deletions app/models/open_api/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

# OpenAPI::Client keeps track of the authorized accesses to the 3-rd party API (aka. OpenAPI)
class OpenAPI::Client < ApplicationRecord
belongs_to :user, optional: false
validates :name, presence: true
validates :token, uniqueness: true
validates :user_id, presence: true

before_create :set_initial_token

Expand All @@ -24,4 +26,8 @@ def set_initial_token
def generate_unique_secure_token
SecureRandom.base58(24)
end

def can_perform?(action, resource)
user.can?(action, resource)
end
end
Loading