Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataPass API - Lecture / écriture #447

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ AllCops:
- "app/migration/**/*"
- "tmp/**/*"
- "sandbox/**/*"
- "config/initializers/doorkeeper.rb"

FactoryBot/FactoryAssociationWithStrategy:
Enabled: false
Expand Down
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ gem 'caxlsx'
gem 'aws-sdk-s3', require: false
gem 'bootsnap', require: false
gem 'csv'
gem 'doorkeeper'
gem 'doorkeeper-i18n'
gem 'draper'
gem 'emailable'
gem 'importmap-rails', '~> 1.0'
Expand Down Expand Up @@ -83,4 +85,5 @@ group :test do
gem 'rspec-rails', '7.1.0'
gem 'simplecov', require: false
gem 'webmock'
gem 'openapi3_parser'
end
12 changes: 12 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ GEM
nokogiri (~> 1.10, >= 1.10.4)
rubyzip (>= 1.3.0, < 3)
coderay (1.1.3)
commonmarker (2.0.2.1-aarch64-linux)
commonmarker (2.0.2.1-arm64-darwin)
commonmarker (2.0.2.1-x86_64-linux)
concurrent-ruby (1.3.5)
connection_pool (2.5.0)
crack (1.0.0)
Expand Down Expand Up @@ -187,6 +190,10 @@ GEM
reline (>= 0.3.8)
diff-lcs (1.5.1)
docile (1.4.0)
doorkeeper (5.7.1)
railties (>= 5)
doorkeeper-i18n (5.2.7)
doorkeeper (>= 5.2)
draper (4.0.2)
actionpack (>= 5.0)
activemodel (>= 5.0)
Expand Down Expand Up @@ -388,6 +395,8 @@ GEM
omniauth-rails_csrf_protection (1.0.2)
actionpack (>= 4.2)
omniauth (~> 2.0)
openapi3_parser (0.10.0)
commonmarker (>= 1.0)
ostruct (0.6.1)
parallel (1.26.3)
parser (3.3.7.0)
Expand Down Expand Up @@ -630,6 +639,8 @@ DEPENDENCIES
cuprite
database_cleaner-active_record
debug
doorkeeper
doorkeeper-i18n
draper
emailable
factory_bot_rails
Expand Down Expand Up @@ -658,6 +669,7 @@ DEPENDENCIES
omniauth
omniauth-oauth2
omniauth-rails_csrf_protection
openapi3_parser
pg (~> 1.5)
propshaft
puma (>= 5.0)
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/frontal_controller.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class API::FrontalController < APIController
class API::FrontalController < ActionController::API
def index
if frontal?
render json: {
Expand Down
36 changes: 36 additions & 0 deletions app/controllers/api/v1/authorization_requests_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class API::V1::AuthorizationRequestsController < API::V1Controller
def index
authorization_requests = AuthorizationRequest
.where(type: valid_authorization_request_types)
.offset(params[:offset])
.limit(params.fetch(:limit, 10))

if authorization_requests.any?
render json: authorization_requests,
each_serializer: API::V1::AuthorizationRequestSerializer,
status: :ok
else
render_error(404, title: 'Non trouvé', detail: 'Aucune demande n\'a été trouvé')
end
end

def show
authorization_request = AuthorizationRequest
.where(type: valid_authorization_request_types)
.find(params[:id])

render json: authorization_request,
serializer: API::V1::AuthorizationRequestSerializer,
status: :ok
rescue ActiveRecord::RecordNotFound
render_error(404, title: 'Non trouvé', detail: 'Aucune demande n\'a été trouvé')
end

private

def valid_authorization_request_types
current_user.developer_roles.map do |role|
"AuthorizationRequest::#{role.split(':')[0].classify}"
end
end
end
5 changes: 5 additions & 0 deletions app/controllers/api/v1/credentials_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class API::V1::CredentialsController < API::V1Controller
def me
render json: current_user.attributes.slice('id', 'email', 'family_name', 'given_name', 'job_title')
end
end
24 changes: 24 additions & 0 deletions app/controllers/api/v1_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
class API::V1Controller < APIController
rescue_from Doorkeeper::Errors::TokenUnknown, with: :render_unauthorized_error

before_action :doorkeeper_authorize!

protected

def render_unauthorized_error
render_error(401, title: 'Non autorisé', detail: "Un jeton d'accès est requis mais absent dans les en-têtes de la requête.", source: { pointer: 'headers/Authorization' })
end

def render_error(http_code, title:, detail:, source: nil)
render json: {
errors: [
{
status: http_code.to_s,
title:,
detail:,
source:,
}.compact
]
}, status: http_code
end
end
10 changes: 10 additions & 0 deletions app/controllers/api_controller.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
class APIController < ActionController::API
include Authentication

api_mode!

def user_id_session
{
'value' => doorkeeper_token.try(:resource_owner_id),
'expires_at' => (doorkeeper_token.try(:expires_in) || 0) + Time.current.to_i,
}
end
end
18 changes: 12 additions & 6 deletions app/controllers/concerns/authentication.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ module Authentication
included do
before_action :authenticate_user!

helper_method :current_user, :current_organization, :user_signed_in?
helper_method :current_user, :current_organization, :user_signed_in? if respond_to?(:helper_method)
skelz0r marked this conversation as resolved.
Show resolved Hide resolved
end

class_methods do
def allow_unauthenticated_access(**)
skip_before_action(:authenticate_user!, **)
end

alias_method :api_mode!, :allow_unauthenticated_access
end

def sign_in_path
Expand Down Expand Up @@ -52,18 +54,22 @@ def user_signed_in?
end

def valid_user_session?
session[:user_id].present? &&
session[:user_id]['value'].present? &&
session[:user_id]['expires_at'].present? &&
session[:user_id]['expires_at'] > Time.current
user_id_session.present? &&
user_id_session['value'].present? &&
user_id_session['expires_at'].present? &&
user_id_session['expires_at'] > Time.current
end

def user_id_session
session[:user_id]
end

def save_redirect_path
session[:return_to_after_sign_in] = request.url
end

def current_user
@current_user ||= User.find_by(id: session[:user_id].try(:[], 'value'))
@current_user ||= User.find_by(id: user_id_session.try(:[], 'value'))
end

def current_organization
Expand Down
9 changes: 9 additions & 0 deletions app/controllers/open_api_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class OpenAPIController < ApplicationController
include Authentication

allow_unauthenticated_access

layout 'application'

def show; end
end
28 changes: 24 additions & 4 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,31 @@ class User < ApplicationRecord
)",
[
"#{authorization_request_type.underscore}:instructor",
"#{authorization_request_type.underscore}:developer",
"#{authorization_request_type.underscore}:reporter",
]
)
}

