mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-07 13:44:23 +08:00
Merge latest core-api branch [SCI-2718]
This commit is contained in:
commit
ab3aeac26b
30 changed files with 917 additions and 85 deletions
3
Gemfile
3
Gemfile
|
@ -15,6 +15,9 @@ gem 'bootstrap_form'
|
||||||
gem 'yomu'
|
gem 'yomu'
|
||||||
gem 'recaptcha', require: 'recaptcha/rails'
|
gem 'recaptcha', require: 'recaptcha/rails'
|
||||||
gem 'sanitize', '~> 4.4'
|
gem 'sanitize', '~> 4.4'
|
||||||
|
|
||||||
|
# Gems for OAuth2 subsystem
|
||||||
|
gem 'doorkeeper', '~> 4.4'
|
||||||
gem 'omniauth'
|
gem 'omniauth'
|
||||||
gem 'omniauth-linkedin-oauth2'
|
gem 'omniauth-linkedin-oauth2'
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,8 @@ GEM
|
||||||
discard (1.0.0)
|
discard (1.0.0)
|
||||||
activerecord (>= 4.2, < 6)
|
activerecord (>= 4.2, < 6)
|
||||||
docile (1.1.5)
|
docile (1.1.5)
|
||||||
|
doorkeeper (4.4.1)
|
||||||
|
railties (>= 4.2)
|
||||||
erubi (1.7.1)
|
erubi (1.7.1)
|
||||||
execjs (2.7.0)
|
execjs (2.7.0)
|
||||||
factory_bot (4.8.2)
|
factory_bot (4.8.2)
|
||||||
|
@ -563,6 +565,7 @@ DEPENDENCIES
|
||||||
devise_invitable
|
devise_invitable
|
||||||
devise_security_extension!
|
devise_security_extension!
|
||||||
discard (~> 1.0)
|
discard (~> 1.0)
|
||||||
|
doorkeeper (~> 4.4)
|
||||||
factory_bot_rails
|
factory_bot_rails
|
||||||
faker
|
faker
|
||||||
figaro
|
figaro
|
||||||
|
|
|
@ -6,9 +6,7 @@ module Api
|
||||||
attr_reader :token
|
attr_reader :token
|
||||||
attr_reader :current_user
|
attr_reader :current_user
|
||||||
|
|
||||||
before_action :load_token, except: %i(authenticate status health)
|
before_action :authenticate_request!, except: %i(status health)
|
||||||
before_action :load_iss, except: %i(authenticate status health)
|
|
||||||
before_action :authenticate_request!, except: %i(authenticate status health)
|
|
||||||
|
|
||||||
rescue_from StandardError do |e|
|
rescue_from StandardError do |e|
|
||||||
logger.error e.message
|
logger.error e.message
|
||||||
|
@ -49,30 +47,8 @@ module Api
|
||||||
render json: response, status: :ok
|
render json: response, status: :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
def authenticate
|
|
||||||
if auth_params[:grant_type] == 'password'
|
|
||||||
user = User.find_by_email(auth_params[:email])
|
|
||||||
unless user&.valid_password?(auth_params[:password])
|
|
||||||
raise StandardError, 'Default: Wrong user password'
|
|
||||||
end
|
|
||||||
payload = { user_id: user.id }
|
|
||||||
token = CoreJwt.encode(payload)
|
|
||||||
render json: { token_type: 'bearer', access_token: token }
|
|
||||||
else
|
|
||||||
raise StandardError, 'Default: Wrong grant type in request'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def load_token
|
|
||||||
if request.headers['Authorization']
|
|
||||||
@token =
|
|
||||||
request.headers['Authorization'].scan(/Bearer (.*)$/).flatten.last
|
|
||||||
end
|
|
||||||
raise StandardError, 'Common: No token in the header' unless @token
|
|
||||||
end
|
|
||||||
|
|
||||||
def azure_jwt_auth
|
def azure_jwt_auth
|
||||||
return unless iss =~ %r{windows.net/|microsoftonline.com/}
|
return unless iss =~ %r{windows.net/|microsoftonline.com/}
|
||||||
token_payload, = Api::AzureJwt.decode(token)
|
token_payload, = Api::AzureJwt.decode(token)
|
||||||
|
@ -83,6 +59,12 @@ module Api
|
||||||
end
|
end
|
||||||
|
|
||||||
def authenticate_request!
|
def authenticate_request!
|
||||||
|
@token = request.headers['Authorization']&.sub('Bearer ', '')
|
||||||
|
raise StandardError, 'Common: No token in the header' unless @token
|
||||||
|
|
||||||
|
@iss = CoreJwt.read_iss(token)
|
||||||
|
raise JWT::InvalidPayload, 'Common: Missing ISS in the token' unless @iss
|
||||||
|
|
||||||
Extends::API_PLUGABLE_AUTH_METHODS.each do |auth_method|
|
Extends::API_PLUGABLE_AUTH_METHODS.each do |auth_method|
|
||||||
method(auth_method).call
|
method(auth_method).call
|
||||||
return true if current_user
|
return true if current_user
|
||||||
|
@ -107,11 +89,6 @@ module Api
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_iss
|
|
||||||
@iss = CoreJwt.read_iss(token)
|
|
||||||
raise JWT::InvalidPayload, 'Common: Missing ISS in the token' unless @iss
|
|
||||||
end
|
|
||||||
|
|
||||||
def auth_params
|
def auth_params
|
||||||
params.permit(:grant_type, :email, :password)
|
params.permit(:grant_type, :email, :password)
|
||||||
end
|
end
|
||||||
|
|
59
app/controllers/api/v1/activities_controller.rb
Normal file
59
app/controllers/api/v1/activities_controller.rb
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class ActivitiesController < BaseController
|
||||||
|
before_action :load_team
|
||||||
|
before_action :load_project
|
||||||
|
before_action :load_experiment
|
||||||
|
before_action :load_task
|
||||||
|
before_action :load_activity, only: :show
|
||||||
|
|
||||||
|
def index
|
||||||
|
activities = @my_module.activities
|
||||||
|
.page(params.dig(:page, :number))
|
||||||
|
.per(params.dig(:page, :size))
|
||||||
|
|
||||||
|
render jsonapi: activities,
|
||||||
|
each_serializer: ActivitySerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render jsonapi: @activity, serializer: ActivitySerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_team
|
||||||
|
@team = Team.find(params.require(:team_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_team?(@team)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_project
|
||||||
|
@project = @team.projects.find(params.require(:project_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_project?(
|
||||||
|
@project
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_experiment
|
||||||
|
@experiment = @project.experiments.find(params.require(:experiment_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_experiment?(
|
||||||
|
@experiment
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_task
|
||||||
|
@my_module = @experiment.my_modules.find(params.require(:task_id))
|
||||||
|
render jsonapi: {}, status: :not_found if @my_module.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_activity
|
||||||
|
@activity = @my_module.activities.find(
|
||||||
|
params.require(:id)
|
||||||
|
)
|
||||||
|
render jsonapi: {}, status: :not_found if @activity.nil?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,7 +5,7 @@ module Api
|
||||||
class InventoriesController < BaseController
|
class InventoriesController < BaseController
|
||||||
before_action :load_team
|
before_action :load_team
|
||||||
before_action :load_inventory, only: %i(show update destroy)
|
before_action :load_inventory, only: %i(show update destroy)
|
||||||
before_action :check_manage_permissions, only: %i(create update destroy)
|
before_action :check_manage_permissions, only: %i(update destroy)
|
||||||
|
|
||||||
def index
|
def index
|
||||||
inventories = @team.repositories
|
inventories = @team.repositories
|
||||||
|
@ -15,7 +15,12 @@ module Api
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
inventory = @team.repositories.create!(inventory_params)
|
unless can_create_repositories?(@team)
|
||||||
|
return render body: nil, status: :forbidden
|
||||||
|
end
|
||||||
|
inventory = @team.repositories.create!(
|
||||||
|
inventory_params.merge(created_by: current_user)
|
||||||
|
)
|
||||||
render jsonapi: inventory,
|
render jsonapi: inventory,
|
||||||
serializer: InventorySerializer,
|
serializer: InventorySerializer,
|
||||||
status: :created
|
status: :created
|
||||||
|
|
|
@ -7,7 +7,7 @@ module Api
|
||||||
before_action :load_inventory
|
before_action :load_inventory
|
||||||
before_action :load_inventory_column, only: %i(show update destroy)
|
before_action :load_inventory_column, only: %i(show update destroy)
|
||||||
before_action :check_manage_permissions, only: %i(update destroy)
|
before_action :check_manage_permissions, only: %i(update destroy)
|
||||||
|
before_action :check_create_permissions, only: %i(create)
|
||||||
def index
|
def index
|
||||||
columns = @inventory.repository_columns
|
columns = @inventory.repository_columns
|
||||||
.includes(:repository_list_items)
|
.includes(:repository_list_items)
|
||||||
|
@ -66,6 +66,12 @@ module Api
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def check_create_permissions
|
||||||
|
unless can_manage_repository?(@inventory)
|
||||||
|
render body: nil, status: :forbidden
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def inventory_column_params
|
def inventory_column_params
|
||||||
unless params.require(:data).require(:type) == 'inventory_columns'
|
unless params.require(:data).require(:type) == 'inventory_columns'
|
||||||
raise ActionController::BadRequest,
|
raise ActionController::BadRequest,
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class MyModuleRepositoryRowsController < BaseController
|
||||||
|
before_action :load_team
|
||||||
|
before_action :load_project
|
||||||
|
before_action :load_experiment
|
||||||
|
before_action :load_task
|
||||||
|
before_action :load_task_repository_row, only: :show
|
||||||
|
|
||||||
|
def index
|
||||||
|
repo_rows = @my_module.my_module_repository_rows
|
||||||
|
.page(params.dig(:page, :number))
|
||||||
|
.per(params.dig(:page, :size))
|
||||||
|
|
||||||
|
render jsonapi: repo_rows,
|
||||||
|
each_serializer: MyModuleRepositoryRowSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render jsonapi: @repo_row, serializer: MyModuleRepositoryRowSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_team
|
||||||
|
@team = Team.find(params.require(:team_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_team?(@team)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_project
|
||||||
|
@project = @team.projects.find(params.require(:project_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_project?(
|
||||||
|
@project
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_experiment
|
||||||
|
@experiment = @project.experiments.find(params.require(:experiment_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_experiment?(
|
||||||
|
@experiment
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_task
|
||||||
|
@my_module = @experiment.my_modules.find(params.require(:task_id))
|
||||||
|
render jsonapi: {}, status: :not_found if @my_module.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_task_repository_row
|
||||||
|
@repo_row = @my_module.my_module_repository_rows.find(
|
||||||
|
params.require(:id)
|
||||||
|
)
|
||||||
|
render jsonapi: {}, status: :not_found if @repo_row.nil?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
59
app/controllers/api/v1/my_module_tags_controller.rb
Normal file
59
app/controllers/api/v1/my_module_tags_controller.rb
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class MyModuleTagsController < BaseController
|
||||||
|
before_action :load_team
|
||||||
|
before_action :load_project
|
||||||
|
before_action :load_experiment
|
||||||
|
before_action :load_task
|
||||||
|
before_action :load_task_tag, only: :show
|
||||||
|
|
||||||
|
def index
|
||||||
|
task_tags = @my_module.my_module_tags
|
||||||
|
.page(params.dig(:page, :number))
|
||||||
|
.per(params.dig(:page, :size))
|
||||||
|
|
||||||
|
render jsonapi: task_tags,
|
||||||
|
each_serializer: MyModuleTagSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render jsonapi: @task_tag, serializer: MyModuleTagSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_team
|
||||||
|
@team = Team.find(params.require(:team_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_team?(@team)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_project
|
||||||
|
@project = @team.projects.find(params.require(:project_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_project?(
|
||||||
|
@project
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_experiment
|
||||||
|
@experiment = @project.experiments.find(params.require(:experiment_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_experiment?(
|
||||||
|
@experiment
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_task
|
||||||
|
@my_module = @experiment.my_modules.find(params.require(:task_id))
|
||||||
|
render jsonapi: {}, status: :not_found if @my_module.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_task_tag
|
||||||
|
@task_tag = @my_module.my_module_tags.find(
|
||||||
|
params.require(:id)
|
||||||
|
)
|
||||||
|
render jsonapi: {}, status: :not_found if @task_tag.nil?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -7,6 +7,7 @@ module Api
|
||||||
before_action :load_project
|
before_action :load_project
|
||||||
before_action :load_experiment
|
before_action :load_experiment
|
||||||
before_action :load_task, only: :show
|
before_action :load_task, only: :show
|
||||||
|
before_action :load_task_relative, only: %i(outputs output inputs input)
|
||||||
|
|
||||||
def index
|
def index
|
||||||
tasks = @experiment.my_modules
|
tasks = @experiment.my_modules
|
||||||
|
@ -20,6 +21,30 @@ module Api
|
||||||
render jsonapi: @my_module, serializer: MyModuleSerializer
|
render jsonapi: @my_module, serializer: MyModuleSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def outputs
|
||||||
|
outputs = @my_module.my_modules
|
||||||
|
.page(params.dig(:page, :number))
|
||||||
|
.per(params.dig(:page, :size))
|
||||||
|
render jsonapi: outputs, each_serializer: MyModuleSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def output
|
||||||
|
output = @my_module.my_modules.find(params.require(:id))
|
||||||
|
render jsonapi: output, serializer: MyModuleSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def inputs
|
||||||
|
inputs = @my_module.my_module_antecessors
|
||||||
|
.page(params.dig(:page, :number))
|
||||||
|
.per(params.dig(:page, :size))
|
||||||
|
render jsonapi: inputs, each_serializer: MyModuleSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def input
|
||||||
|
input = @my_module.my_module_antecessors.find(params.require(:id))
|
||||||
|
render jsonapi: input, serializer: MyModuleSerializer
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def load_team
|
def load_team
|
||||||
|
@ -43,7 +68,14 @@ module Api
|
||||||
|
|
||||||
def load_task
|
def load_task
|
||||||
@my_module = @experiment.my_modules.find(params.require(:id))
|
@my_module = @experiment.my_modules.find(params.require(:id))
|
||||||
render jsonapi: {}, status: :not_found if @my_module.nil?
|
end
|
||||||
|
|
||||||
|
# Made the method below because its more elegant than changing parameters
|
||||||
|
# in routes file, and here. It exists because when we call input or output
|
||||||
|
# for a task, the "id" that used to be task id is now an id for the output
|
||||||
|
# or input.
|
||||||
|
def load_task_relative
|
||||||
|
@my_module = @experiment.my_modules.find(params.require(:task_id))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
57
app/controllers/api/v1/protocols_controller.rb
Normal file
57
app/controllers/api/v1/protocols_controller.rb
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class ProtocolsController < BaseController
|
||||||
|
before_action :load_team
|
||||||
|
before_action :load_project
|
||||||
|
before_action :load_experiment
|
||||||
|
before_action :load_task
|
||||||
|
before_action :load_protocol, only: :show
|
||||||
|
|
||||||
|
def index
|
||||||
|
protocols = @my_module.protocols
|
||||||
|
.page(params.dig(:page, :number))
|
||||||
|
.per(params.dig(:page, :size))
|
||||||
|
|
||||||
|
render jsonapi: protocols,
|
||||||
|
each_serializer: ProtocolSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render jsonapi: @protocol, serializer: ProtocolSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_team
|
||||||
|
@team = Team.find(params.require(:team_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_team?(@team)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_project
|
||||||
|
@project = @team.projects.find(params.require(:project_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_project?(
|
||||||
|
@project
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_experiment
|
||||||
|
@experiment = @project.experiments.find(params.require(:experiment_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_experiment?(
|
||||||
|
@experiment
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_task
|
||||||
|
@my_module = @experiment.my_modules.find(params.require(:task_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_protocol
|
||||||
|
@protocol = @my_module.protocols.find(
|
||||||
|
params.require(:id)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
57
app/controllers/api/v1/user_my_modules_controller.rb
Normal file
57
app/controllers/api/v1/user_my_modules_controller.rb
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class UserMyModulesController < BaseController
|
||||||
|
before_action :load_team
|
||||||
|
before_action :load_project
|
||||||
|
before_action :load_experiment
|
||||||
|
before_action :load_task
|
||||||
|
before_action :load_user_task, only: :show
|
||||||
|
|
||||||
|
def index
|
||||||
|
user_tasks = @my_module.user_my_modules
|
||||||
|
.page(params.dig(:page, :number))
|
||||||
|
.per(params.dig(:page, :size))
|
||||||
|
|
||||||
|
render jsonapi: user_tasks,
|
||||||
|
each_serializer: UserMyModuleSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
render jsonapi: @user_task, serializer: UserMyModuleSerializer
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def load_team
|
||||||
|
@team = Team.find(params.require(:team_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_team?(@team)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_project
|
||||||
|
@project = @team.projects.find(params.require(:project_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_project?(
|
||||||
|
@project
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_experiment
|
||||||
|
@experiment = @project.experiments.find(params.require(:experiment_id))
|
||||||
|
render jsonapi: {}, status: :forbidden unless can_read_experiment?(
|
||||||
|
@experiment
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_task
|
||||||
|
@my_module = @experiment.my_modules.find(params.require(:task_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
def load_user_task
|
||||||
|
@user_task = @my_module.user_my_modules.find(
|
||||||
|
params.require(:id)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -198,6 +198,13 @@ class User < ApplicationRecord
|
||||||
has_many :zip_exports, inverse_of: :user, dependent: :destroy
|
has_many :zip_exports, inverse_of: :user, dependent: :destroy
|
||||||
has_many :datatables_teams, class_name: '::Views::Datatables::DatatablesTeam'
|
has_many :datatables_teams, class_name: '::Views::Datatables::DatatablesTeam'
|
||||||
|
|
||||||
|
has_many :access_grants, class_name: 'Doorkeeper::AccessGrant',
|
||||||
|
foreign_key: :resource_owner_id,
|
||||||
|
dependent: :delete_all
|
||||||
|
has_many :access_tokens, class_name: 'Doorkeeper::AccessToken',
|
||||||
|
foreign_key: :resource_owner_id,
|
||||||
|
dependent: :delete_all
|
||||||
|
|
||||||
# If other errors besides parameter "avatar" exist,
|
# If other errors besides parameter "avatar" exist,
|
||||||
# they will propagate to "avatar" also, so remove them
|
# they will propagate to "avatar" also, so remove them
|
||||||
# and put all other (more specific ones) in it
|
# and put all other (more specific ones) in it
|
||||||
|
|
12
app/serializers/api/v1/activity_serializer.rb
Normal file
12
app/serializers/api/v1/activity_serializer.rb
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class ActivitySerializer < ActiveModel::Serializer
|
||||||
|
type :activities
|
||||||
|
attributes :id, :my_module_id, :user_id, :type_of, :message,
|
||||||
|
:project_id, :experiment_id
|
||||||
|
belongs_to :my_module, serializer: MyModuleSerializer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,12 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class MyModuleRepositoryRowSerializer < ActiveModel::Serializer
|
||||||
|
type :task_inventory_rows
|
||||||
|
attribute :repository_row_id, key: :inventory_row_id
|
||||||
|
attribute :my_module_id, key: :task_id
|
||||||
|
belongs_to :my_module, serializer: MyModuleSerializer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
13
app/serializers/api/v1/my_module_tag_serializer.rb
Normal file
13
app/serializers/api/v1/my_module_tag_serializer.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class MyModuleTagSerializer < ActiveModel::Serializer
|
||||||
|
type :task_tags
|
||||||
|
attributes :id, :tag_id
|
||||||
|
attribute :my_module_id, key: :task_id
|
||||||
|
|
||||||
|
belongs_to :my_module, serializer: MyModuleSerializer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
15
app/serializers/api/v1/protocol_serializer.rb
Normal file
15
app/serializers/api/v1/protocol_serializer.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class ProtocolSerializer < ActiveModel::Serializer
|
||||||
|
type :protocols
|
||||||
|
attributes :id, :name, :authors, :description,
|
||||||
|
:team_id, :protocol_type,
|
||||||
|
:nr_of_linked_children
|
||||||
|
attribute :my_module_id, key: :task_id
|
||||||
|
|
||||||
|
belongs_to :my_module, serializer: MyModuleSerializer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -4,7 +4,10 @@ module Api
|
||||||
module V1
|
module V1
|
||||||
class ResultSerializer < ActiveModel::Serializer
|
class ResultSerializer < ActiveModel::Serializer
|
||||||
type :results
|
type :results
|
||||||
attributes :name, :archived
|
attributes :name, :user_id, :archived
|
||||||
|
attribute :my_module_id, key: :task_id
|
||||||
|
|
||||||
|
belongs_to :my_module, serializer: MyModuleSerializer
|
||||||
has_one :result_asset, key: :asset,
|
has_one :result_asset, key: :asset,
|
||||||
serializer: ResultAssetSerializer,
|
serializer: ResultAssetSerializer,
|
||||||
class_name: 'ResultAsset',
|
class_name: 'ResultAsset',
|
||||||
|
|
13
app/serializers/api/v1/user_my_module_serializer.rb
Normal file
13
app/serializers/api/v1/user_my_module_serializer.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class UserMyModuleSerializer < ActiveModel::Serializer
|
||||||
|
type :user_tasks
|
||||||
|
attributes :id, :user_id
|
||||||
|
attribute :my_module_id, key: :task_id
|
||||||
|
|
||||||
|
belongs_to :my_module, serializer: MyModuleSerializer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -30,5 +30,13 @@ module Api
|
||||||
return true if time_left < (Api.configuration.core_api_token_ttl.to_i / 2)
|
return true if time_left < (Api.configuration.core_api_token_ttl.to_i / 2)
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Method used by Doorkeeper for custom tokens
|
||||||
|
def self.generate(options = {})
|
||||||
|
encode(
|
||||||
|
{ user_id: options[:resource_owner_id] },
|
||||||
|
options[:expires_in].seconds.from_now.to_i
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
9
app/views/doorkeeper/authorizations/error.html.erb
Normal file
9
app/views/doorkeeper/authorizations/error.html.erb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<div class="center-block center-block-narrow">
|
||||||
|
<div class="page-header">
|
||||||
|
<h1><%= t('doorkeeper.authorizations.error.title') %></h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<main role="main">
|
||||||
|
<%= @pre_auth.error_response.body[:error_description] %>
|
||||||
|
</main>
|
||||||
|
</div>
|
42
app/views/doorkeeper/authorizations/new.html.erb
Normal file
42
app/views/doorkeeper/authorizations/new.html.erb
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<div class="center-block center-block-narrow">
|
||||||
|
<header class="page-header" role="banner">
|
||||||
|
<h1><%= t('.title') %></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main role="main">
|
||||||
|
<p class="h4">
|
||||||
|
<%= raw t('.prompt', client_name: content_tag(:strong, class: 'text-info') { @pre_auth.client.name }) %>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<% if @pre_auth.scopes.count > 0 %>
|
||||||
|
<div id="oauth-permissions">
|
||||||
|
<p><%= t('.able_to') %>:</p>
|
||||||
|
|
||||||
|
<ul class="text-info">
|
||||||
|
<% @pre_auth.scopes.each do |scope| %>
|
||||||
|
<li><%= t scope, scope: [:doorkeeper, :scopes] %></li>
|
||||||
|
<% end %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<%= form_tag oauth_authorization_path, method: :post do %>
|
||||||
|
<%= hidden_field_tag :client_id, @pre_auth.client.uid %>
|
||||||
|
<%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri %>
|
||||||
|
<%= hidden_field_tag :state, @pre_auth.state %>
|
||||||
|
<%= hidden_field_tag :response_type, @pre_auth.response_type %>
|
||||||
|
<%= hidden_field_tag :scope, @pre_auth.scope %>
|
||||||
|
<%= submit_tag t('doorkeeper.authorizations.buttons.authorize'), class: "btn btn-success btn-lg btn-block" %>
|
||||||
|
<% end %>
|
||||||
|
<%= form_tag oauth_authorization_path, method: :delete do %>
|
||||||
|
<%= hidden_field_tag :client_id, @pre_auth.client.uid %>
|
||||||
|
<%= hidden_field_tag :redirect_uri, @pre_auth.redirect_uri %>
|
||||||
|
<%= hidden_field_tag :state, @pre_auth.state %>
|
||||||
|
<%= hidden_field_tag :response_type, @pre_auth.response_type %>
|
||||||
|
<%= hidden_field_tag :scope, @pre_auth.scope %>
|
||||||
|
<%= submit_tag t('doorkeeper.authorizations.buttons.deny'), class: "btn btn-danger btn-lg btn-block" %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
9
app/views/doorkeeper/authorizations/show.html.erb
Normal file
9
app/views/doorkeeper/authorizations/show.html.erb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<div class="center-block center-block-narrow">
|
||||||
|
<header class="page-header">
|
||||||
|
<h1><%= t('.title') %>:</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main role="main">
|
||||||
|
<code id="authorization_code"><%= params[:code] %></code>
|
||||||
|
</main>
|
||||||
|
</div>
|
|
@ -42,5 +42,11 @@ module Scinote
|
||||||
|
|
||||||
# SciNote Core Application version
|
# SciNote Core Application version
|
||||||
VERSION = File.read(Rails.root.join('VERSION')).strip.freeze
|
VERSION = File.read(Rails.root.join('VERSION')).strip.freeze
|
||||||
|
|
||||||
|
# Doorkeeper overrides
|
||||||
|
config.to_prepare do
|
||||||
|
# Only Authorization endpoint
|
||||||
|
Doorkeeper::AuthorizationsController.layout 'sign_in_halt'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ Api.configure do |config|
|
||||||
config.core_api_sign_alg = ENV['CORE_API_SIGN_ALG']
|
config.core_api_sign_alg = ENV['CORE_API_SIGN_ALG']
|
||||||
end
|
end
|
||||||
if ENV['CORE_API_TOKEN_TTL']
|
if ENV['CORE_API_TOKEN_TTL']
|
||||||
config.core_api_token_ttl = ENV['CORE_API_TOKEN_TTL']
|
config.core_api_token_ttl = ENV['CORE_API_TOKEN_TTL'].to_i.seconds
|
||||||
end
|
end
|
||||||
if ENV['CORE_API_TOKEN_ISS']
|
if ENV['CORE_API_TOKEN_ISS']
|
||||||
config.core_api_token_iss = ENV['CORE_API_TOKEN_ISS']
|
config.core_api_token_iss = ENV['CORE_API_TOKEN_ISS']
|
||||||
|
|
136
config/initializers/doorkeeper.rb
Normal file
136
config/initializers/doorkeeper.rb
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
Doorkeeper.configure do
|
||||||
|
# Change the ORM that doorkeeper will use (needs plugins)
|
||||||
|
orm :active_record
|
||||||
|
|
||||||
|
# This block will be called to check whether the resource owner is authenticated or not.
|
||||||
|
resource_owner_authenticator do
|
||||||
|
current_user || warden.authenticate!(scope: :user)
|
||||||
|
end
|
||||||
|
|
||||||
|
# If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
|
||||||
|
# admin_authenticator do
|
||||||
|
# # Put your admin authentication logic here.
|
||||||
|
# # Example implementation:
|
||||||
|
# Admin.find_by_id(session[:admin_id]) || redirect_to(new_admin_session_url)
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Authorization Code expiration time (default 10 minutes).
|
||||||
|
authorization_code_expires_in 10.minutes
|
||||||
|
|
||||||
|
# Access token expiration time (default 2 hours).
|
||||||
|
# If you want to disable expiration, set this to nil.
|
||||||
|
access_token_expires_in 2.hours
|
||||||
|
|
||||||
|
# Assign a custom TTL for implicit grants.
|
||||||
|
# custom_access_token_expires_in do |oauth_client|
|
||||||
|
# oauth_client.application.additional_settings.implicit_oauth_expiration
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Use a custom class for generating the access token.
|
||||||
|
# https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
|
||||||
|
access_token_generator 'Api::CoreJwt'
|
||||||
|
|
||||||
|
# The controller Doorkeeper::ApplicationController inherits from.
|
||||||
|
# Defaults to ActionController::Base.
|
||||||
|
# https://github.com/doorkeeper-gem/doorkeeper#custom-base-controller
|
||||||
|
# base_controller 'DoorkeeperCustomController'
|
||||||
|
|
||||||
|
# Reuse access token for the same resource owner within an application (disabled by default)
|
||||||
|
# Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383
|
||||||
|
# reuse_access_token
|
||||||
|
|
||||||
|
# Issue access tokens with refresh token (disabled by default)
|
||||||
|
use_refresh_token
|
||||||
|
|
||||||
|
# Provide support for an owner to be assigned to each registered application (disabled by default)
|
||||||
|
# Optional parameter confirmation: true (default false) if you want to enforce ownership of
|
||||||
|
# a registered application
|
||||||
|
# Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support
|
||||||
|
# enable_application_owner confirmation: false
|
||||||
|
|
||||||
|
# Define access token scopes for your provider
|
||||||
|
# For more information go to
|
||||||
|
# https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes
|
||||||
|
# default_scopes :public
|
||||||
|
# optional_scopes :write, :update
|
||||||
|
|
||||||
|
# Change the way client credentials are retrieved from the request object.
|
||||||
|
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
|
||||||
|
# falls back to the `:client_id` and `:client_secret` params from the `params` object.
|
||||||
|
# Check out https://github.com/doorkeeper-gem/doorkeeper/wiki/Changing-how-clients-are-authenticated
|
||||||
|
# for more information on customization
|
||||||
|
# client_credentials :from_basic, :from_params
|
||||||
|
|
||||||
|
# Change the way access token is authenticated from the request object.
|
||||||
|
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
|
||||||
|
# falls back to the `:access_token` or `:bearer_token` params from the `params` object.
|
||||||
|
# Check out https://github.com/doorkeeper-gem/doorkeeper/wiki/Changing-how-clients-are-authenticated
|
||||||
|
# for more information on customization
|
||||||
|
# access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param
|
||||||
|
|
||||||
|
# Change the native redirect uri for client apps
|
||||||
|
# When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider
|
||||||
|
# The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL
|
||||||
|
# (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
|
||||||
|
#
|
||||||
|
# native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
|
||||||
|
|
||||||
|
# Forces the usage of the HTTPS protocol in non-native redirect uris (enabled
|
||||||
|
# by default in non-development environments). OAuth2 delegates security in
|
||||||
|
# communication to the HTTPS protocol so it is wise to keep this enabled.
|
||||||
|
#
|
||||||
|
# Callable objects such as proc, lambda, block or any object that responds to
|
||||||
|
# #call can be used in order to allow conditional checks (to allow non-SSL
|
||||||
|
# redirects to localhost for example).
|
||||||
|
#
|
||||||
|
# force_ssl_in_redirect_uri !Rails.env.development?
|
||||||
|
#
|
||||||
|
# force_ssl_in_redirect_uri { |uri| uri.host != 'localhost' }
|
||||||
|
|
||||||
|
# Specify what redirect URI's you want to block during creation. Any redirect
|
||||||
|
# URI is whitelisted by default.
|
||||||
|
#
|
||||||
|
# You can use this option in order to forbid URI's with 'javascript' scheme
|
||||||
|
# for example.
|
||||||
|
#
|
||||||
|
# forbid_redirect_uri { |uri| uri.scheme.to_s.downcase == 'javascript' }
|
||||||
|
|
||||||
|
# Specify what grant flows are enabled in array of Strings. The valid
|
||||||
|
# strings and the flows they enable are:
|
||||||
|
#
|
||||||
|
# "authorization_code" => Authorization Code Grant Flow
|
||||||
|
# "implicit" => Implicit Grant Flow
|
||||||
|
# "password" => Resource Owner Password Credentials Grant Flow
|
||||||
|
# "client_credentials" => Client Credentials Grant Flow
|
||||||
|
#
|
||||||
|
# If not specified, Doorkeeper enables authorization_code and
|
||||||
|
# client_credentials.
|
||||||
|
#
|
||||||
|
# implicit and password grant flows have risks that you should understand
|
||||||
|
# before enabling:
|
||||||
|
# http://tools.ietf.org/html/rfc6819#section-4.4.2
|
||||||
|
# http://tools.ietf.org/html/rfc6819#section-4.4.3
|
||||||
|
#
|
||||||
|
grant_flows %w(authorization_code)
|
||||||
|
|
||||||
|
# Hook into the strategies' request & response life-cycle in case your
|
||||||
|
# application needs advanced customization or logging:
|
||||||
|
#
|
||||||
|
# before_successful_strategy_response do |request|
|
||||||
|
# puts "BEFORE HOOK FIRED! #{request}"
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# after_successful_strategy_response do |request, response|
|
||||||
|
# puts "AFTER HOOK FIRED! #{request}, #{response}"
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Under some circumstances you might want to have applications auto-approved,
|
||||||
|
# so that the user skips the authorization step.
|
||||||
|
# For example if dealing with a trusted application.
|
||||||
|
# skip_authorization do |resource_owner, client|
|
||||||
|
# client.superapp? or resource_owner.admin?
|
||||||
|
# end
|
||||||
|
|
||||||
|
# WWW-Authenticate Realm (default "Doorkeeper").
|
||||||
|
# realm "Doorkeeper"
|
||||||
|
end
|
128
config/locales/doorkeeper.en.yml
Normal file
128
config/locales/doorkeeper.en.yml
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
en:
|
||||||
|
activerecord:
|
||||||
|
attributes:
|
||||||
|
doorkeeper/application:
|
||||||
|
name: 'Name'
|
||||||
|
redirect_uri: 'Redirect URI'
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
doorkeeper/application:
|
||||||
|
attributes:
|
||||||
|
redirect_uri:
|
||||||
|
fragment_present: 'cannot contain a fragment.'
|
||||||
|
invalid_uri: 'must be a valid URI.'
|
||||||
|
relative_uri: 'must be an absolute URI.'
|
||||||
|
secured_uri: 'must be an HTTPS/SSL URI.'
|
||||||
|
forbidden_uri: 'is forbidden by the server.'
|
||||||
|
|
||||||
|
doorkeeper:
|
||||||
|
applications:
|
||||||
|
confirmations:
|
||||||
|
destroy: 'Are you sure?'
|
||||||
|
buttons:
|
||||||
|
edit: 'Edit'
|
||||||
|
destroy: 'Destroy'
|
||||||
|
submit: 'Submit'
|
||||||
|
cancel: 'Cancel'
|
||||||
|
authorize: 'Authorize'
|
||||||
|
form:
|
||||||
|
error: 'Whoops! Check your form for possible errors'
|
||||||
|
help:
|
||||||
|
confidential: 'Application will be used where the client secret can be kept confidential. Native mobile apps and Single Page Apps are considered non-confidential.'
|
||||||
|
redirect_uri: 'Use one line per URI'
|
||||||
|
native_redirect_uri: 'Use %{native_redirect_uri} if you want to add localhost URIs for development purposes'
|
||||||
|
scopes: 'Separate scopes with spaces. Leave blank to use the default scopes.'
|
||||||
|
edit:
|
||||||
|
title: 'Edit application'
|
||||||
|
index:
|
||||||
|
title: 'Your applications'
|
||||||
|
new: 'New Application'
|
||||||
|
name: 'Name'
|
||||||
|
callback_url: 'Callback URL'
|
||||||
|
confidential: 'Confidential?'
|
||||||
|
confidentiality:
|
||||||
|
'yes': 'Yes'
|
||||||
|
'no': 'No'
|
||||||
|
new:
|
||||||
|
title: 'New Application'
|
||||||
|
show:
|
||||||
|
title: 'Application: %{name}'
|
||||||
|
application_id: 'Application Id'
|
||||||
|
secret: 'Secret'
|
||||||
|
scopes: 'Scopes'
|
||||||
|
confidential: 'Confidential'
|
||||||
|
callback_urls: 'Callback urls'
|
||||||
|
actions: 'Actions'
|
||||||
|
|
||||||
|
authorizations:
|
||||||
|
buttons:
|
||||||
|
authorize: 'Authorize'
|
||||||
|
deny: 'Deny'
|
||||||
|
error:
|
||||||
|
title: 'An error has occurred'
|
||||||
|
new:
|
||||||
|
title: 'Authorization required'
|
||||||
|
prompt: 'Authorize %{client_name} to use your account?'
|
||||||
|
able_to: 'This application will be able to'
|
||||||
|
show:
|
||||||
|
title: 'Authorization code'
|
||||||
|
|
||||||
|
authorized_applications:
|
||||||
|
confirmations:
|
||||||
|
revoke: 'Are you sure?'
|
||||||
|
buttons:
|
||||||
|
revoke: 'Revoke'
|
||||||
|
index:
|
||||||
|
title: 'Your authorized applications'
|
||||||
|
application: 'Application'
|
||||||
|
created_at: 'Created At'
|
||||||
|
date_format: '%Y-%m-%d %H:%M:%S'
|
||||||
|
|
||||||
|
errors:
|
||||||
|
messages:
|
||||||
|
# Common error messages
|
||||||
|
invalid_request: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
|
||||||
|
invalid_redirect_uri: "The requested redirect uri is malformed or doesn't match client redirect URI."
|
||||||
|
unauthorized_client: 'The client is not authorized to perform this request using this method.'
|
||||||
|
access_denied: 'The resource owner or authorization server denied the request.'
|
||||||
|
invalid_scope: 'The requested scope is invalid, unknown, or malformed.'
|
||||||
|
server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.'
|
||||||
|
temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.'
|
||||||
|
|
||||||
|
# Configuration error messages
|
||||||
|
credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.'
|
||||||
|
resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfigured.'
|
||||||
|
|
||||||
|
# Access grant errors
|
||||||
|
unsupported_response_type: 'The authorization server does not support this response type.'
|
||||||
|
|
||||||
|
# Access token errors
|
||||||
|
invalid_client: 'Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method.'
|
||||||
|
invalid_grant: 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.'
|
||||||
|
unsupported_grant_type: 'The authorization grant type is not supported by the authorization server.'
|
||||||
|
|
||||||
|
invalid_token:
|
||||||
|
revoked: "The access token was revoked"
|
||||||
|
expired: "The access token expired"
|
||||||
|
unknown: "The access token is invalid"
|
||||||
|
|
||||||
|
flash:
|
||||||
|
applications:
|
||||||
|
create:
|
||||||
|
notice: 'Application created.'
|
||||||
|
destroy:
|
||||||
|
notice: 'Application deleted.'
|
||||||
|
update:
|
||||||
|
notice: 'Application updated.'
|
||||||
|
authorized_applications:
|
||||||
|
destroy:
|
||||||
|
notice: 'Application revoked.'
|
||||||
|
|
||||||
|
layouts:
|
||||||
|
admin:
|
||||||
|
nav:
|
||||||
|
oauth2_provider: 'OAuth2 Provider'
|
||||||
|
applications: 'Applications'
|
||||||
|
home: 'Home'
|
||||||
|
application:
|
||||||
|
title: 'OAuth authorization required'
|
|
@ -1,4 +1,7 @@
|
||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
|
use_doorkeeper do
|
||||||
|
skip_controllers :applications, :authorized_applications, :token_info
|
||||||
|
end
|
||||||
require 'subdomain'
|
require 'subdomain'
|
||||||
|
|
||||||
def draw(routes_name)
|
def draw(routes_name)
|
||||||
|
@ -539,7 +542,6 @@ Rails.application.routes.draw do
|
||||||
namespace :api, defaults: { format: 'json' } do
|
namespace :api, defaults: { format: 'json' } do
|
||||||
get 'health', to: 'api#health'
|
get 'health', to: 'api#health'
|
||||||
get 'status', to: 'api#status'
|
get 'status', to: 'api#status'
|
||||||
post 'auth/token', to: 'api#authenticate'
|
|
||||||
if Api.configuration.core_api_v1_preview
|
if Api.configuration.core_api_v1_preview
|
||||||
namespace :v1 do
|
namespace :v1 do
|
||||||
resources :teams, only: %i(index show) do
|
resources :teams, only: %i(index show) do
|
||||||
|
@ -556,12 +558,6 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
resources :projects, only: %i(index show) do
|
resources :projects, only: %i(index show) do
|
||||||
resources :experiments, only: %i(index show) do
|
resources :experiments, only: %i(index show) do
|
||||||
resources :my_modules,
|
|
||||||
only: %i(index show),
|
|
||||||
path: 'tasks',
|
|
||||||
as: :tasks do
|
|
||||||
resources :results, only: %i(index create show)
|
|
||||||
end
|
|
||||||
resources :my_module_groups,
|
resources :my_module_groups,
|
||||||
only: %i(index show),
|
only: %i(index show),
|
||||||
path: 'task_groups',
|
path: 'task_groups',
|
||||||
|
@ -570,6 +566,37 @@ Rails.application.routes.draw do
|
||||||
only: %i(index show),
|
only: %i(index show),
|
||||||
path: 'connections',
|
path: 'connections',
|
||||||
as: :connections
|
as: :connections
|
||||||
|
resources :my_modules,
|
||||||
|
only: %i(index show),
|
||||||
|
path: 'tasks',
|
||||||
|
as: :tasks do
|
||||||
|
resources :my_module_repository_rows, only: %i(index show),
|
||||||
|
path: 'task_inventory_rows',
|
||||||
|
as: :task_inventory_rows
|
||||||
|
resources :user_my_modules, only: %i(index show),
|
||||||
|
path: 'user_tasks',
|
||||||
|
as: :user_tasks
|
||||||
|
resources :my_module_tags, only: %i(index show),
|
||||||
|
path: 'task_tags',
|
||||||
|
as: :task_tags
|
||||||
|
resources :protocols, only: %i(index show),
|
||||||
|
path: 'protocols',
|
||||||
|
as: :protocols
|
||||||
|
resources :results, only: %i(index create show),
|
||||||
|
path: 'results',
|
||||||
|
as: :results
|
||||||
|
get 'inputs',
|
||||||
|
to: 'my_modules#inputs'
|
||||||
|
get 'inputs/:id',
|
||||||
|
to: 'my_modules#input'
|
||||||
|
get 'outputs',
|
||||||
|
to: 'my_modules#outputs'
|
||||||
|
get 'outputs/:id',
|
||||||
|
to: 'my_modules#output'
|
||||||
|
resources :activities, only: %i(index show),
|
||||||
|
path: 'activities',
|
||||||
|
as: :activities
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
71
db/migrate/20180813120338_create_doorkeeper_tables.rb
Normal file
71
db/migrate/20180813120338_create_doorkeeper_tables.rb
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
class CreateDoorkeeperTables < ActiveRecord::Migration[5.1]
|
||||||
|
def change
|
||||||
|
create_table :oauth_applications do |t|
|
||||||
|
t.string :name, null: false
|
||||||
|
t.string :uid, null: false
|
||||||
|
t.string :secret, null: false
|
||||||
|
t.text :redirect_uri, null: false
|
||||||
|
t.string :scopes, null: false, default: ''
|
||||||
|
t.boolean :confidential, null: false, default: true
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :oauth_applications, :uid, unique: true
|
||||||
|
|
||||||
|
create_table :oauth_access_grants do |t|
|
||||||
|
t.integer :resource_owner_id, null: false
|
||||||
|
t.references :application, null: false
|
||||||
|
t.string :token, null: false
|
||||||
|
t.integer :expires_in, null: false
|
||||||
|
t.text :redirect_uri, null: false
|
||||||
|
t.datetime :created_at, null: false
|
||||||
|
t.datetime :revoked_at
|
||||||
|
t.string :scopes
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :oauth_access_grants, :token, unique: true
|
||||||
|
add_foreign_key :oauth_access_grants, :users, column: :resource_owner_id
|
||||||
|
add_foreign_key(
|
||||||
|
:oauth_access_grants,
|
||||||
|
:oauth_applications,
|
||||||
|
column: :application_id
|
||||||
|
)
|
||||||
|
|
||||||
|
create_table :oauth_access_tokens do |t|
|
||||||
|
t.integer :resource_owner_id
|
||||||
|
t.references :application
|
||||||
|
|
||||||
|
# If you use a custom token generator you may need to change this column
|
||||||
|
# from string to text, so that it accepts tokens larger than 255
|
||||||
|
# characters. More info on custom token generators in:
|
||||||
|
# https://github.com/doorkeeper-gem/doorkeeper/tree/v3.0.0.rc1#custom-access-token-generator
|
||||||
|
#
|
||||||
|
t.text :token, null: false
|
||||||
|
# t.string :token, null: false
|
||||||
|
|
||||||
|
t.string :refresh_token
|
||||||
|
t.integer :expires_in
|
||||||
|
t.datetime :revoked_at
|
||||||
|
t.datetime :created_at, null: false
|
||||||
|
t.string :scopes
|
||||||
|
|
||||||
|
# If there is a previous_refresh_token column,
|
||||||
|
# refresh tokens will be revoked after a related access token is used.
|
||||||
|
# If there is no previous_refresh_token column,
|
||||||
|
# previous tokens are revoked as soon as a new access token is created.
|
||||||
|
# Comment out this line if you'd rather have refresh tokens
|
||||||
|
# instantly revoked.
|
||||||
|
t.string :previous_refresh_token, null: false, default: ""
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :oauth_access_tokens, :token, unique: true
|
||||||
|
add_index :oauth_access_tokens, :resource_owner_id
|
||||||
|
add_index :oauth_access_tokens, :refresh_token, unique: true
|
||||||
|
add_foreign_key :oauth_access_tokens, :users, column: :resource_owner_id
|
||||||
|
add_foreign_key(
|
||||||
|
:oauth_access_tokens,
|
||||||
|
:oauth_applications,
|
||||||
|
column: :application_id
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
47
db/schema.rb
47
db/schema.rb
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20180806115201) do
|
ActiveRecord::Schema.define(version: 20180813120338) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -240,6 +240,47 @@ ActiveRecord::Schema.define(version: 20180806115201) do
|
||||||
t.index ["created_at"], name: "index_notifications_on_created_at"
|
t.index ["created_at"], name: "index_notifications_on_created_at"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "oauth_access_grants", force: :cascade do |t|
|
||||||
|
t.integer "resource_owner_id", null: false
|
||||||
|
t.bigint "application_id", null: false
|
||||||
|
t.string "token", null: false
|
||||||
|
t.integer "expires_in", null: false
|
||||||
|
t.text "redirect_uri", null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "revoked_at"
|
||||||
|
t.string "scopes"
|
||||||
|
t.index ["application_id"], name: "index_oauth_access_grants_on_application_id"
|
||||||
|
t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "oauth_access_tokens", force: :cascade do |t|
|
||||||
|
t.integer "resource_owner_id"
|
||||||
|
t.bigint "application_id"
|
||||||
|
t.text "token", null: false
|
||||||
|
t.string "refresh_token"
|
||||||
|
t.integer "expires_in"
|
||||||
|
t.datetime "revoked_at"
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.string "scopes"
|
||||||
|
t.string "previous_refresh_token", default: "", null: false
|
||||||
|
t.index ["application_id"], name: "index_oauth_access_tokens_on_application_id"
|
||||||
|
t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true
|
||||||
|
t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id"
|
||||||
|
t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table "oauth_applications", force: :cascade do |t|
|
||||||
|
t.string "name", null: false
|
||||||
|
t.string "uid", null: false
|
||||||
|
t.string "secret", null: false
|
||||||
|
t.text "redirect_uri", null: false
|
||||||
|
t.string "scopes", default: "", null: false
|
||||||
|
t.boolean "confidential", default: true, null: false
|
||||||
|
t.datetime "created_at", null: false
|
||||||
|
t.datetime "updated_at", null: false
|
||||||
|
t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true
|
||||||
|
end
|
||||||
|
|
||||||
create_table "projects", id: :serial, force: :cascade do |t|
|
create_table "projects", id: :serial, force: :cascade do |t|
|
||||||
t.string "name", null: false
|
t.string "name", null: false
|
||||||
t.integer "visibility", default: 0, null: false
|
t.integer "visibility", default: 0, null: false
|
||||||
|
@ -864,6 +905,10 @@ ActiveRecord::Schema.define(version: 20180806115201) do
|
||||||
add_foreign_key "my_modules", "users", column: "last_modified_by_id"
|
add_foreign_key "my_modules", "users", column: "last_modified_by_id"
|
||||||
add_foreign_key "my_modules", "users", column: "restored_by_id"
|
add_foreign_key "my_modules", "users", column: "restored_by_id"
|
||||||
add_foreign_key "notifications", "users", column: "generator_user_id"
|
add_foreign_key "notifications", "users", column: "generator_user_id"
|
||||||
|
add_foreign_key "oauth_access_grants", "oauth_applications", column: "application_id"
|
||||||
|
add_foreign_key "oauth_access_grants", "users", column: "resource_owner_id"
|
||||||
|
add_foreign_key "oauth_access_tokens", "oauth_applications", column: "application_id"
|
||||||
|
add_foreign_key "oauth_access_tokens", "users", column: "resource_owner_id"
|
||||||
add_foreign_key "projects", "teams"
|
add_foreign_key "projects", "teams"
|
||||||
add_foreign_key "projects", "users", column: "archived_by_id"
|
add_foreign_key "projects", "users", column: "archived_by_id"
|
||||||
add_foreign_key "projects", "users", column: "created_by_id"
|
add_foreign_key "projects", "users", column: "created_by_id"
|
||||||
|
|
|
@ -21,45 +21,4 @@ describe Api::ApiController, type: :controller do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'Post #authenticate' do
|
|
||||||
let(:user) { create(:user) }
|
|
||||||
|
|
||||||
context 'When valid request' do
|
|
||||||
before do
|
|
||||||
post :authenticate, params: { email: user.email,
|
|
||||||
password: user.password,
|
|
||||||
grant_type: 'password' }
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'Returns HTTP success' do
|
|
||||||
expect(response).to have_http_status(200)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'Returns valid JWT token' do
|
|
||||||
token = nil
|
|
||||||
expect { token = json['access_token'] }.not_to raise_exception
|
|
||||||
user_id = nil
|
|
||||||
expect { user_id = decode_token(token) }.not_to raise_exception
|
|
||||||
expect(user_id).to eq(user.id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'When invalid password in request' do
|
|
||||||
it 'Returns HTTP error' do
|
|
||||||
post :authenticate, params: { email: user.email,
|
|
||||||
password: 'wrong_password',
|
|
||||||
grant_type: 'password' }
|
|
||||||
expect(response).to have_http_status(400)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'When no grant_type in request' do
|
|
||||||
it 'Returns HTTP error' do
|
|
||||||
post :authenticate, params: { email: user.email,
|
|
||||||
password: user.password }
|
|
||||||
expect(response).to have_http_status(400)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue