Merge branch 'staging'

This commit is contained in:
Xavier J 2016-03-01 10:42:54 +01:00
commit 59f7e33f6b
21 changed files with 428 additions and 53 deletions

View file

@ -49,6 +49,7 @@ gem 'draper'
#Gestion des comptes utilisateurs
gem 'devise'
gem 'openid_connect'
gem 'rest-client'
gem 'carrierwave'
@ -79,6 +80,9 @@ gem 'bootstrap-wysihtml5-rails', '~> 0.3.3.8'
gem 'as_csv'
gem 'apipie-rails', '=0.3.1'
gem "maruku" # for Markdown support in apipie
group :test do
gem 'capybara'
gem 'factory_girl'

View file

@ -47,6 +47,8 @@ GEM
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.3.8)
apipie-rails (0.3.1)
json
arel (6.0.2)
as_csv (2.0.2)
actionpack (>= 3.0)
@ -211,6 +213,7 @@ GEM
activesupport (>= 3.1.0)
rack (>= 1.4.0)
rest-client
maruku (0.7.2)
method_source (0.8.2)
mime-types (2.6.1)
mini_portile (0.6.2)
@ -453,6 +456,7 @@ PLATFORMS
DEPENDENCIES
active_model_serializers
apipie-rails (= 0.3.1)
as_csv
bootstrap-datepicker-rails
bootstrap-sass (~> 3.3.5)
@ -480,6 +484,7 @@ DEPENDENCIES
leaflet-rails
logstasher
mailjet
maruku
mina!
nyan-cat-formatter
openid_connect

View file

@ -0,0 +1,19 @@
class API::StatistiquesController < ApplicationController
def dossiers_stats
render json: {
total: total_dossiers,
mois: dossiers_mois
}
end
private
def total_dossiers
Dossier.where.not(state: :draft).size
end
def dossiers_mois
Dossier.where.not(state: :draft).where(created_at: (1.month.ago)..Time.now).size
end
end

View file

@ -1,5 +1,19 @@
class API::V1::DossiersController < APIController
api :GET, '/procedures/:procedure_id/dossiers/', 'Liste de tous les dossiers d\'une procédure'
param :procedure_id, Integer, desc: "L'identifiant de la procédure", required: true
param :token, String, desc: "Token administrateur", required: true
error code: 401, desc: "Non authorisé"
error code: 404, desc: "Procédure inconnue"
description <<-EOS
Plop
EOS
meta champs: {
}
def index
procedure = current_administrateur.procedures.find(params[:procedure_id])
dossiers = procedure.dossiers.where.not(state: :draft).paginate(page: params[:page])
@ -8,6 +22,21 @@ class API::V1::DossiersController < APIController
render json: {}, status: 404
end
api :GET, '/procedures/:procedure_id/dossiers/:id', 'Informations du dossier d\'une procédure'
param :procedure_id, Integer, desc: "L'identifiant de la procédure", required: true
param :dossier_id, Integer, desc: "L'identifiant du dossier", required: true
param :token, String, desc: "Token administrateur", required: true
error code: 401, desc: "Non authorisé"
error code: 404, desc: "Procédure ou dossier inconnu"
description <<-EOS
Plop
EOS
meta champs: {
}
def show
procedure = current_administrateur.procedures.find(params[:procedure_id])
dossier = procedure.dossiers.find(params[:id])

View file

@ -1,4 +1,18 @@
class API::V1::ProceduresController < APIController
api :GET, '/procedures/:id', 'Informations concernant une procédure'
param :id, Integer, desc: "L'identifiant de la procédure", required: true
param :token, String, desc: "Token administrateur", required: true
error code: 401, desc: "Non authorisé"
error code: 404, desc: "Procédure inconnue"
description <<-EOS
Plop
EOS
meta champs: {
}
def show
@procedure = current_administrateur.procedures.find(params[:id]).decorate

View file

@ -2,9 +2,15 @@ class Cerfa < ActiveRecord::Base
belongs_to :dossier
mount_uploader :content, CerfaUploader
validates :content, :file_size => { :maximum => 3.megabytes }
validates :content, :file_size => {:maximum => 3.megabytes}
def empty?
content.blank?
end
def content_url
unless content.url.nil?
(Downloader.new content, 'CERFA').url
end
end
end

View file

@ -7,9 +7,15 @@ class PieceJustificative < ActiveRecord::Base
alias_attribute :type, :type_de_piece_justificative_id
mount_uploader :content, PieceJustificativeUploader
validates :content, :file_size => { :maximum => 3.megabytes }
validates :content, :file_size => {:maximum => 3.megabytes}
def empty?
content.blank?
end
def content_url
unless content.url.nil?
(Downloader.new content, type_de_piece_justificative.libelle).url
end
end
end