add_instruction_boolean_settings :submit_notifications, :messages_notifications

has_many :oauth_applications,
class_name: 'Doorkeeper::Application',
as: :owner,
dependent: :restrict_with_exception

has_many :access_grants,
class_name: 'Doorkeeper::AccessGrant',
foreign_key: :resource_owner_id,
inverse_of: :resource_owner,
dependent: :delete_all

has_many :access_tokens,
class_name: 'Doorkeeper::AccessToken',
foreign_key: :resource_owner_id,
inverse_of: :resource_owner,
dependent: :delete_all

def full_name
if family_name.present? && given_name.present?
"#{family_name} #{given_name}"
Expand All @@ -65,13 +83,15 @@ def instructor?(authorization_request_type = nil)
def reporter_roles
(roles.select { |role|
role.end_with?(':reporter')
} + instructor_roles).uniq
} + instructor_roles + developer_roles).uniq
end

def instructor_roles
roles.select do |role|
role.end_with?(':instructor')
end
roles.select { |role| role.end_with?(':instructor') }
end

def developer_roles
roles.select { |role| role.end_with?(':developer') }
end

def reporter?(authorization_request_type = nil)
Expand Down
1 change: 1 addition & 0 deletions app/serializers/api/v1/authorization_request_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
class API::V1::AuthorizationRequestSerializer < WebhookAuthorizationRequestSerializer; end
8 changes: 6 additions & 2 deletions app/serializers/webhook_authorization_request_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ class WebhookAuthorizationRequestSerializer < ApplicationSerializer

def data
object.data.keys.index_with { |key|
object.public_send(key)
}.symbolize_keys
begin
object.public_send(key)
rescue NoMethodError
nil
end
}.compact.symbolize_keys
end
end
29 changes: 29 additions & 0 deletions app/views/open_api/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<div id="redoc_container">
</div>

<script>
function initRedoc() {
var uri = '<%= open_api_v1_path %>';

Redoc.init(
uri,
{
jsonSampleExpandLevel: 'all',
expandResponses: '200',
expandSingleSchemaField: true,
schemaExpansionLevel: 'all'
},
document.getElementById('redoc_container')
)
}

var redocScript = document.createElement("script");

redocScript.src = "https://cdn.jsdelivr.net/npm/redoc@latest/bundles/redoc.standalone.js";

redocScript.onload = function () {
initRedoc();
};

document.documentElement.firstChild.appendChild(redocScript);
</script>
Loading
Loading