1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-18 07:52:23 +01:00

OpenAPI endpoints to create/update/show/delete machines

This commit is contained in:
Sylvain 2021-02-01 17:43:15 +01:00
parent ed2315d717
commit 30e9f6febf
13 changed files with 210 additions and 36 deletions

View File

@ -1,8 +1,11 @@
# Changelog Fab-manager # Changelog Fab-manager
## Next release ## Next release
- Full German translation (thanks to [@korrupt](https://crowdin.com/profile/korrupt))
- OpenAPI endpoints to create/update/show/delete machines
- Updated environment documentation - Updated environment documentation
- Removed useless locales' configuration files - Removed useless locales' configuration files
- OpenAPI's endpoints will now return more detailed error messages when something wrong occurs
- Fix a security issue: updated ini to 1.3.8 to fix [CVE-2020-7788](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-7788) - Fix a security issue: updated ini to 1.3.8 to fix [CVE-2020-7788](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-7788)
Fix a security issue: updated nokogiri to 1.11.1 to fix [CVE-2020-26247](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-26247) Fix a security issue: updated nokogiri to 1.11.1 to fix [CVE-2020-26247](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-26247)
- Updated caxlsx to 3.0.4, and the dependencies of caxlsx_rail - Updated caxlsx to 3.0.4, and the dependencies of caxlsx_rail
@ -27,7 +30,7 @@
- Removed fab-manager email address from the seeds - Removed fab-manager email address from the seeds
- Initialize new plans with default prices for machines & spaces - Initialize new plans with default prices for machines & spaces
- Display a message when no plans are available - Display a message when no plans are available
- Fix a bug: in the settings area, boolean switches are always shown as false - Fix a bug: in the settings' area, boolean switches are always shown as false
- Fix a bug: public cards presenting the plans in the public area, have bogus style - Fix a bug: public cards presenting the plans in the public area, have bogus style
- Fix a bug: theme primary color is ignored on links - Fix a bug: theme primary color is ignored on links
- [TODO DEPLOY] `rails fablab:maintenance:rebuild_stylesheet` - [TODO DEPLOY] `rails fablab:maintenance:rebuild_stylesheet`
@ -36,7 +39,7 @@
- Add intermediate step version for upgrades: v4.4.6. This will prevent issues with FootprintDebug if a regeneration is needed - Add intermediate step version for upgrades: v4.4.6. This will prevent issues with FootprintDebug if a regeneration is needed
- Check postgreSQL status before compiling assets - Check postgreSQL status before compiling assets
- Improved documentation about the upgrade process - Improved the documentation about the upgrade process
- Fix a bug: unable to set libraries locales to their default values (en-us) - Fix a bug: unable to set libraries locales to their default values (en-us)
- Fix a bug: unable to display details about a closed period - Fix a bug: unable to display details about a closed period
- Fix a bug: members cannot view available trainings slots - Fix a bug: members cannot view available trainings slots
@ -44,7 +47,7 @@
## v4.6.1 2020 October 21 ## v4.6.1 2020 October 21
- Reduced down time during upgrades - Reduced downtime during upgrades
- Architecture changes to allow including React.js components into the application - Architecture changes to allow including React.js components into the application
- Allow running upgrade scripts from dev ranch - Allow running upgrade scripts from dev ranch
- Fix a bug: script mount-webpack.sh was not updating the docker-compose.yml file - Fix a bug: script mount-webpack.sh was not updating the docker-compose.yml file

View File

@ -1,5 +1,9 @@
# frozen_string_literal: true
# Parameters for OpenAPI endpoints
class OpenAPI::V1::BaseController < ActionController::Base class OpenAPI::V1::BaseController < ActionController::Base
protect_from_forgery with: :null_session protect_from_forgery with: :null_session
skip_before_action :verify_authenticity_token
before_action :authenticate before_action :authenticate
before_action :increment_calls_count before_action :increment_calls_count
@ -7,37 +11,47 @@ class OpenAPI::V1::BaseController < ActionController::Base
rescue_from OpenAPI::ParameterError, with: :bad_request rescue_from OpenAPI::ParameterError, with: :bad_request
rescue_from ActionController::ParameterMissing, with: :bad_request rescue_from ActionController::ParameterMissing, with: :bad_request
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_api_client
protected protected
def not_found
render json: { errors: ["Not found"] }, status: :not_found
end
def bad_request def not_found(exception)
render json: { errors: ["Bad request"] }, status: :bad_request render json: { errors: exception }, status: :not_found
end end
def authenticate def bad_request(exception)
authenticate_token || render_unauthorized render json: { errors: exception }, status: :bad_request
end end
def authenticate_token def server_error(exception)
authenticate_with_http_token do |token, options| render json: { error: exception }, status: :internal_server_error
@open_api_client = OpenAPI::Client.find_by(token: token) end
end
end
def current_api_client def authenticate
@open_api_client authenticate_token || render_unauthorized
end end
def render_unauthorized def authenticate_token
render json: { errors: ['Bad credentials'] }, status: 401 authenticate_with_http_token do |token, _options|
@open_api_client = OpenAPI::Client.find_by(token: token)
end end
end
def current_api_client
@open_api_client
end
def render_unauthorized
render json: { errors: ['Bad credentials'] }, status: 401
end
private private
def increment_calls_count
@open_api_client.increment_calls_count def increment_calls_count
end @open_api_client.increment_calls_count
end
end end

View File

@ -1,3 +1,4 @@
# OpenAPI controller for the invoices
class OpenAPI::V1::InvoicesController < OpenAPI::V1::BaseController class OpenAPI::V1::InvoicesController < OpenAPI::V1::BaseController
extend OpenAPI::ApiDoc extend OpenAPI::ApiDoc
expose_doc expose_doc
@ -5,14 +6,12 @@ class OpenAPI::V1::InvoicesController < OpenAPI::V1::BaseController
def index def index
@invoices = Invoice.order(created_at: :desc) @invoices = Invoice.order(created_at: :desc)
if params[:user_id].present? @invoices = @invoices.where(user_id: params[:user_id]) if params[:user_id].present?
@invoices = @invoices.where(user_id: params[:user_id])
end
if params[:page].present? return unless params[:page].present?
@invoices = @invoices.page(params[:page]).per(per_page)
paginate @invoices, per_page: per_page @invoices = @invoices.page(params[:page]).per(per_page)
end paginate @invoices, per_page: per_page
end end
def download def download
@ -21,7 +20,8 @@ class OpenAPI::V1::InvoicesController < OpenAPI::V1::BaseController
end end
private private
def per_page
params[:per_page] || 20 def per_page
end params[:per_page] || 20
end
end end

View File

@ -1,8 +1,52 @@
# frozen_string_literal: true
# authorized 3rd party softwares can manage the machines through the OpenAPI
class OpenAPI::V1::MachinesController < OpenAPI::V1::BaseController class OpenAPI::V1::MachinesController < OpenAPI::V1::BaseController
extend OpenAPI::ApiDoc extend OpenAPI::ApiDoc
expose_doc expose_doc
before_action :set_machine, only: %i[show update destroy]
def index def index
@machines = Machine.order(:created_at) @machines = Machine.order(:created_at)
end end
def create
@machine = Machine.new(machine_params)
if @machine.save
render :show, status: :created, location: @machine
else
render json: @machine.errors, status: :unprocessable_entity
end
end
def update
if @machine.update(machine_params)
render :show, status: :ok, location: @machine
else
render json: @machine.errors, status: :unprocessable_entity
end
end
def show; end
def destroy
if @machine.destroyable?
@machine.destroy
head :no_content
else
render json: { error: 'has existing reservations' }, status: :unprocessable_entity
end
end
private
def machine_params
params.require(:machine).permit(:name, :description, :spec, :disabled,
machine_image_attributes: [:attachment])
end
def set_machine
@machine = Machine.friendly.find(params[:id])
end
end end

View File

@ -83,4 +83,100 @@ class OpenAPI::V1::MachinesDoc < OpenAPI::V1::BaseDoc
} }
MACHINES MACHINES
end end
doc_for :create do
api :POST, "/#{API_VERSION}/machines", 'Create a machine'
formats %w[json multipart/form-data]
description 'Create a new machine.'
returns code: 201, desc: 'The machine was successfully created'
param :machine, Hash, required: true do
param :name, String, desc: 'The name of the machine.', required: true
param :description, String, desc: 'A long textual description of the machine. HTML is supported.', required: true
param :spec, String, desc: 'A long textual description of the technical specifications of the machine. HTML is supported.'
param :disabled, [TrueClass, FalseClass], desc: "Should the machine be disabled? If yes, the machine won't be reservable and will be shown apart."
param :machine_image_attributes, Hash do
param :attachment, ActionDispatch::Http::UploadedFile, required: true, desc: 'Upload a picture for the machine.'
end
end
example <<-MACHINE
curl -X POST
-H "Authorization:Token token=xxx"
-H "Content-Type:multipart/form-data"
-H "Accept: application/json"
-F machine[name]="Epilog laser"
-F machine[description]="La découpeuse laser vous permet de découper ou graver des matériaux."
-F machine[machine_image_attributes[attachment]]=@epilog.jpeg
/open_api/v1/machines
curl -X POST
-H "Authorization:Token token=xxx"
-H "Content-Type:application/json"
-H "Accept: application/json"
-d '{"machine": { "name": "DMP Flex 100", "description": "Cette imprimante 3D peut imprimer des métaux." }}'
/open_api/v1/machines
MACHINE
end
doc_for :update do
api :PATCH, "/#{API_VERSION}/machines/:id", 'Update a machine'
formats %w[json multipart/form-data]
description 'Update an existing machine.'
returns code: 200, desc: 'The machine was successfully updated'
param :machine, Hash, required: true do
param :name, String, desc: 'The name of the machine.', required: true
param :description, String, desc: 'A long textual description of the machine. HTML is supported.', required: true
param :spec, String, desc: 'A long textual description of the technical specifications of the machine. HTML is supported.'
param :disabled, [TrueClass, FalseClass], desc: "Should the machine be disabled? If yes, the machine won't be reservable and will be shown apart."
param :machine_image_attributes, Hash do
param :attachment, ActionDispatch::Http::UploadedFile, required: true, desc: 'Upload a picture for the machine.'
end
end
example <<-MACHINE
curl -X PATCH
-H "Authorization:Token token=xxx"
-H "Content-Type:multipart/form-data"
-H "Accept: application/json"
-F machine[spec]="Laser CO2 de 60W<br>Surface de travail de 812 x 508 mm"
-F machine[machine_image_attributes[attachment]]=@epilog2.jpg
/open_api/v1/machines/10
curl -X PATCH
-H "Authorization:Token token=xxx"
-H "Content-Type:application/json"
-H "Accept: application/json"
-d '{"machine": { "disabled": true }}'
/open_api/v1/machines/10
MACHINE
end
doc_for :show do
api :GET, "/#{API_VERSION}/machines/:id", 'Show a machine'
description 'Show all the details of single machine.'
example <<-MACHINES
# /open_api/v1/machines/1
{
"id": 1,
"name": "Epilog EXT36 Laser",
"slug": "decoupeuse-laser",
"disabled": false,
"updated_at": "2015-02-17T11:06:00.495+01:00",
"created_at": "2014-06-30T03:32:31.972+02:00",
"description": "La découpeuse Laser, EPILOG Legend 36EXT\r\n\r\nInformations générales :\r\nLa découpeuse laser vous permet de découper ou graver des matériaux. \r\n\r\nPour la découpe, il suffit d'apporter votre fichier vectorisé type illustrator, svg ou dxf avec des \"lignes de coupe\" d'une épaisseur inférieure à 0,01 mm et la machine s'occupera du reste!\r\n\r\nLa gravure est basée sur le spectre noir et blanc. Les nuances sont obtenues par différentes profondeurs de gravure correspondant aux niveaux de gris de votre image. Il suffit pour cela d'apporter une image scannée ou un fichier photo en noir et blanc pour pouvoir reproduire celle-ci sur votre support.\r\n\r\nTypes de matériaux gravables/découpeables ?\r\nDu bois au tissu, du plexiglass au cuir, cette machine permet de découper et graver la plupart des matériaux sauf les métaux. La gravure est néanmoins possible sur les métaux recouverts d'une couche de peinture ou les aluminiums anodisés. \r\nConcernant l'épaisseur des matériaux découpés, il est préférable de ne pas dépasser 5 mm pour le bois et 6 mm pour le plexiglass.\r\n",
"spec": "Puissance : 40W\r\nSurface de travail : 914x609 mm \r\nEpaisseur maximale de la matière : 305mm\r\nSource laser : tube laser type CO2\r\nContrôles de vitesse et de puissance : ces deux paramètres sont ajustables en fonction du matériau (de 1% à 100%) .\r\n",
"image": "/uploads/machine_image/2514/machine_image.jpg"
}
MACHINES
end
doc_for :destroy do
api :DELETE, "/#{API_VERSION}/machines/:id", 'Delete a machine'
description 'Delete an existing machine that does not have any existing reservations.'
returns code: 204, desc: 'The machine was successfully deleted'
example <<-MACHINE
curl -X DELETE
-H "Authorization:Token token=xxx"
-H "Accept: application/json"
/open_api/v1/machines/10
MACHINE
end
end end