View file

@ -0,0 +1,6 @@
class CerfaSerializer < ActiveModel::Serializer
attributes :content_url => :url
has_one :type_de_champ
end

View file

@ -0,0 +1,5 @@
class ChampSerializer < ActiveModel::Serializer
attributes :value
has_one :type_de_champ
end

View file

@ -4,8 +4,12 @@ class DossierSerializer < ActiveModel::Serializer
:description,
:created_at,
:updated_at,
:archived
:archived,
:mandataire_social
has_one :entreprise
has_one :etablissement
has_one :cerfa
has_many :champs
has_many :pieces_justificatives
end

View file

@ -0,0 +1,5 @@
class PieceJustificativeSerializer < ActiveModel::Serializer
attributes :content_url => :url
has_one :type_de_piece_justificative
end

View file

@ -1,7 +1,7 @@
class TypeDeChampSerializer < ActiveModel::Serializer
attributes :id,
:libelle,
:type_champ,
{:type_champ => :type},
:order_place,
:description
end

View file

@ -12,7 +12,7 @@
- if user_signed_in?
= 'Pièce fournie'
- elsif gestionnaire_signed_in?
%a{ href: "#{(Downloader.new @facade.dossier.cerfa.content, 'CERFA').url}", target: '_blank' } Consulter
%a{ href: "#{@facade.dossier.cerfa.content_url}", target: '_blank' } Consulter
- else
= 'Pièce non fournie'
@ -27,7 +27,7 @@
- if user_signed_in?
= 'Pièce fournie'
- elsif gestionnaire_signed_in?
%a{ href: "#{(Downloader.new piece_justificative.content, piece_justificative.type_de_piece_justificative.libelle).url}", target: '_blank' } Consulter
%a{ href: "#{piece_justificative.content_url}", target: '_blank' } Consulter
- else
= 'Pièce non fournie'

View file

@ -0,0 +1,18 @@
Apipie.configure do |config|
config.app_name = "API TPS"
config.api_base_url = "/api/v1"
config.doc_base_url = "/docs"
config.api_controllers_matcher = File.join(Rails.root, "app", "controllers","api","v1", "**","*.rb")
config.markup = Apipie::Markup::Markdown.new
config.default_version = '1.0'
config.validate = false
config.copyright = "© SGMAP"
config.namespaced_resources = true
config.show_all_examples = true
config.app_info = <<-EOS
Description
EOS
end

View file

@ -116,5 +116,11 @@ Rails.application.routes.draw do
resources :dossiers, only: [:index, :show]
end
end
namespace :statistiques do
get 'dossiers' => '/api/statistiques#dossiers_stats'
end
end
apipie
end

165
doc/apipie_examples.json Normal file
View file

@ -0,0 +1,165 @@
{
"dossiers#index": [
{
"verb": "GET",
"path": "/api/v1/procedures/2/dossiers",
"versions": [
"1.0"
],
"query": "token=92cf04673cb66ab57a0c45e085b5140398ab4b6c",
"request_data": null,
"response_data": {
"dossiers": [
{
"id": 2,
"nom_projet": "Demande de subvention dans le cadre d'accompagnement d'enfant à l'étranger",
"updated_at": "2008-09-01T08:05:00.000Z"
}
],
"pagination": {
"page": 1,
"resultats_par_page": 12,
"nombre_de_page": 1
}
},
"code": "200",
"show_in_doc": 1,
"recorded": true
}
],
"dossiers#show": [
{
"verb": "GET",
"path": "/api/v1/procedures/1/dossiers/1",
"versions": [
"1.0"
],
"query": "token=7cba5df87cf134d07c3c467eb21b4f2a2b2605be",
"request_data": null,
"response_data": {
"dossier": {
"id": 1,
"nom_projet": "Demande de subvention dans le cadre d'accompagnement d'enfant à l'étranger",
"description": "Ma super description",
"created_at": "2008-09-01T08:05:00.000Z",
"updated_at": "2008-09-01T08:05:00.000Z",
"archived": false,
"mandataire_social": false,
"entreprise": {
"siren": "440117620",
"capital_social": 537100000,
"numero_tva_intracommunautaire": "FR27440117620",
"forme_juridique": "SA à conseil d'administration (s.a.i.)",
"forme_juridique_code": "5599",
"nom_commercial": "GRTGAZ",
"raison_sociale": "GRTGAZ",
"siret_siege_social": "44011762001530",
"code_effectif_entreprise": "51",
"date_creation": "2016-01-28T10:16:29.000Z",
"nom": null,
"prenom": null
},
"etablissement": {
"siret": "44011762001530",
"siege_social": true,
"naf": "4950Z",
"libelle_naf": "Transports par conduites",
"adresse": "GRTGAZ\r IMMEUBLE BORA\r 6 RUE RAOUL NORDLING\r 92270 BOIS COLOMBES\r",
"numero_voie": "6",
"type_voie": "RUE",
"nom_voie": "RAOUL NORDLING",
"complement_adresse": "IMMEUBLE BORA",
"code_postal": "92270",
"localite": "BOIS COLOMBES",
"code_insee_localite": "92009"
},
"cerfa": null,
"champs": [
{
"value": null,
"type_de_champ": {
"id": 1,
"libelle": "Description",
"type": "textarea",
"order_place": 1,
"description": "description de votre projet"
}
}
],
"pieces_justificatives": [
{
"url": null,
"type_de_piece_justificative": {
"id": 1,
"libelle": "RIB",
"description": "Releve identité bancaire"
}
},
{
"url": null,
"type_de_piece_justificative": {
"id": 2,
"libelle": "Attestation MSA",
"description": "recuperation automatique"
}
}
]
}
},
"code": "200",
"show_in_doc": 1,
"recorded": true
}
],
"procedures#show": [
{
"verb": "GET",
"path": "/api/v1/procedures/3",
"versions": [
"1.0"
],
"query": "token=cc00dc59ddc89f64c6310bb4e25c55eeb63ee89c",
"request_data": null,
"response_data": {
"procedure": {
"label": "Demande de subvention",
"link": "http://localhost",
"id": 3,
"description": "Demande de subvention à l'intention des associations",
"organisation": "Orga SGMAP",
"direction": "direction SGMAP",
"archived": false,
"geographic_information": {
"use_api_carto": false,
"quartiers_prioritaires": false,
"cadastre": false
},
"types_de_champ": [
{
"id": 3,
"libelle": "Description",
"type": "textarea",
"order_place": 1,
"description": "description de votre projet"
}
],
"types_de_piece_justificative": [
{
"id": 5,
"libelle": "RIB",
"description": "Releve identité bancaire"
},
{
"id": 6,
"libelle": "Attestation MSA",
"description": "recuperation automatique"
}
]
}
},
"code": "200",
"show_in_doc": 1,
"recorded": true
}
]
}

View file

@ -0,0 +1,12 @@
require 'spec_helper'
describe API::StatistiquesController, type: :controller do
describe '#GET dossiers_stats' do
before do
get :dossiers_stats
end
it { expect(response.status).to eq 200 }
end
end

View file