View File

@ -1 +1,3 @@
# frozen_string_literal: true
json.extract! machine, :id, :name, :slug, :disabled, :updated_at, :created_at json.extract! machine, :id, :name, :slug, :disabled, :updated_at, :created_at

View File

@ -0,0 +1,3 @@
# frozen_string_literal: true
json.partial! 'open_api/v1/machines/machine', machine: @machine

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
json.machines @machines do |machine| json.machines @machines do |machine|
json.partial! 'open_api/v1/machines/machine', machine: machine json.partial! 'open_api/v1/machines/machine', machine: machine
json.extract! machine, :description, :spec json.extract! machine, :description, :spec

View File

@ -0,0 +1,5 @@
# frozen_string_literal: true
json.partial! 'open_api/v1/machines/machine', machine: @machine
json.extract! @machine, :description, :spec
json.image URI.join(root_url, @machine.machine_image.attachment.url) if @machine.machine_image

View File

@ -0,0 +1,3 @@
# frozen_string_literal: true
json.partial! 'open_api/v1/machines/machine', machine: @machine

View File

@ -39,6 +39,7 @@ en:
must_be_in_the_past: "The period must be strictly prior to today's date." must_be_in_the_past: "The period must be strictly prior to today's date."
apipie: apipie:
api_documentation: "API Documentation" api_documentation: "API Documentation"
code: "HTTP code"
#error messages when importing an account from a SSO #error messages when importing an account from a SSO
omniauth: omniauth:
email_already_linked_to_another_account_please_input_your_authentication_code: "E-mail address \"%{OLD_MAIL}\" is already linked to another account, please input your authentication code." email_already_linked_to_another_account_please_input_your_authentication_code: "E-mail address \"%{OLD_MAIL}\" is already linked to another account, please input your authentication code."

View File

@ -39,6 +39,7 @@ fr:
must_be_in_the_past: "La période doit être strictement antérieure à la date du jour." must_be_in_the_past: "La période doit être strictement antérieure à la date du jour."
apipie: apipie:
api_documentation: "Documentation de l'API" api_documentation: "Documentation de l'API"
code: "Code HTTP "
#error messages when importing an account from a SSO #error messages when importing an account from a SSO
omniauth: omniauth:
email_already_linked_to_another_account_please_input_your_authentication_code: "L'adresse de courriel \"%{OLD_MAIL}\" est déjà associée à un compte utilisateur, merci de saisir votre code d'authentification." email_already_linked_to_another_account_please_input_your_authentication_code: "L'adresse de courriel \"%{OLD_MAIL}\" est déjà associée à un compte utilisateur, merci de saisir votre code d'authentification."

View File

@ -189,7 +189,7 @@ Rails.application.routes.draw do
resources :trainings resources :trainings
resources :user_trainings resources :user_trainings
resources :reservations resources :reservations
resources :machines resources :machines, only: %i[index create update show destroy]
resources :bookable_machines resources :bookable_machines
resources :invoices do resources :invoices do
get :download, on: :member get :download, on: :member