@ -2,15 +2,15 @@ require 'spec_helper'
describe API::V1::DossiersController do
let(:admin) { create(:administrateur) }
let(:procedure) { create(:procedure, administrateur: admin) }
let(:procedure) { create(:procedure, :with_two_type_de_piece_justificative, :with_type_de_champ, administrateur: admin) }
let(:wrong_procedure) { create(:procedure) }
it { expect(described_class).to be < APIController }
describe 'GET index' do
let(:response) { get :index, token: admin.api_token, procedure_id: procedure_id }
let(:retour) { get :index, token: admin.api_token, procedure_id: procedure_id }
subject { response }
subject { retour }
context 'when procedure is not found' do
let(:procedure_id) { 99_999_999 }
@ -26,9 +26,11 @@ describe API::V1::DossiersController do
let(:procedure_id) { procedure.id }
let(:date_creation) { Time.local(2008, 9, 1, 10, 5, 0) }
let!(:dossier) { Timecop.freeze(date_creation) { create(:dossier, :with_entreprise, procedure: procedure, state: 'initiated') } }
let(:body) { JSON.parse(response.body, symbolize_names: true) }
let(:body) { JSON.parse(retour.body, symbolize_names: true) }
it { expect(response.code).to eq('200') }
it 'return REST code 200', :show_in_doc do
expect(retour.code).to eq('200')
end
it { expect(body).to have_key :pagination }
@ -57,7 +59,7 @@ describe API::V1::DossiersController do
end
context 'when there are multiple pages' do
let(:response) { get :index, token: admin.api_token, procedure_id: procedure_id, page: 2 }
let(:retour) { get :index, token: admin.api_token, procedure_id: procedure_id, page: 2 }
let!(:dossier1) { create(:dossier, :with_entreprise, procedure: procedure, state: 'initiated') }
let!(:dossier2) { create(:dossier, :with_entreprise, procedure: procedure, state: 'initiated') }
@ -78,8 +80,8 @@ describe API::V1::DossiersController do
end
describe 'GET show' do
let(:response) { get :show, token: admin.api_token, procedure_id: procedure_id, id: dossier_id }
subject { response }
let(:retour) { get :show, token: admin.api_token, procedure_id: procedure_id, id: dossier_id }
subject { retour }
context 'when procedure is not found' do
let(:procedure_id) { 99_999_999 }
@ -113,39 +115,43 @@ describe API::V1::DossiersController do
let(:date_creation) { Time.local(2008, 9, 1, 10, 5, 0) }
let!(:dossier) { Timecop.freeze(date_creation) { create(:dossier, :with_entreprise, procedure: procedure) } }
let(:dossier_id) { dossier.id }
let(:body) { JSON.parse(response.body, symbolize_names: true) }
let(:field_list) { [:id, :nom_projet, :created_at, :updated_at, :description, :archived, :entreprise, :etablissement] }
let(:body) { JSON.parse(retour.body, symbolize_names: true) }
let(:field_list) { [:id, :nom_projet, :created_at, :updated_at, :description, :archived, :mandataire_social, :entreprise, :etablissement, :cerfa, :pieces_justificatives, :champs] }
subject { body[:dossier] }
it { expect(response.code).to eq('200') }
it 'return REST code 200', :show_in_doc do
expect(retour.code).to eq('200')
end
it { expect(subject[:id]).to eq(dossier.id) }
it { expect(subject[:nom_projet]).to eq(dossier.nom_projet) }
it { expect(subject[:created_at]).to eq('2008-09-01T08:05:00.000Z') }
it { expect(subject[:updated_at]).to eq('2008-09-01T08:05:00.000Z') }
it { expect(subject[:description]).to eq(dossier.description) }
it { expect(subject[:archived]).to eq(dossier.archived) }
it { expect(subject[:mandataire_social]).to eq(dossier.mandataire_social) }
it { expect(subject.keys).to match_array(field_list) }
describe 'entreprise' do
let(:field_list) { [
:siren,
:capital_social,
:numero_tva_intracommunautaire,
:forme_juridique,
:forme_juridique_code,
:nom_commercial,
:raison_sociale,
:siret_siege_social,
:code_effectif_entreprise,
:date_creation,
:nom,
:prenom] }
subject { super()[:entreprise]}
:siren,
:capital_social,
:numero_tva_intracommunautaire,
:forme_juridique,
:forme_juridique_code,
:nom_commercial,
:raison_sociale,
:siret_siege_social,
:code_effectif_entreprise,
:date_creation,
:nom,
:prenom] }
subject { super()[:entreprise] }
it { expect(subject[:siren]).to eq('440117620')}
it { expect(subject[:capital_social]).to eq(537_100_000)}
it { expect(subject[:numero_tva_intracommunautaire]).to eq('FR27440117620')}
it { expect(subject[:forme_juridique]).to eq('SA à conseil d\'administration (s.a.i.)')}
it { expect(subject[:siren]).to eq('440117620') }
it { expect(subject[:capital_social]).to eq(537_100_000) }
it { expect(subject[:numero_tva_intracommunautaire]).to eq('FR27440117620') }
it { expect(subject[:forme_juridique]).to eq('SA à conseil d\'administration (s.a.i.)') }
it { expect(subject[:forme_juridique_code]).to eq('5599') }
it { expect(subject[:nom_commercial]).to eq('GRTGAZ') }
it { expect(subject[:raison_sociale]).to eq('GRTGAZ') }
@ -155,22 +161,80 @@ describe API::V1::DossiersController do
it { expect(subject.keys).to match_array(field_list) }
end
describe 'pieces_justificatives' do
let(:field_list) { [
:url] }
subject { super()[:pieces_justificatives] }
it { expect(subject.length).to eq 2 }
describe 'first piece justificative' do
subject { super().first }
it { expect(subject.keys.include?(:url)).to be_truthy }
it { expect(subject.keys.include?(:type_de_piece_justificative)).to be_truthy }
describe 'type de piece justificative' do
let(:field_list) { [
:id,
:libelle,
:description] }
subject { super()[:type_de_piece_justificative] }
it { expect(subject.keys.include?(:id)).to be_truthy }
it { expect(subject[:libelle]).to eq('RIB') }
it { expect(subject[:description]).to eq('Releve identité bancaire') }
end
end
end
describe 'champs' do
let(:field_list) { [
:url] }
subject { super()[:champs] }
it { expect(subject.length).to eq 1 }
describe 'first champs' do
subject { super().first }
it { expect(subject.keys.include?(:value)).to be_truthy }
it { expect(subject.keys.include?(:type_de_champ)).to be_truthy }
describe 'type de champ' do
let(:field_list) { [
:id,
:libelle,
:description,
:order_place,
:type] }
subject { super()[:type_de_champ] }
it { expect(subject.keys.include?(:id)).to be_truthy }
it { expect(subject[:libelle]).to eq('Description') }
it { expect(subject[:description]).to eq('description de votre projet') }
it { expect(subject.keys.include?(:order_place)).to be_truthy }
it { expect(subject[:type]).to eq('textarea') }
end
end
end
describe 'etablissement' do
let(:field_list) { [
:siret,
:siege_social,
:naf,
:libelle_naf,
:adresse,
:numero_voie,
:type_voie,
:nom_voie,
:complement_adresse,
:code_postal,
:localite,
:code_insee_localite
:siret,
:siege_social,
:naf,
:libelle_naf,
:adresse,
:numero_voie,
:type_voie,
:nom_voie,
:complement_adresse,
:code_postal,
:localite,
:code_insee_localite
] }
subject { super()[:etablissement]}
subject { super()[:etablissement] }
it { expect(subject[:siret]).to eq('44011762001530') }
it { expect(subject[:siege_social]).to eq(true) }

View file

@ -3,6 +3,7 @@ require 'spec_helper'
describe API::V1::ProceduresController do
let(:admin) { create(:administrateur) }
it { expect(described_class).to be < APIController }
describe 'GET show' do
context 'when procedure does not exist' do
subject { get :show, id: 999_999_999, token: admin.api_token }
@ -14,11 +15,15 @@ describe API::V1::ProceduresController do
it { expect(subject.status).to eq(404) }
end
context 'when procedure exist' do
let(:procedure) { create(:procedure, administrateur: admin) }
let(:procedure) { create(:procedure, :with_two_type_de_piece_justificative, :with_type_de_champ, administrateur: admin) }
subject { get :show, id: procedure, token: admin.api_token }
it { expect(subject.status).to eq(200) }
it 'return REST code 200', :show_in_doc do
expect(subject.status).to eq(200)
end
describe 'body' do
let(:module_api_carto) { create(:module_api_carto, use_api_carto: true, quartiers_prioritaires: true, cadastre: true)}
let(:module_api_carto) { create(:module_api_carto, use_api_carto: true, quartiers_prioritaires: true, cadastre: true) }
let(:procedure) { create(:procedure, :with_type_de_champ, :with_two_type_de_piece_justificative, module_api_carto: module_api_carto, administrateur: admin) }
let(:response) { get :show, id: procedure.id, token: admin.api_token }
subject { JSON.parse(response.body, symbolize_names: true)[:procedure] }
@ -27,7 +32,7 @@ describe API::V1::ProceduresController do
it { expect(subject[:label]).to eq(procedure.libelle) }
it { expect(subject[:description]).to eq(procedure.description) }
it { expect(subject[:organisation]).to eq(procedure.organisation) }
it { expect(subject[:direction]).to eq(procedure.direction) }
it { expect(subject[:direction]).to eq(proced,ure.direction) }
it { expect(subject[:link]).to eq(procedure.lien_demarche) }
it { expect(subject[:archived]).to eq(procedure.archived) }
it { is_expected.to have_key(:types_de_champ) }
@ -37,7 +42,7 @@ describe API::V1::ProceduresController do
let(:champ) { procedure.types_de_champ.first }
it { expect(subject[:id]).to eq(champ.id) }
it { expect(subject[:libelle]).to eq(champ.libelle) }
it { expect(subject[:type_champ]).to eq(champ.type_champ) }
it { expect(subject[:type]).to eq(champ.type_champ) }
it { expect(subject[:order_place]).to eq(champ.order_place) }
it { expect(subject[:description]).to eq(champ.description) }
end

View file

@ -1,6 +1,6 @@
FactoryGirl.define do
factory :type_de_champ do
libelle 'Libellé'
libelle 'Description'
description 'description de votre projet'
type_champ 'textarea'
order_place 1

View file

@ -80,6 +80,8 @@ RSpec.configure do |config|
config.infer_base_class_for_anonymous_controllers = false
config.filter_run :show_in_doc => true if ENV['APIPIE_RECORD']
config.order = 'random'
config.include Devise::TestHelpers, type: :view